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:
- hasModelChildren Rolleneigenschaft zur Bestimmung, ob ein Knoten Kindknoten hat.
- DelegateModel::rootIndex erlaubt die Angabe des Wurzelknotens
- DelegateModel::modelIndex() gibt ein QModelIndex zurück, das zugewiesen werden kann DelegateModel::rootIndex
- DelegateModel::parentModelIndex() gibt ein QModelIndex zurück, das zugewiesen werden kann DelegateModel::rootIndex
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 } |
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.