Verwendung von QtAbstractItemModel in Android Studio Projekten
Überblick
Dieses Beispiel besteht aus zwei Projekten: einem Android Studio Projekt (qtabstractitemmodel_java) und einem QML Projekt (qtabstractitemmodel). Sie können das QML-Projekt in ein Android-Projekt importieren.
Das Beispiel zeigt, wie man komplexe Datentypen zwischen Java und QML handhabt. Es zeigt, wie die Java-API-Klassen QtAbstractItemModel
und QtModelIndex
verwendet werden können. In QML wird die Datenverwendung mit dem Element TableView demonstriert. In Java wird die Datennutzung anhand eines Modells mit verschachtelten ArrayList-Elementen für Zeilen und Spalten demonstriert. Weitere Informationen darüber, wie QML funktioniert, finden Sie unter Qt Qml.
Ausführen des Beispiels
Um dieses Beispiel auszuführen, benötigen Sie Android Studio und Qt Tools für Android Studio zusätzlich zu einer Standardinstallation von Qt für Android. Öffnen Sie qtabstractitemmodel_java in Android Studio und folgen Sie den Anweisungen in Qt Tools for Android Studio, um das qtabstractitemmodel
zu importieren.
QML-Projekt
Auf der Seite des QML-Projekts verwendet das Beispiel ein Rectangle als Stammobjekt. Die Eigenschaftsvariable dataModel
enthält das von der Java-Seite erstellte und gelieferte Datenmodell.
Rectangle { id: mainRectangle property AbstractItemModel dataModel
TableView zeigt unser Datenmodell an. In der Eigenschaft delegate
definiert das Beispiel jedes Zellelement des Modells mit Text.
TableView { id: tableView model: mainRectangle.dataModel anchors {fill: parent; margins: 20} columnSpacing: 4 rowSpacing: 6 boundsBehavior: TableView.OvershootBounds clip: true ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } ScrollBar.horizontal: ScrollBar{ policy: ScrollBar.AsNeeded }
Im Delegaten setzt das Beispiel die Eigenschaften row
und column
über die Methoden QHash<int, QByteArray> QAbstractItemModel::roleNames() const und QtModelIndex index(int row, int column, QtModelIndex parent) und Object data(QtModelIndex qtModelIndex, int role) des Modells.
Der Aufruf dieser Methoden aus QML bedeutet, dass die Ausführung im Qt qtMainLoopThread Thread-Kontext stattfindet.
Siehe QAbstractItemModel für eine detaillierte Beschreibung.
TableView { id: tableView model: mainRectangle.dataModel anchors {fill: parent; margins: 20} columnSpacing: 4 rowSpacing: 6 boundsBehavior: TableView.OvershootBounds clip: true ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } ScrollBar.horizontal: ScrollBar{ policy: ScrollBar.AsNeeded }
Android Studio Projekt
Das Android Studio Projekt (qtabstractitemmodel_java) enthält eine Activity Klasse MainActivity
und MyDataModel
.
Datenmodell
Das Datenmodell, c MyDataModel, erweitert die Klasse QtAbstractItemModel
. Die Klasse QtAbstractItemModel
ist ein Wrapper für QAbstractItemModel.
Da die Methoden der Klasse MyDataModel
sowohl von der QML- als auch von der Android-Seite aufgerufen werden, erfolgt die Ausführung in beiden Thread-Kontexten, dem Qt qtMainLoopThread und dem Android-Hauptthread-Kontext. Sie müssen die Synchronisation beim Zugriff auf Membervariablen in Methoden der Klasse MyDataModel
sicherstellen.
Zunächst initialisiert das Beispiel das Modell mit einem einfachen Zeilen- und Spalten-Mock-Datensatz. Beachten Sie, dass diese Konstruktormethode im Android-Hauptthread-Kontext aufgerufen wird.
/* * Initializes the two-dimensional array list with following content: * [] [] [] [] 1A 1B 1C 1D * [] [] [] [] 2A 2B 2C 2D * [] [] [] [] 3A 3B 3C 3D * [] [] [] [] 4A 4B 4C 4D * Threading: called in Android main thread context. */ public MyDataModel() {
Im Beispiel werden die Methoden von QtAbstractItemModel
für verschiedene Zwecke überschrieben. Die Methoden columnCount() und rowCount() geben die Anzahl der einzelnen Spalten im Modell zurück. Die Ausführung von rowCount() erfolgt in beiden Thread-Kontexten, Qt qtMainLoopThread und Android Main Thread-Kontext.
/* * Returns the count of columns. * Threading: called in Android main thread context. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public int columnCount(QtModelIndex qtModelIndex) { return m_columns; } /* * Returns the count of rows. * Threading: called in Android main thread context. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public int rowCount(QtModelIndex qtModelIndex) { return m_dataList.size(); }
Die Methode data() liefert Modelldaten basierend auf der Rolle und dem Index von Java zu QML. Die Methode roleNames() gibt einen Hash zurück, der numerische Rollenwerte mit ihren Namen als Strings vergleicht; in QML verwenden wir diese Rollennamen, um die entsprechenden Daten aus dem Modell zu holen. Die Methode index() gibt den neuen Modellindex zurück. Die Methode parent() sollte einen Elternteil des Indexes zurückgeben. Da sich dieses Beispiel jedoch auf Daten ohne übergeordnete Indizes konzentriert, überschreiben wir die Methode und geben einen leeren QtModelIndex() zurück. Da die Methoden von QML aus aufgerufen werden, erfolgt die Ausführung im Qt qtMainLoopThread Thread-Kontext.
/* * Returns the data to QML based on the roleNames * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public Object data(QtModelIndex qtModelIndex, int role) { switch (role) { case ROLE_ROW: Cell elementForRow = m_dataList.get(qtModelIndex.row()).get(qtModelIndex.column()); String row = String.valueOf(elementForRow.getRow()); return row; case ROLE_COLUMN: Cell elementForColumn = m_dataList.get(qtModelIndex.row()).get(qtModelIndex.column()); String column = elementForColumn.getColumn(); return column; default: Log.w(TAG, "data unrecognized role: " + role); return null; } } /* * Defines what string i.e. role in QML side gets the data from Java side. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public HashMap<Integer, String> roleNames() { HashMap<Integer, String> roles = new HashMap<>(); roles.put(ROLE_ROW, "row"); roles.put(ROLE_COLUMN, "column"); return roles; } /* * Returns a new index model. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public QtModelIndex index(int row, int column, QtModelIndex parent) { return createIndex(row, column, 0); } /* * Returns a parent model. * Threading: not used called in this example. */ @Override synchronized public QtModelIndex parent(QtModelIndex qtModelIndex) { return new QtModelIndex(); }
Das Beispiel implementiert Methoden auf der Modellseite für MainActivity
UI-Interaktion zum Hinzufügen und Entfernen von Zeilen und Spalten. Ruft begin, end, insert und remove rows auf, um Modellindizes zu aktualisieren, wie beginInsertRow(). Da das Beispiel die QtAbstractItemModel
verwendet, muss es beginInsertRows() und endInsertRows() jedes Mal aufrufen, wenn es neue Zeilen in das Modell einfügt. Dasselbe gilt für das Entfernen. Da die Methoden von der Android-Seite aus aufgerufen werden, findet die Ausführung im Kontext des Android-Hauptthreads statt.
/* * Adds a row. * Threading: called in Android main thread context. */ synchronized public void addRow() { if (m_columns > 0 && m_dataList.size() < MAX_ROWS_AND_COLUMNS) { beginInsertRows(new QtModelIndex(), m_dataList.size(), m_dataList.size()); m_dataList.add(generateRow()); endInsertRows(); } } /* * Removes a row. * Threading: called in Android main thread context. */ synchronized public void removeRow() { if (m_dataList.size() > 1) { beginRemoveRows(new QtModelIndex(), m_dataList.size() - 1, m_dataList.size() - 1); m_dataList.remove(m_dataList.size() - 1); endRemoveRows(); } }
Das Beispiel implementiert Methoden auf der Modellseite für MainActivity
UI-Interaktion zum Hinzufügen und Entfernen von Spalten. Die Aufrufe begin, end, insert und remove columns aktualisieren Modellindizes, wie beginRemoveColumn(). Es gilt das gleiche Kontextbewusstsein wie bei den Methoden add und remove row.
/* * Adds a column. * Threading: called in Android main thread context. */ synchronized public void addColumn() { if (!m_dataList.isEmpty() && m_columns < MAX_ROWS_AND_COLUMNS) { beginInsertColumns(new QtModelIndex(), m_columns, m_columns); generateColumn(); m_columns += 1; endInsertColumns(); } } /* * Removes a column. * Threading: called in Android main thread context. */ synchronized public void removeColumn() { if (m_columns > 1) { int columnToRemove = m_columns - 1; beginRemoveColumns(new QtModelIndex(), columnToRemove, columnToRemove); m_columns -= 1; endRemoveColumns(); } }
Hauptaktivität
MainActivity
implementiert die Schnittstelle QtQmlStatusChangeListener
, um Statusaktualisierungen zu erhalten, wenn die QML geladen wird. Sie ist auch die wichtigste Android-Aktivität.
Das Beispiel erstellt und initialisiert das Datenmodell. Siehe auch QtQuickView
private final MyDataModel m_model = new MyDataModel();
Das Beispiel setzt die UI-Schaltfläche und ihre Listener, damit die Benutzer über die Benutzeroberfläche mit dem Modell interagieren können.
/* * Returns the count of columns. * Threading: called in Android main thread context. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public int columnCount(QtModelIndex qtModelIndex) { return m_columns; } /* * Returns the count of rows. * Threading: called in Android main thread context. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public int rowCount(QtModelIndex qtModelIndex) { return m_dataList.size(); }
Das Beispiel beginnt mit dem Laden des QML-Inhalts. Das Laden erfolgt im Hintergrund, bis der Status von ready
aktualisiert wird.
/* * Returns the data to QML based on the roleNames * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public Object data(QtModelIndex qtModelIndex, int role) { switch (role) { case ROLE_ROW: Cell elementForRow = m_dataList.get(qtModelIndex.row()).get(qtModelIndex.column()); String row = String.valueOf(elementForRow.getRow()); return row; case ROLE_COLUMN: Cell elementForColumn = m_dataList.get(qtModelIndex.row()).get(qtModelIndex.column()); String column = elementForColumn.getColumn(); return column; default: Log.w(TAG, "data unrecognized role: " + role); return null; } } /* * Defines what string i.e. role in QML side gets the data from Java side. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public HashMap<Integer, String> roleNames() { HashMap<Integer, String> roles = new HashMap<>(); roles.put(ROLE_ROW, "row"); roles.put(ROLE_COLUMN, "column"); return roles; } /* * Returns a new index model. * Threading: called in Qt qtMainLoopThread thread context. */ @Override synchronized public QtModelIndex index(int row, int column, QtModelIndex parent) { return createIndex(row, column, 0); } /* * Returns a parent model. * Threading: not used called in this example. */ @Override synchronized public QtModelIndex parent(QtModelIndex qtModelIndex) { return new QtModelIndex(); }
Das Beispiel legt das Datenmodell fest, wenn der QML-Inhalt geladen ist und der Status bereit ist.
/* * Adds a row. * Threading: called in Android main thread context. */ synchronized public void addRow() { if (m_columns > 0 && m_dataList.size() < MAX_ROWS_AND_COLUMNS) { beginInsertRows(new QtModelIndex(), m_dataList.size(), m_dataList.size()); m_dataList.add(generateRow()); endInsertRows(); } } /* * Removes a row. * Threading: called in Android main thread context. */ synchronized public void removeRow() { if (m_dataList.size() > 1) { beginRemoveRows(new QtModelIndex(), m_dataList.size() - 1, m_dataList.size() - 1); m_dataList.remove(m_dataList.size() - 1); endRemoveRows(); } }
© 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.