Verwendung von C++-Modellen mit Qt Quick Ansichten

In einem benutzerdefinierten C++-Modell bereitgestellte Daten

Modelle können in C++ definiert und dann für QML verfügbar gemacht werden. Dies ist nützlich, um bestehende C++-Datenmodelle oder andere komplexe Datensätze für QML verfügbar zu machen.

Eine C++-Modellklasse kann als QStringList, QVariantList, QObjectList oder QAbstractItemModel definiert werden. Die ersten drei eignen sich für die Darstellung einfacherer Datensätze, während QAbstractItemModel eine flexiblere Lösung für komplexere Modelle darstellt.

Hier finden Sie ein Video-Tutorial, das Sie durch den gesamten Prozess der Darstellung eines C++-Modells in QML führt:

QStringList-basiertes Modell

Ein Modell kann eine einfache QStringList sein, die den Inhalt der Liste über die modelData-Rolle bereitstellt.

Hier ist ein ListView mit einem Delegaten, der den Wert seines Modellelements über die Rolle modelData referenziert:

ListView {
    width: 100
    height: 100
    required model

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

Eine Qt-Anwendung kann dieses QML-Dokument laden und den Wert von myModel auf ein QStringList setzen:

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

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

Der vollständige Quellcode für dieses Beispiel ist in examples/quick/models/stringlistmodel im Qt-Installationsverzeichnis verfügbar.

Hinweis: Es gibt keine Möglichkeit für die Ansicht zu wissen, dass sich der Inhalt von QStringList geändert hat. Wenn sich die QStringList ändert, muss das Modell zurückgesetzt werden, indem die model Eigenschaft der Ansicht erneut gesetzt wird.

QVariantList-basiertes Modell

Ein Modell kann eine einzelne QVariantList sein, die den Inhalt der Liste über die modelData-Rolle bereitstellt.

Die API funktioniert genau wie bei QStringList, wie im vorherigen Abschnitt gezeigt.

Hinweis: Es gibt keine Möglichkeit für die Ansicht zu wissen, dass sich der Inhalt einer QVariantList geändert hat. Wenn sich die QVariantList ändert, muss das Modell zurückgesetzt werden.

QObjectList-basiertes Modell

Eine Liste von QObject* Werten kann auch als Modell verwendet werden. Ein QList<QObject*> stellt die Eigenschaften der Objekte in der Liste als Rollen zur Verfügung.

Die folgende Anwendung erstellt eine DataObject Klasse mit Q_PROPERTY Werten, auf die als benannte Rollen zugegriffen werden kann, wenn ein QList<DataObject*> an QML übergeben wird:

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) }});
    ...

Die QObject* ist als modelData Eigenschaft verfügbar. Zur Vereinfachung werden die Eigenschaften des Objekts auch direkt im Kontext des Delegaten verfügbar gemacht. Hier verweist view.qml auf die DataModel Eigenschaften im ListView Delegaten:

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 }
    }
}

Beachten Sie die Verwendung der Eigenschaft color. Sie können vorhandene Eigenschaften anfordern, indem Sie sie als required in einem abgeleiteten Typ deklarieren.

Der vollständige Quellcode für dieses Beispiel ist in examples/quick/models/objectlistmodel im Qt-Installationsverzeichnis verfügbar.

Hinweis: Es gibt keine Möglichkeit für die Ansicht zu wissen, dass sich der Inhalt von QList geändert hat. Wenn sich die QList ändert, muss das Modell zurückgesetzt werden, indem die model Eigenschaft erneut gesetzt wird.

QAbstractItemModel Unterklasse

Ein Modell kann durch Unterklassifizierung von QAbstractItemModel definiert werden. Dies ist der beste Ansatz, wenn Sie ein komplexeres Modell haben, das von den anderen Ansätzen nicht unterstützt werden kann. Eine QAbstractItemModel kann auch automatisch eine QML-Ansicht benachrichtigen, wenn sich die Modelldaten ändern.

Die Rollen einer QAbstractItemModel Unterklasse können durch eine Neuimplementierung von QAbstractItemModel::roleNames() für QML zugänglich gemacht werden.

Hier ist eine Anwendung mit einer QAbstractListModel Unterklasse namens AnimalModel, die die Rollen type und sizes zur Verfügung stellt. Sie implementiert QAbstractItemModel::roleNames() neu, um die Rollennamen freizulegen, so dass auf sie über QML zugegriffen werden kann:

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)}});
    ...

Dieses Modell wird von einem Delegaten ListView angezeigt, der auf die Rollen Typ und Größe zugreift:

