使用C++model:
当需要少量数据时,QML中直接定义模型时非常方便。
当数据较为复杂或者想在c++里操纵数据时,可以在C++中设计Model并在qml中展示数据,这样会更加稳定可靠。
Qt向导里可以方便地添加Model类。在新建文件里,Qt->QT Item Model。
#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,包含了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 。
#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()声名修改完毕。必须调用beginInsertRows和endInsertRows,这样底层就能正确处理数据的变化,并且将变化及时的反应到View中。插入函数同理。
更多信息:http://doc.qt.io/qt-5/qabstractitemmodel.html#beginInsertRows
DataModel model;
model.append("orange item","orange");
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("$Model",&model);
engine.load(QUrl(QStringLiteral("qrc:/main.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)
}
}
}
}
运行效果图
参考:qmlbook