QML中使用C++Model

 使用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 roleNames() const;

private:
    QList dataList_;
};

#endif // DATAMODEL_H

这里定义了一个数据类型Data,包含了titlecolor两个数据项,根据自己的需求定义。也定义了我们的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 DataModel::roleNames() const
{
    QHash 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()声名修改完毕。必须调用beginInsertRowsendInsertRows,这样底层就能正确处理数据的变化,并且将变化及时的反应到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)
            }
        }
    }
}

运行效果图

QML中使用C++Model_第1张图片

参考:qmlbook

你可能感兴趣的:(QML)