使用C++model:

当需要少量数据时,QML中直接定义模型时非常方便。

当数据较为复杂或者想在c++里操纵数据时,可以在C++中设计Model并在qml中展示数据,这样会更加稳定可靠。

Qt向导里可以方便地添加Model类。在新建文件里,Qt->QT Item Model。

代码实现:
datamodel.h
#ifndef DATAMODEL_H
#define DATAMODEL_H

#include

class Data
{
public:
Data(const QString &title,const QString &color);

QString title() const;
QString color() const;

private:
QString title_;
QString color_;
};

class DataModel : public QAbstractListModel
{
Q_OBJECT

public:
enum DataRoles{
TitleRole = Qt::UserRole + 1,
ColorRole
};

explicit DataModel(QObject *parent = nullptr);
~DataModel();

// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

// Add data:
Q_INVOKABLE void insert(int index,const Data &data) ;

// Remove data:
Q_INVOKABLE void remove(int index);
Q_INVOKABLE void append(const QString &title,const QString &color);
int count() const;

protected: // interface QAbstractListModel
virtual QHash<int, QByteArray> roleNames() const;

private:
QList dataList_;
};

#endif // DATAMODEL_H
这里定义了一个数据类型Data,包含了title和color两个数据项,根据自己的需求定义。也定义了我们的DataModel.这就是qml中需要使用的C++model了。

       以下两个是自定义model类必须实现的接口(因为是listmodel所以只需要实现行的rowCount)

int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

类内声名了一个枚举类型(DataRoles),每个类型对应数据项中被访问的一个属性。

QVariant data(const QModelIndex &index, int role)是访问每个列表项的接口,访问的时候会通过index代表索引,role代表查找的属性(对应定义的枚举类型 DataRoles)。

roleNames函数设置自己的类型,返回role的别名,提供给qml使用。

如果qml中不需要使用的函数,则不需要声明Q_INVOKABLE 。

datamodel.cpp
#include “datamodel.h”

Data::Data(const QString &title, const QString &color)
:title_(title)
,color_(color)
{

}

QString Data::title() const
{
return title_;
}

QString Data::color() const
{
return color_;
}

DataModel::DataModel(QObject *parent)
QAbstractListModel(parent)
{
}

DataModel::~DataModel()
{
}

int DataModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return dataList_.count();
}

QVariant DataModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
if(row < 0 || row >= dataList_.count()) {
return QVariant();
}

const Data &data = dataList_[row];
switch (role) {
case TitleRole:
    return data.title();
    break;
case ColorRole:
    return data.color();
    break;
}

return QVariant();

}

//dm : data model
QHash<int, QByteArray> DataModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[TitleRole] = “dmTitle”;
roles[ColorRole] = “dmColor”;
return roles;
// emit countChanged(m_data.count());
}

void DataModel::insert(int index, const Data &data)
{
if(index < 0 || index > dataList_.count()) {
return;
}

emit beginInsertRows(QModelIndex(), index, index);
dataList_.insert(index, data);
emit endInsertRows();

// emit countChanged(m_data.count());
}

void DataModel::remove(int index)
{
if(index < 0 || index >= dataList_.count()) {
return;
}

beginRemoveRows(QModelIndex(), index, index);
dataList_.removeAt(index);
endRemoveRows();

}

void DataModel::append(const QString &title,const QString &color)
{
insert(count(), Data(title,color));
}

int DataModel::count() const
{
return rowCount(QModelIndex());
}
在进行增删的时候必须先调用beginInsertRows(QModelIndex, int , int),其中第一个参数代表的是 Model 数据,QModelIndex()得到这个Model的虚拟rootItem;后两个参数代表所改动的行数范围,如在第三行加入2个数据(则是从第三行改动到第五行),则两个参数分别是(3,5),此处只修改一行,所以两个参数相同。修改完成后还要调用endInsertRows()声名修改完毕。必须调用beginInsertRows和endInsertRows,这样底层就能正确处理数据的变化,并且将变化及时的反应到View中。插入函数同理。

          更多信息:http://doc.qt.io/qt-5/qabstractitemmodel.html#beginInsertRows

在main.cpp中注册到上下文
DataModel model;
model.append(“orange item”,“orange”);

QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("$Model",&model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

在 QML 中读取
可以看到model中定义的别名dmColor ,dmTitle在这里使用。

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 1.4
Window {
visible: true
width: 640
height: 480
title: qsTr(“Model”)

ListView {
    id: view
    width: parent.width
    height: parent.height-rect_input.height
    // set our dynamic model to the views model property
    model: $Model
    delegate: Rectangle {
        width: view.width
        height: 40
        border.color: Qt.darker(color)
        // construct a string based on the models proeprties
        color: dmColor

        Text {
            anchors.left: parent.left
            text: dmTitle
        }
        Image{
            id: icon
            anchors.right: parent.right
            source: "/image/remove.png"
            MouseArea{
                anchors.fill: parent
                onClicked: $Model.remove(index)
            }
        }
    }
}

RowLayout {
    id:rect_input
    anchors.bottom: parent.bottom
    width: parent.width
    height: 50
    TextField{
        id: text_title
        Layout.fillWidth: true
        text: 'orange item'
    }
    TextField {
        id: text_color
        Layout.fillWidth: true
        text: 'orange'
    }
    Button {
        text: 'Add'
        onClicked: {
            $Model.append(text_title.text,text_color.text)
        }
    }
}

}
运行效果图

原文:https://blog.csdn.net/fxy0325/article/details/81434762

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