Usando QtAbstractItemModel en Proyectos Android Studio
Qt Quick para Android API los ejemplos son Proyectos Android Studio
Los ejemplos de Qt Quick para Android API se proporcionan como proyectos de Android Studio. Las carpetas de los proyectos se encuentran en su ubicación de instalación de Qt.
Por ejemplo, en la ruta de instalación por defecto de Windows, se encuentran aquí:
C:\Qt\Examples\Qt-<patch-release-number>\platforms\android\<example-name>
Estos proyectos ya están configurados para utilizar una versión del plugin Qt Gradle compatible con esta versión de Qt.
Visión general

Este ejemplo consta de dos proyectos: un proyecto de Android Studio (qtabstractitemmodel_java) y un proyecto QML (qtabstractitemmodel). Puede importar el proyecto QML en un proyecto Android.
El ejemplo muestra cómo manejar tipos de datos complejos entre Java y QML. Demuestra cómo utilizar las clases API Java QtAbstractItemModel y QtModelIndex. En QML, el uso de datos se demuestra con el elemento TableView. En Java, el uso de datos se demuestra con un modelo de elementos ArrayList anidados para filas y columnas. Para más información sobre el funcionamiento de QML, véase Qt Qml.
Ejecución del ejemplo
Para ejecutar este ejemplo, necesita Android Studio y Qt Tools para Android Studio sobre una instalación estándar de Qt para Android. Abre qtabstractitemmodel_java en Android Studio y sigue las instrucciones de Qt Tools for Android Studio para importar el proyecto qtabstractitemmodel.
Proyecto QML
En el proyecto QML, el ejemplo utiliza un Rectangle como objeto raíz. La variable de propiedad dataModel contiene el modelo de datos creado y entregado desde el lado Java.
Rectangle { id: mainRectangle property AbstractItemModel dataModel
TableView muestra nuestro modelo de datos.
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 }
En la propiedad delegate, cada elemento de celda del modelo se define con un Rectangle que contiene un TextEdit. La propiedad text del TextEdit se establece utilizando el método QAbstractItemModel::data() que devuelve un valor basado en el rol y el índice dados.
Llamar a estos métodos desde QML significa que la ejecución tiene lugar en el contexto del hilo qtMainLoopThread de Qt.
delegate: Rectangle { implicitWidth: (tableView.height > tableView.width) ? tableView.width / 10 : tableView.height / 5 implicitHeight: implicitWidth required property var model color: "#2CDE85" border {color: "#00414A"; width: 2} TextEdit { // Calls MyDataModel::data to get data based on the roles. // Called in Qt qtMainLoopThread thread context. // // After editing is finished, call MyDataModel::setData() // to update the value of selected cell. onEditingFinished: parent.model.edit = text text: parent.model.display font {pixelSize: 26; bold: true} padding: 5 anchors.fill: parent wrapMode: TextEdit.Wrap horizontalAlignment: TextEdit.AlignHCenter verticalAlignment: TextEdit.AlignVCenter } }
En el caso de editar el campo TextEdit, el manejador onEditingFinished() establece el valor del rol edit del modelo al texto editado. Esto llama al método QAbstractItemModel::setData(), donde el texto editado de la celda se actualiza al índice correspondiente del modelo.
Para más información ver QAbstractItemModel.
Proyecto Android Studio
El proyecto Android Studio (qtabstractitemmodel_java) contiene una clase Activity MainActivity y una clase MyDataModel.
Modelo de datos
El modelo de datos, MyDataModel, extiende la clase QtAbstractItemModel. La clase QtAbstractItemModel es una envoltura de la clase QAbstractItemModel.
Como los métodos de la clase MyDataModel son llamados desde ambos lados, QML y Android, la ejecución ocurre en ambos contextos de hilo, Qt qtMainLoopThread, y contextos de hilo principal de Android. Debe garantizar la sincronización al acceder a las variables miembro en los métodos de la clase MyDataModel.
En primer lugar, el ejemplo inicializa el modelo con un conjunto de datos simulado de filas y columnas. Tenga en cuenta que este método constructor se llama en el contexto del hilo principal de Android.
/*
* 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() {El ejemplo sobrescribe los métodos QtAbstractItemModel para diferentes propósitos. Los métodos columnCount() y rowCount() devuelven el recuento de cada uno en un modelo. La ejecución de cada rowCount() ocurre en ambos contextos de hilo, el qtMainLoopThread de Qt y los contextos de hilo principal de Android.
/*
* 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();
}El método data() proporciona datos del modelo basados en el rol y el índice de Java a QML. El método roleNames() devuelve un hash que empareja valores numéricos de rol con sus nombres como cadenas; en QML, usamos estos nombres de rol para obtener los datos correspondientes del modelo. El método index() devuelve el nuevo índice del modelo. El método parent() debería devolver un padre del índice. Aún así, como este ejemplo se centra en datos sin índices padre, anulamos el método y devolvemos un QtModelIndex() vacío. Como los métodos se llaman desde QML, la ejecución se produce en el contexto del hilo qtMainLoopThread de Qt.
/*
* 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) {
if (role == ROLE_DISPLAY) {
Cell elementForEdit = m_dataList.get(qtModelIndex.row()).get(qtModelIndex.column());
return elementForEdit.getValue();
}
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_DISPLAY, "display");
roles.put(ROLE_EDIT, "edit");
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();
}El ejemplo sobrescribe el método QAbstractItemModel::setData(), que se llama cuando los datos del modelo en index se establecen desde el lado QML de la aplicación.
/*
* Gets called when model data is edited from QML side.
* Sets the role data for the item at index to value,
* if given index is valid and if data in given index truly changed.
*/
@Override
synchronized public boolean setData(QtModelIndex index, Object value, int role) {
Cell cellAtIndex = m_dataList.get(index.row()).get(index.column());
String cellValueAtIndex = cellAtIndex.getValue();
if (!index.isValid() || role != ROLE_EDIT
|| Objects.equals(cellValueAtIndex, value.toString())) {
return false;
}
cellAtIndex.setValue(value.toString());
// Send dataChanged() when data was successfully set.
dataChanged(index, index, new int[]{role});
return true;
}El ejemplo implementa métodos en el lado del modelo para la interacción MainActivity UI para añadir y eliminar filas y columnas. Las llamadas comienzan, terminan, insertan y eliminan filas para actualizar los índices del modelo, como beginInsertRow(). Como el ejemplo utiliza el QtAbstractItemModel, debe llamar a beginInsertRows() y endInsertRows() cada vez que inserta nuevas filas en el modelo. Lo mismo se aplica a la eliminación. Como los métodos se llaman desde el lado de Android, la ejecución tiene lugar en el contexto del hilo principal de Android.
/*
* 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(generateNewRow());
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();
}
}El ejemplo implementa métodos en el lado del modelo para MainActivity interacción UI para añadir y eliminar columnas. Las llamadas comienzan, terminan, insertan y eliminan columnas para actualizar los índices del modelo, como beginRemoveColumn(). Se aplica el mismo conocimiento del contexto que con los métodos add y 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);
generateNewColumn();
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);
for (int row = 0; row < m_dataList.size(); row++)
m_dataList.get(row).remove(columnToRemove);
m_columns -= 1;
endRemoveColumns();
}
}Actividad principal
MainActivity implementa la interfaz QtQmlStatusChangeListener para obtener actualizaciones de estado cuando se carga el QML. También es la actividad principal de Android.
El ejemplo crea e inicializa el modelo de datos. Ver también QtQuickView
private final MyDataModel m_model = new MyDataModel();
El ejemplo configura el botón UI y sus listeners para permitir a los usuarios interactuar con el modelo a través de la UI.
/*
* 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();
}El ejemplo comienza a cargar el contenido QML. La carga se realiza en segundo plano hasta que se actualiza el estado de ready.
/*
* 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) {
if (role == ROLE_DISPLAY) {
Cell elementForEdit = m_dataList.get(qtModelIndex.row()).get(qtModelIndex.column());
return elementForEdit.getValue();
}
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_DISPLAY, "display");
roles.put(ROLE_EDIT, "edit");
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();
}El ejemplo establece el modelo de datos cuando el contenido QML está cargado, y el estado está listo.
/*
* Gets called when model data is edited from QML side.
* Sets the role data for the item at index to value,
* if given index is valid and if data in given index truly changed.
*/
@Override
synchronized public boolean setData(QtModelIndex index, Object value, int role) {
Cell cellAtIndex = m_dataList.get(index.row()).get(index.column());
String cellValueAtIndex = cellAtIndex.getValue();
if (!index.isValid() || role != ROLE_EDIT
|| Objects.equals(cellValueAtIndex, value.toString())) {
return false;
}
cellAtIndex.setValue(value.toString());
// Send dataChanged() when data was successfully set.
dataChanged(index, index, new int[]{role});
return true;
}© 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.