En esta página

Exposición de QtAbstractListModel a QML

Qt Quick Los ejemplos de API para Android son proyectos de Android Studio

Los ejemplos de la API Qt Quick para Android se proporcionan como proyectos de Android Studio. Las carpetas de los proyectos se encuentran en tu 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 consiste en dos proyectos separados: Un proyecto QML y un proyecto Android basado en Kotlin que alojará y mostrará el contenido QML. Muestra cómo usar QtAbstractListModel para compartir datos desde el lado Android a la vista QML que muestra los datos usando un ListView.

Ejecución del ejemplo

Para ejecutar este ejemplo, necesitas Android Studio y una instalación de Qt para Android.

El plugin Qt Gradle se utilizará para construir el proyecto QML durante el proceso de construcción del proyecto Android. Para ello, el ejemplo tiene alguna configuración del plugin en el archivo build.gradle.kts a nivel de aplicación que puede necesitar ser modificada si el plugin no puede, por ejemplo, encontrar el directorio del kit Qt.

QtBuild {
    // Relative for Qt (Installer or MaintenanceTool) installations.
    qtPath = file("../../../../../../../6.11.0")
    projectPath = file("../../qtabstractlistmodel")
}

Para más información sobre la configuración del plugin, consulta la documentación del plugin Qt Gradle.

Proyecto QML

El proyecto QML es bastante simple, define un modelo de datos como una propiedad del objeto raíz y algunos elementos UI para mostrar los datos de ese modelo.

Rectangle {
    id: mainRectangle

    property AbstractItemModel dataModel

Para mostrar los datos del modelo, se crea ListView. La propiedad model se establece en el modelo de datos declarado anteriormente.

    ListView {
        id: listView

        model: mainRectangle.dataModel

Para mostrar el modelo de datos, ListView necesita un delegado que se instanciará para cada elemento del modelo de datos. En este caso, el delegado será un Rectangle que contiene dos elementos Text en un Column, mostrando los datos de cada elemento del modelo de datos.

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

Proyecto Kotlin

La parte Android consiste en una única Activity y la definición del modelo de datos utilizado anteriormente en la vista QML.

Modelo de datos

El modelo de datos MyListModel es una clase hija de QtAbstractListModel, con ArrayList<String> como sistema interno de almacenamiento de datos. En el bloque inicializador de MyListModel, genera algunos datos aleatorios para la lista.

class MyListModel : QtAbstractListModel() {
    private val m_dataList = ArrayList<String>()

    init {
        synchronized(this) {
            for (row in 0..4) {
                m_dataList.add(UUID.randomUUID().toString())
            }
        }
    }

Cada elemento del modelo tiene asociado un conjunto de elementos de datos, cada uno con su propia función. Las implementaciones personalizadas de QtAbstractItemModel deben definir un rol personalizado para cada elemento de datos. Cada rol tiene asociado un valor Int, que se utiliza al recuperar los datos, y un valor String, que especifica el nombre del elemento de datos cuando se utiliza desde QML.

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

Mientras que los valores de Int en el método "roleNames()" pueden codificarse de forma rígida, este ejemplo especifica una clase enum personalizada DataRole dentro de MyListModel, que se utiliza cuando se hace referencia a estos valores. En este ejemplo, definimos dos roles: UUID y Fila.

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

A la hora de devolver datos del modelo de datos, la clase debe sobrescribir el método "QtAbstractListModel::data()". Este método toma dos parámetros: QtModelIndex y Int, que hacen referencia al índice y al rol del elemento de datos, respectivamente.

En "MyDataModel::data()", el rol UUID devuelve los datos del índice dado en los datos internos, mientras que el rol Row devuelve la fila del elemento solicitado.

Nota: Este método, junto con algunos otros, está anotado con una etiqueta @Synchronized. Esto se debe a que las llamadas a estos métodos se originan en el hilo Qt y acceden a los datos subyacentes posiblemente al mismo tiempo que las peticiones del hilo Android a través de los métodos "addRow()" y "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 -> ""
        }
    }

Para permitir que actores externos manipulen el QtAbstractItemModel, el ejemplo añade dos métodos adicionales a MyDataModel. Para añadir datos a la fila, tiene el método "addRow()"; para eliminar datos, está el método "removeRow()". Estos se utilizan desde la actividad principal.

    @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()
        }
    }

Actividad principal

La clase MainActivity es una simple Activity basada en Kotlin pero también implementa la interfaz QtQmlStatusChangeListener para escuchar los eventos de estado de carga de QML. También almacena el objeto QtQuickViewContent para la vista principal de la aplicación QML y una instancia del modelo de datos detallado anteriormente.

class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener {
    private val m_mainQmlContent: Main = Main()
    private val m_listModel = MyListModel()

Al crear la Actividad principal de la aplicación, el ejemplo crea primero un QtQuickView y lo coloca en la jerarquía de vistas.

        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)

Después de añadir el QtQuickView en la UI, el ejemplo encuentra los botones que se utilizan para manipular el modelo de datos y establece algunos click listeners para llamar a addRow() y removeRow() en el modelo de datos miembro.

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

Una vez que la configuración de la UI y los escuchadores están hechos, el componente QML puede ser preparado y cargado. El ejemplo establece MainActivity como receptor de la señal de cambio de estado del componente QML e indica a QtQuickView que cargue el componente QML.

        m_mainQmlContent.setStatusChangeListener(this)
        qtQuickView.loadContent(m_mainQmlContent)

Finalmente, una vez que el componente QML se ha cargado correctamente, el ejemplo asigna el valor de la instancia MyDataModel a la propiedad dataModel del componente QML.

    override fun onStatusChanged(qtQmlStatus: QtQmlStatus) {
        if (qtQmlStatus === QtQmlStatus.READY) {
            m_mainQmlContent.setDataModel(m_listModel)
        }
    }

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