Qt6QMLBookQtC++C++中的模型
Models in C++
C++中的模型
One of the most common ways to integrate C++ and QML is through models. A model provides data to a view such
as ListViews, GridView, PathViews, and other views which take a model and create an instance of a delegate for each entry in the model. The view is smart enough to only create these instances which are visible or in the cache range. This makes it possible to have large models with tens of thousands of entries but still have a very slick user interface. The delegate acts like a template to be rendered with the model entries data. So in summary: a view renders entries from the model using a delegate as a template. The model is a data provider for views.
集成C++和QML最常⽤的⽅法之⼀是通过模型。模型向视图提供数据,例如ListView、GridView、PathView和其他视图,这些视图采⽤模型并为模型中的每个条⽬创建委托实例。该视图⾜够智能,只能创建可见或在缓存范围内的这些实例。这使得拥有数以万计条⽬的⼤型模型成为可能,但仍然有⼀个⾮
常流畅的⽤户界⾯。委托的作⽤类似于要使⽤模型条⽬数据呈现的模板。总之:视图使⽤委托作为模板呈现模型中的条⽬。该模型是视图的数据提供者。
When you do not want to use C++ you can also define models in pure QML. You have several ways to provide a model for the view. For handling of data coming from C++ or a large amount of data, the C++ model is more suitable than this pure QML approach. But often you only need a few entries then these QML models are well suited.
当你不想使⽤C++时,你也可以在纯QML中定义模型。有⼏种⽅法可以为视图提供模型。为了处理来⾃C++或⼤量数据的数据,C++模型⽐这种纯QML⽅法更适合。但通常只需要⼏个条⽬,这些QML模型就⾮常适合了。
ListView {
// using a integer as model
model: 5
delegate: Text { text: 'index: ' + index }
}
ListView {
// using a JS array as model
model: ['A', 'B', 'C', 'D', 'E']
delegate: Text { 'Char['+ index +']: ' + modelData }
}
ListView {
// using a dynamic QML ListModel as model
model: ListModel {
ListElement { char: 'A' }
ListElement { char: 'B' }
ListElement { char: 'C' }
ListElement { char: 'D' }
ListElement { char: 'E' }
}
delegate: Text { 'Char['+ index +']: ' + model.char }
}
The QML views know how to handle these different types of models. For models coming from the C++ world, the view expects a specific protocol to be followed. This protocol is defined in the API defined in QAbstractItemModel, together with documentation describing the dynamic behavior. The API was developed for driving views in the desktop widget world and is flexible enough to act as a base for trees, or multi-column tables as well as lists. In QML, we usually use either the list variant of the API, QAbstractListModel or, for the TableView element, the table variant of the API, QAbstractTableModel. The API contains some functions that have to be implemented and some optional ones that extend the capabilities of the model. The optional parts mostly handle the dynamic use cases for changing, adding or deleting data.
QML视图知道如何处理这些不同类型的模型。对于来⾃C++世界的模型,视图期望遵循特定的协议。该协议在QAbstracteModel中定义的API中定义,以及描述动态⾏为的⽂档。API是为驱动桌⾯窗体世界中的视图⽽开发的,它⾜够灵活,可以作为树、多列表和列表的基础。在QML中,我们通常使⽤列表变量的API,QAbstractListModel,或者对于TableView元素类型,使⽤表变量的
API,QAbstractTableModel。API包含⼀些必须实现的函数和⼀些扩展模型功能的可选函数。可选部分主要处理更改、添加或删除数据的动态⽤例。
A simple model
⼀个简单的模型
A typical QML C++ model derives from QAbstractListModel and implements at least the data and rowCount function. In the example below, we will use a series of SVG color names provided by the QColor class and display them using our model. The data is stored into a QList<QString> data container.
⼀个典型的QML C++模型是从QAbstractListModel中派⽣出来的,并且⾄少实现了data和rowCount函数。在下⾯的⽰例中,我们将使⽤QColor类提供的⼀系列SVG颜⾊名称,并使⽤我们的模型显⽰它们。数据存储在QList<QString>数据容器中。
Our DataEntryModel is derived form QAbstractListModel and implements the mandatory functions. We can ignore the parent
in rowCount as this is only used in a tree model. The QModelIndex class provides the row and column information for the cell, for which the view wants to retrieve data. The view is pulling information from the model on a row/column and role-based. The QAbstractListModel is defined in QtCore but QColor in QtGui. That is why we have the additional QtGui dependency. For QML applications it is okay to depend on QtGui but it should normally not depend on QtWidgets.
我们的DataEntryModel是从QAbstractListModel派⽣的,并实现了必需的函数。我们可以忽略rowCount中的⽗级,因为它仅⽤于树模型。QModelIndex类为视图想要检索数据的单元格提供⾏和列信息。视图以⾏/列和基于⾓⾊的⽅式从模型中提取信息。QAbstractListModel在QtCore中定义,⽽QColor在QtGui中定义。这就是为什么我们有额外的QtGui依赖。对于QML应⽤程序,可以依赖QtGui,但通常不应该依赖QTWidget。
#ifndef DATAENTRYMODEL_H
#define DATAENTRYMODEL_H
#include <QtCore>
#include <QtGui>
class DataEntryModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit DataEntryModel(QObject *parent = 0);
~DataEntryModel();
public: // QAbstractItemModel interface
virtual int rowCount(const QModelIndex &parent) const;
virtual QVariant data(const QModelIndex &index, int role) const;
private:
QList<QString> m_data;
};
#endif // DATAENTRYMODEL_H
On the implementation side, the most complex part is the data function. We first need to make a range check to ensure that we've been provided a valid index. Then we check that the display role is supported. Each item in a model can have multiple display roles defining various aspects of the data contained. The Qt::DisplayRole is the default text role a view will ask for. There is a small set of default roles defined in Qt which can be used, but normally a model will define its own roles for clarity. In the example, all calls which do not contain the display role are ignored at the moment and the default
value QVariant() is returned.
在实现⽅⾯,最复杂的部分是数据函数。我们⾸先需要进⾏范围检查,以确保提供了有效的索引。然后检查是否⽀持显⽰⾓⾊。模型中的每个项都可以有多个显⽰⾓⾊,定义所包含数据的各个⽅⾯。Qt::DisplayRole是视图要求的默认⽂本⾓⾊。Qt中定义了⼀⼩部分可以使⽤的默认⾓⾊,但为了清晰
起见,模型通常会定义⾃⼰的⾓⾊。在本例中,此时将忽略所有不包含display⾓⾊的调⽤,并返回默认值
QVariant()。
#include "dataentrymodel.h"
DataEntryModel::DataEntryModel(QObject *parent)
: QAbstractListModel(parent)
{
// initialize our data (QList<QString>) with a list of color names
m_data = QColor::colorNames();
}
DataEntryModel::~DataEntryModel()
{
}
int DataEntryModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
// return our data count
return unt();
}
QVariant DataEntryModel::data(const QModelIndex &index, int role) const
{
// the index returns the requested row and column information.
// we ignore the column and only use the row information
int row = w();
// boundary check for the row
if(row < 0 || row >= unt()) {
return QVariant();
}
// A model can return data for different roles.
// The default role is the display role.
// it can be accesses in QML with "model.display"
switch(role) {
case Qt::DisplayRole:
// Return the color name for the particular row
/
/ Qt automatically converts it to the QVariant type
return m_data.value(row);
}
// The view asked for other data, just return an empty QVariant
return QVariant();
}
The next step would be to register the model with QML using the qmlRegisterType call. This is done inside the main.cpp before the QML file was loaded.
下⼀步是使⽤qmlRegisterType调⽤向QML注册模型。这是在main.cpp内完成的。加载QML⽂件之前。
#include <QtGui>
#include <QtQml>
#include "dataentrymodel.h"
qt listviewint main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
// register the type DataEntryModel
// under the url "ample" in version 1.0
// under the name "DataEntryModel"
qmlRegisterType<DataEntryModel>("ample", 1, 0, "DataEntryModel");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
();
}
Now you can access the DataEntryModel using the QML import statement ample 1.0 and use it just like other QML item DataEntryModel {}.
现在,您可以使⽤QML import语句ample 1.0载⼊DataEntryModel,并像其他QML项⼀样使⽤它,DataEntryModel{}。
We use this in this example to display a simple list of color entries.
在本例中,我们使⽤它来显⽰颜⾊条⽬的简单列表。
ample 1.0
ListView {
id: view
anchors.fill: parent
model: DataEntryModel {}
delegate: ListDelegate {
// use the defined model role "display"
text: model.display
}
highlight: ListHighlight { }
}
The ListDelegate is a custom type to display some text. The ListHighlight is just a rectangle. The code was extracted to keep the example compact.
ListDelegate是⼀种⽤于显⽰某些⽂本的⾃定义类型。ListHighlight只是⼀个矩形。提取代码是为了保持⽰例的紧凑性。
The view can now display a list of strings using the C++ model and the display property of the model. It is still very simple, but already usable in QML. Normally the data is provided from outside the model and the model would act as an interface to the view.
视图现在可以使⽤C++模型、模型的显⽰属性,显⽰字符串列表。它仍然⾮常简单,但已经可以在QML中使⽤。通常,数据是从模型外部提供的,模型将充当视图的接⼝。
TIP
注
To expose a table of data instead of a list, the QAbstractTableModel is used. The only difference compared to
implementing a QAbstractListModel is that you must also provide the columnCount method.
要暴露数据表⽽不是列表,可以使⽤QAbstractTableModel。与实现QAbstractListModel相⽐,唯⼀的区别在于还必须提供columnCount⽅法。
More Complex Data
更多复杂数据
In reality, the model data is often much more complex. So there is a need to define custom roles so t
hat the view can query other data via properties. For example, the model could provide not only the color as a hex string but maybe also the hue, saturation, and brightness from the HSV color model as “model.hue”, “model.saturation” and “model.brightness” in QML.
实际上,模型数据往往要复杂得多。因此,需要定义⾃定义⾓⾊,以便视图可以通过属性查询其他数据。例如,该模型不仅可以提供⼗六进制字符串形式的颜⾊,还可以提供HSV颜⾊模型中的⾊调、饱和度和亮度,如QML中的“model.hue”、
“model.saturation”和“model.brightness”。
#ifndef ROLEENTRYMODEL_H
#define ROLEENTRYMODEL_H
#include <QtCore>
#include <QtGui>
class RoleEntryModel : public QAbstractListModel
{
Q_OBJECT
public:
// Define the role names to be used
enum RoleNames {
NameRole = Qt::UserRole,
HueRole = Qt::UserRole+2,
SaturationRole = Qt::UserRole+3,
BrightnessRole = Qt::UserRole+4
};
explicit RoleEntryModel(QObject *parent = 0);
~RoleEntryModel();
/
/ QAbstractItemModel interface
public:
virtual int rowCount(const QModelIndex &parent) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
protected:
// return the roles mapping to be used by QML
virtual QHash<int, QByteArray> roleNames() const override;
private:
QList<QColor> m_data;
QHash<int, QByteArray> m_roleNames;
};
#endif // ROLEENTRYMODEL_H
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论