ListView {
    width: 200; height: 250

    required model

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

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

QML-Ansichten werden automatisch aktualisiert, wenn sich das Modell ändert. Denken Sie daran, dass das Modell die Standardregeln für Modelländerungen befolgen und die Ansicht benachrichtigen muss, wenn das Modell geändert wurde, indem Sie QAbstractItemModel::dataChanged(), QAbstractItemModel::beginInsertRows() usw. verwenden. Weitere Informationen finden Sie in der Referenz Model subclassing.

Der vollständige Quellcode für dieses Beispiel ist in examples/quick/models/abstractitemmodel im Qt-Installationsverzeichnis verfügbar.

QAbstractItemModel stellt eine Hierarchie von Tabellen dar, aber die derzeit von QML bereitgestellten Ansichten können nur Listendaten anzeigen. Um die untergeordneten Listen eines hierarchischen Modells anzuzeigen, verwenden Sie den QML-Typ DelegateModel, der die folgenden Eigenschaften und Funktionen für Listenmodelle vom Typ QAbstractItemModel bereitstellt:

SQL-Modelle

Qt bietet C++-Klassen, die SQL-Datenmodelle unterstützen. Diese Klassen arbeiten transparent mit den zugrundeliegenden SQL-Daten und reduzieren die Notwendigkeit, SQL-Abfragen für grundlegende SQL-Operationen wie Erstellen, Einfügen oder Aktualisieren auszuführen. Weitere Einzelheiten zu diesen Klassen finden Sie unter Verwendung der SQL-Modellklassen.

Obwohl die C++-Klassen vollständige Funktionssätze für die Bearbeitung von SQL-Daten bereitstellen, bieten sie keinen Datenzugriff auf QML. Daher müssen Sie ein benutzerdefiniertes C++-Datenmodell als Unterklasse einer dieser Klassen implementieren und es QML entweder als Typ oder Kontexteigenschaft zur Verfügung stellen.

Nur-Lese-Datenmodell

Das benutzerdefinierte Modell muss die folgenden Methoden reimplementieren, um den Nur-Lese-Zugriff auf die Daten von QML aus zu ermöglichen:

  • roleNames(), um die Rollennamen für das QML-Frontend freizugeben. Die folgende Version gibt zum Beispiel die Feldnamen der ausgewählten Tabelle als Rollennamen zurück:
     QHash<int, QByteArray> SqlQueryModel::roleNames() const
     {
        QHash<int, QByteArray> roles;
        // record() returns an empty QSqlRecord
        for (int i = 0; i < this->record().count(); i ++) {
            roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
        }
        return roles;
    }
  • data(), um SQL-Daten für das QML-Frontend bereitzustellen. Die folgende Implementierung gibt zum Beispiel Daten für den angegebenen Modellindex zurück:
    QVariant SqlQueryModel::data(const QModelIndex &index, int role) const
    {
        QVariant value;
    
        if (index.isValid()) {
            if (role < Qt::UserRole) {
                value = QSqlQueryModel::data(index, role);
            } else {
                int columnIdx = role - Qt::UserRole - 1;
                QModelIndex modelIndex = this->index(index.row(), columnIdx);
                value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
            }
        }
        return value;
    }

Die Klasse QSqlQueryModel ist gut genug, um ein benutzerdefiniertes Nur-Lese-Modell zu implementieren, das Daten in einer SQL-Datenbank darstellt. Das Chat-Tutorial-Beispiel demonstriert dies sehr gut, indem es ein benutzerdefiniertes Modell implementiert, um die Kontaktdetails aus einer SQLite-Datenbank zu holen.

Editierbares Datenmodell

QSqlTableModel implementiert setData() wie unten beschrieben.

Je nach EditStrategy, das vom Modell verwendet wird, werden die Änderungen entweder in eine Warteschlange gestellt, um später übermittelt zu werden, oder sofort übermittelt.

Sie können auch neue Daten in das Modell einfügen, indem Sie QSqlTableModel::insertRecord() aufrufen. Im folgenden Beispielschnipsel wird ein QSqlRecord mit Buchdetails gefüllt und an das Modell angehängt:

...
QSqlRecord newRecord = record();
newRecord.setValue("author", "John Grisham");
newRecord.setValue("booktitle", "The Litigators");
insertRecord(rowCount(), newRecord);
...

C++-Datenmodelle für QML verfügbar machen

Die obigen Beispiele verwenden erforderliche Eigenschaften der Ansicht, um Modellwerte direkt in QML-Komponenten festzulegen. Eine Alternative dazu ist die Registrierung der C++-Modellklasse als QML-Typ (siehe Definieren von QML-Typen in C++). Dadurch können die Modellklassen direkt als Typen in QML erstellt werden:

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
    }
}

Siehe Schreiben von QML-Erweiterungen mit C++ für Details zum Schreiben von QML-Typen in C++.

Ändern von Modelldaten

Neben roleNames() und data() müssen editierbare Modelle die Methode setData reimplementieren, um Änderungen an bestehenden Modelldaten zu speichern. Die folgende Version der Methode prüft, ob der angegebene Modellindex gültig ist und role gleich Qt::EditRole ist:

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;
}

Hinweis: Es ist wichtig, dass nach dem Speichern der Änderungen das Signal dataChanged() ausgegeben wird.

Im Gegensatz zu den C++-Elementansichten wie QListView oder QTableView muss die Methode setData() gegebenenfalls explizit von QML-Delegaten aufgerufen werden. Dies geschieht, indem der entsprechenden Modelleigenschaft einfach ein neuer Wert zugewiesen wird.

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

Hinweis: Die Rolle edit ist gleich Qt::EditRole. Siehe roleNames() für die eingebauten Rollennamen. In realen Modellen werden jedoch normalerweise benutzerdefinierte Rollen registriert.

© 2025 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.