本页内容

在Qt Quick 视图中使用 C++ 模型

自定义 C++ 模型中提供的数据

模型可以在 C++ 中定义,然后供 QML 使用。这有助于将现有的 C++ 数据模型或其他复杂数据集暴露给 QML。

C++ 模型类可以定义为QStringList 、QVariantList 、QObjectList 或QAbstractItemModel 。前三个类型适用于暴露较简单的数据集,而QAbstractItemModel 为更复杂的模型提供了更灵活的解决方案。

基于 QStringList 的模型

模型可以是一个简单的QStringList ,它通过modelData角色提供列表的内容。

以下是一个带有委托的ListView ,该委托使用modelData 角色引用其模型项的值:

ListView {
    width: 100
    height: 100
    required model

    delegate: Rectangle {
        required property string modelData
        height: 25
        width: 100
        Text { text: parent.modelData }
    }
}

Qt应用程序可以加载此QML文档,并将myModel 的值设置为QStringList :

    QStringList dataList = {
        "Item 1",
        "Item 2",
        "Item 3",
        "Item 4"
    };

    QQuickView view;
    view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }});

该示例的完整源代码位于 Qt 安装目录下的examples/quick/models/stringlistmodel中。

注意: 视图无法 得知QStringList 的内容已发生变化。如果QStringList 发生变化,则需要通过再次设置视图的model 属性来重置模型。

基于 QVariantList 的模型

模型可以是一个单独的QVariantList ,它通过modelData角色提供列表的内容。

其 API 工作原理与上一节中展示的QStringList 完全相同。

注意: 视图无法 得知QVariantList 的内容发生了变化。如果QVariantList 发生变化,则必须通过再次设置视图的model 属性来重置模型。

基于 QObjectList 的模型

QObject* 值的列表也可用作模型。QList<QObject*> 将列表中对象的属性作为角色提供。

以下应用程序创建了一个包含Q_PROPERTY 值的DataObject 类,当QList<DataObject*> 暴露给 QML 时,这些值将作为命名角色提供访问:

class DataObject : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
    ...
};

int main(int argc, char ** argv)
{
    QGuiApplication app(argc, argv);

    const QStringList colorList = {"red",
                                   "green",
                                   "blue",
                                   "yellow"};

    const QStringList moduleList = {"Core", "GUI", "Multimedia", "Multimedia Widgets", "Network",
                                    "QML", "Quick", "Quick Controls", "Quick Dialogs",
                                    "Quick Layouts", "Quick Test", "SQL", "Widgets", "3D",
                                    "Android Extras", "Bluetooth", "Concurrent", "D-Bus",
                                    "Gamepad", "Graphical Effects", "Help", "Image Formats",
                                    "Location", "Mac Extras", "NFC", "OpenGL", "Platform Headers",
                                    "Positioning", "Print Support", "Purchasing", "Quick Extras",
                                    "Quick Timeline", "Quick Widgets", "Remote Objects", "Script",
                                    "SCXML", "Script Tools", "Sensors", "Serial Bus",
                                    "Serial Port", "Speech", "SVG", "UI Tools", "WebEngine",
                                    "WebSockets", "WebView", "Windows Extras", "XML",
                                    "XML Patterns", "Charts", "Network Authorization",
                                    "Virtual Keyboard", "Quick 3D", "Quick WebGL"};

    QList<QObject *> dataList;
    for (const QString &module : moduleList)
        dataList.append(new DataObject("Qt " + module, colorList.at(rand() % colorList.length())));

    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }});
    ...

QObject* 可作为modelData 属性使用。为方便起见,该对象的属性也可直接在委托的上下文中使用。在此,view.qml 引用了ListView 委托中的DataModel 属性:

ListView {
    id: listview
    width: 200; height: 320
    required model
    ScrollBar.vertical: ScrollBar { }

    delegate: Rectangle {
        width: listview.width; height: 25

        required color
        required property string name

        Text { text: parent.name }
    }
}

请注意color 属性的用法。您可以在派生类型中将现有属性声明为required ,从而将其作为必需属性。

此示例的完整源代码位于 Qt 安装目录下的examples/quick/models/objectlistmodel中。

注意: 视图无法 知晓QObjectList 的内容是否已发生变化。如果QObjectList 发生变化,则需要通过再次设置视图的model 属性来重置模型。

