QtAbstractListModel für QML verfügbar machen
Überblick
Dieses Beispiel besteht aus zwei separaten Projekten: Einem QML-Projekt und einem Kotlin-basierten Android-Projekt, das den QML-Inhalt hosten und anzeigen wird. Es zeigt, wie QtAbstractListModel verwendet wird, um Daten von der Android-Seite an die QML-Ansicht weiterzugeben, die die Daten unter Verwendung einer ListView anzeigt.
Ausführen des Beispiels
Um dieses Beispiel auszuführen, benötigen Sie Android Studio und eine Qt für Android Installation.
Das Qt Gradle Plugin wird verwendet, um das QML-Projekt während des Build-Prozesses des Android-Projekts zu erstellen. Zu diesem Zweck enthält das Beispiel einige Plugin-Konfigurationen in der build.gradle.kts-Datei auf App-Ebene, die möglicherweise geändert werden müssen, wenn das Plugin z. B. das Qt-Kit-Verzeichnis nicht finden kann.
QtBuild { // Relative for Qt (Installer or MaintenanceTool) installations. qtPath = file("../../../../../../../6.8.2") projectPath = file("../../qtabstractlistmodel") }
Weitere Informationen zur Konfiguration des Plugins finden Sie in der Dokumentation zum Qt Gradle Plugin.
QML-Projekt
Das QML-Projekt ist recht einfach, es definiert ein Datenmodell als Eigenschaft des Root-Objekts und einige UI-Elemente zur Anzeige der Daten aus diesem Modell.
Rectangle { id: mainRectangle property AbstractItemModel dataModel
Um die Daten aus dem Modell anzuzeigen, wird ein ListView erstellt. Die Eigenschaft model
wird dann auf das zuvor deklarierte Datenmodell gesetzt.
ListView { id: listView model: mainRectangle.dataModel
Um das Datenmodell anzuzeigen, benötigt ListView einen Delegaten, der für jedes Element des Datenmodells instanziiert wird. In diesem Fall wird der Delegat ein Rectangle sein, der zwei Text Elemente in einem Column enthält und die Daten von jedem Element im Datenmodell anzeigt.
delegate: Rectangle { required property var model width: listView.width height: textColumn.height + (2 * textColumn.spacing) color: "#2CDE85" radius: 25 Column { id: textColumn height: idText.height + rowText.height + spacing spacing: 15 anchors { verticalCenter: parent.verticalCenter left: parent.left right: parent.right leftMargin: 20 rightMargin: 20 } Text { id: idText color: "#00414A" text: model.id font.pixelSize: 36 font.bold: true } Text { id: rowText color: "#00414A" text: model.row font.pixelSize: 36 font.bold: true } } }
Kotlin-Projekt
Die Android-Seite besteht aus einer einzigen Activity und der Definition für das Datenmodell, das zuvor in der QML-Ansicht verwendet wurde.
Datenmodell
Das Datenmodell MyListModel
ist eine Unterklasse von QtAbstractListModel, mit ArrayList<String>
als internes Speichersystem für Daten. Im Initialisierungsblock von MyListModel
werden einige zufällige Daten für die Liste erzeugt.
class MyListModel : QtAbstractListModel() { private val m_dataList = ArrayList<String>() init { synchronized(this) { for (row in 0..4) { m_dataList.add(UUID.randomUUID().toString()) } } }
Jedem Element im Modell ist ein Satz von Datenelementen zugeordnet, jedes mit seiner eigenen Rolle. Benutzerdefinierte Implementierungen von QtAbstractItemModel müssen eine eigene Rolle für jedes Datenelement definieren. Jede Rolle hat einen zugehörigen Int-Wert, der beim Abrufen der Daten verwendet wird, und einen String-Wert, der den Namen des Datenelements angibt, wenn es von QML aus verwendet wird.
@Synchronized override fun roleNames(): HashMap<Int, String> { val m_roles = HashMap<Int, String>() m_roles[DataRole.UUID.value()] = "id" m_roles[DataRole.Row.value()] = "row" return m_roles }
Während die Int
-Werte in der "roleNames()"
-Methode fest kodiert sein können, wird in diesem Beispiel eine benutzerdefinierte Enum-Klasse DataRole
innerhalb von MyListModel
angegeben, die beim Verweis auf diese Werte verwendet wird. In diesem Beispiel definieren wir zwei Rollen: UUID und Row.
private enum class DataRole(val m_value: Int) { UUID(0), Row(1); fun value(): Int { return m_value } companion object { fun valueOf(value: Int): DataRole? { val values = entries.toTypedArray() if (0 <= value && value < values.size) return values[value] return null } } }
Wenn es um die Rückgabe von Daten aus dem Datenmodell geht, muss die Klasse die Methode "QtAbstractListModel::data()"
außer Kraft setzen. Diese Methode benötigt zwei Parameter: QtModelIndex und Int
, die sich jeweils auf den Index und die Rolle des Datenelements beziehen.
In "MyDataModel::data()"
gibt die Rolle UUID
die Daten ab dem angegebenen Index in den internen Daten zurück, während die Rolle Row
die Zeile des angeforderten Elements zurückgibt.
Hinweis: Diese Methode und einige andere sind mit einem @Synchronized-Tag versehen. Dies ist darauf zurückzuführen, dass die Aufrufe dieser Methoden aus dem Qt-Thread stammen und auf die zugrunde liegenden Daten möglicherweise zur gleichen Zeit zugreifen wie die Anfragen aus dem Android-Thread über die Methoden "addRow()"
und "removeRow()"
.
@Synchronized override fun data(qtModelIndex: QtModelIndex, role: Int): Any { return when (DataRole.valueOf(role)) { DataRole.UUID -> "UUID: " + m_dataList[qtModelIndex.row()] DataRole.Row -> "Row: " + qtModelIndex.row() else -> "" } }
Um externen Akteuren die Möglichkeit zu geben, das QtAbstractItemModel zu manipulieren, fügt das Beispiel zwei zusätzliche Methoden zu MyDataModel
hinzu. Um der Zeile Daten hinzuzufügen, gibt es die Methode "addRow()"
; um Daten zu entfernen, gibt es die Methode "removeRow()"
. Diese werden von der Hauptaktivität aus verwendet.
@Synchronized fun addRow() { beginInsertRows(QtModelIndex(), m_dataList.size, m_dataList.size) m_dataList.add(UUID.randomUUID().toString()) endInsertRows() } @Synchronized fun removeRow() { if (!m_dataList.isEmpty()) { beginRemoveRows(QtModelIndex(), m_dataList.size - 1, m_dataList.size - 1) m_dataList.removeAt(m_dataList.size - 1) endRemoveRows() } }
Hauptaktivität
Die Klasse MainActivity
ist eine einfache Kotlin-basierte Activity, implementiert aber auch die Schnittstelle QtQmlStatusChangeListener, um auf QML-Ladestatusereignisse zu hören. Sie speichert auch das QtQuickViewContent
Objekt für die Hauptansicht der QML-Anwendung und eine Instanz des oben beschriebenen Datenmodells.
class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener { private val m_mainQmlContent: Main = Main() private val m_listModel = MyListModel()
Beim Erstellen der Hauptaktivität der Anwendung wird im Beispiel zunächst eine QtQuickView erstellt und in die View-Hierarchie eingefügt.
val qtQuickView: QtQuickView = QtQuickView(this) val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) val qmlFrameLayout: FrameLayout = findViewById<FrameLayout>(R.id.qmlFrame) qmlFrameLayout.addView(qtQuickView, params)
Nach dem Hinzufügen der QtQuickView in die Benutzeroberfläche findet das Beispiel die Schaltflächen, die zur Manipulation des Datenmodells verwendet werden, und setzt einige Klick-Listener, um addRow()
und removeRow()
auf dem Mitgliedsdatenmodell aufzurufen.
val addRowAtEndButton: Button = findViewById<Button>(R.id.addRow) val removeRowFromEndButton: Button = findViewById<Button>(R.id.removeRow) addRowAtEndButton.setOnClickListener { _: View? -> m_listModel.addRow() } removeRowFromEndButton.setOnClickListener { _: View? -> m_listModel.removeRow() }
Sobald das UI-Setup und die Listener fertig sind, kann die QML-Komponente vorbereitet und geladen werden. Im Beispiel wird MainActivity
als Listener für das Statusänderungssignal der QML-Komponente festgelegt und QtQuickView
angewiesen, die QML-Komponente zu laden.
m_mainQmlContent.setStatusChangeListener(this) qtQuickView.loadContent(m_mainQmlContent)
Sobald die QML-Komponente erfolgreich geladen wurde, weist das Beispiel den Wert der MyDataModel-Instanz der Eigenschaft dataModel
in der QML-Komponente zu.
override fun onStatusChanged(qtQmlStatus: QtQmlStatus) { if (qtQmlStatus === QtQmlStatus.READY) { m_mainQmlContent.setDataModel(m_listModel) } }
© 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.