QAbstractItemModel 的子类

可以通过继承 `QAbstractItemModel` 来定义模型。如果您的模型较为复杂且无法通过其他方法支持,这是最佳方案。当模型数据发生变化时,QAbstractItemModel 还可以自动通知 QML 视图。

QAbstractItemModel 子类的角色可以通过重写QAbstractItemModel::roleNames()方法向QML公开。

以下是一个包含名为AnimalModel 的QAbstractListModel 子类的应用程序,该子类公开了type和sizes角色。它重写了QAbstractItemModel::roleNames() 方法以公开角色名称,从而允许通过 QML 访问这些角色:

class Animal
{
public:
    Animal(const QString &type, const QString &size);
    ...
};

class AnimalModel : public QAbstractListModel
{
    Q_OBJECT
public:
    enum AnimalRoles {
        TypeRole = Qt::UserRole + 1,
        SizeRole
    };

    AnimalModel(QObject *parent = nullptr);
    ...
};

QHash<int, QByteArray> AnimalModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[TypeRole] = "type";
    roles[SizeRole] = "size";
    return roles;
}

int main(int argc, char ** argv)
{
    QGuiApplication app(argc, argv);

    AnimalModel model;
    model.addAnimal(Animal("Wolf", "Medium"));
    model.addAnimal(Animal("Polar bear", "Large"));
    model.addAnimal(Animal("Quoll", "Small"));

    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.setInitialProperties({{"model", QVariant::fromValue(&model)}});
    ...

该模型由一个ListView 委托对象显示,该委托对象访问type和size角色:

ListView {
    width: 200; height: 250

    required model

    delegate: Text {
        required property string type
        required property string size

        text: "Animal: " + type + ", " + size
    }
}

当模型发生变化时,QML 视图会自动更新。请注意,模型必须遵循模型变化的标准规则,并在模型发生变化时使用QAbstractItemModel::dataChanged()、QAbstractItemModel::beginInsertRows() 等方法通知视图。有关更多信息,请参阅《模型子类化参考》。

本示例的完整源代码位于 Qt 安装目录下的examples/quick/models/abstractitemmodel中。

QAbstractItemModel 展示了一个表的层次结构,但 QML 目前提供的视图只能显示列表数据。为了显示层次化模型的子列表,请使用DelegateModel QML 类型,它提供了以下属性与函数,可与QAbstractItemModel 类型的列表模型配合使用:

将 C++ 数据模型暴露给 QML

上述示例利用视图上的必填属性,在 QML 组件中直接设置模型值。另一种方法是将 C++ 模型类注册为 QML 类型(参见《从 C++ 定义 QML 类型》)。这使得模型类能够直接作为 QML 中的类型创建:

C++
class MyModel : public QAbstractItemModel
{
    Q_OBJECT
    QML_ELEMENT

    // [...]
}
QML
MyModel {
    id: myModel
}
ListView {
    width: 200; height: 250
    model: myModel
    delegate: Text {
        required property string someProperty
        text: someProperty
    }
}

有关在C++中编写 QML 类型的详细信息,请参阅《使用 C++ 编写 QML 扩展》。

修改模型数据

除了roleNames() 和data() 之外,可编辑模型还必须重写setData 方法,以将对现有模型数据的更改保存下来。以下版本的方法会检查给定的模型索引是否有效,以及role 是否等于Qt::EditRole :

bool EditableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && role == Qt::EditRole) {
        // Set data in model here. It can also be a good idea to check whether
        // the new value actually differs from the current value
        if (m_entries[index.row()] != value.toString()) {
            m_entries[index.row()] = value.toString();
            emit dataChanged(index, index, { Qt::EditRole, Qt::DisplayRole });
            return true;
        }
    }
    return false;
}

注意: 在保存更改后,务必 发出dataChanged() 信号。

与 C++ 项视图(如QListView 或QTableView )不同,setData() 方法必须在适当的时候从 QML 委托中显式调用。这只需为相应的模型属性赋新值即可实现。

ListView {
    anchors.fill: parent
    model: EditableModel {}
    delegate: TextField {
        width: ListView.view.width
        text: model.edit
        onAccepted: model.edit = text
    }
}

注意: edit 角色等 同于Qt::EditRole 。有关内置角色名称,请参阅roleNames()。不过,实际应用中的模型通常会注册自定义角色。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.