Sur cette page

Exposition de QtAbstractListModel à QML

Qt Quick Les exemples de QtAbstractListModel pour l'API Android sont des projets Android Studio

Les exemples de l'API Qt Quick pour Android sont fournis en tant que projets Android Studio. Les dossiers des projets se trouvent dans votre emplacement d'installation de Qt Location.

Par exemple, sous le chemin d'installation par défaut de Windows, ils se trouvent ici :

C:\Qt\Examples\Qt-<patch-release-number>\platforms\android\<example-name>

Ces projets sont déjà configurés pour utiliser une version du plugin Qt Gradle compatible avec cette version de Qt.

Vue d'ensemble

Cet exemple se compose de deux projets distincts : Un projet QML et un projet Android basé sur Kotlin qui hébergera et affichera le contenu QML. Il montre comment utiliser QtAbstractListModel pour partager des données du côté Android vers la vue QML qui affiche les données à l'aide d'une page ListView.

Exécution de l'exemple

Pour exécuter cet exemple, vous avez besoin d'Android Studio et d'une installation de Qt pour Android.

Le plugin Qt Gradle sera utilisé pour construire le projet QML pendant le processus de construction du projet Android. Pour cela, l'exemple a une configuration du plugin dans le fichier build.gradle.kts au niveau de l'application qui peut avoir besoin d'être modifié si le plugin ne peut pas, par exemple, trouver le répertoire du kit Qt.

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

Pour plus de détails sur la configuration du plugin, veuillez vous référer à la documentation du plugin Qt Gradle.

Projet QML

Le projet QML est assez simple, il définit un modèle de données comme une propriété de l'objet racine et quelques éléments d'interface utilisateur pour afficher les données de ce modèle.

Rectangle {
    id: mainRectangle

    property AbstractItemModel dataModel

Pour afficher les données du modèle, une page ListView est créée. La propriété model est alors définie comme étant le modèle de données déclaré précédemment.

    ListView {
        id: listView

        model: mainRectangle.dataModel

Pour afficher le modèle de données, le site ListView a besoin d'un délégué qui sera instancié pour chaque élément du modèle de données. Dans ce cas, le délégué sera un Rectangle qui contient deux éléments Text dans un Column, affichant les données de chaque élément du modèle de données.

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

Projet Kotlin

La partie Android se compose d'une seule activité et de la définition du modèle de données utilisé précédemment dans la vue QML.

Modèle de données

Le modèle de données MyListModel est une classe enfant de QtAbstractListModel, avec ArrayList<String> comme système de stockage interne des données. Le bloc d'initialisation de MyListModel génère des données aléatoires pour la liste.

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

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

Chaque élément du modèle est associé à un ensemble d'éléments de données, chacun ayant son propre rôle. Les implémentations personnalisées de QtAbstractItemModel doivent définir un rôle personnalisé pour chaque élément de données. Chaque rôle est associé à une valeur Int, qui est utilisée lors de la récupération des données, et à une valeur String, qui spécifie le nom de l'élément de données lorsqu'il est utilisé à partir de 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
    }

Alors que les valeurs de Int dans la méthode "roleNames()" peuvent être codées en dur, cet exemple spécifie une classe enum personnalisée DataRole dans MyListModel, qui est utilisée pour faire référence à ces valeurs. Dans cet exemple, nous définissons deux rôles : UUID et 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
            }
        }
    }

Lorsqu'il s'agit de renvoyer des données à partir du modèle de données, la classe doit surcharger la méthode "QtAbstractListModel::data()". Cette méthode prend deux paramètres : QtModelIndex et Int, qui renvoient respectivement à l'index et au rôle de l'élément de données.

Dans "MyDataModel::data()", le rôle UUID renvoie les données de l'index donné dans les données internes, tandis que le rôle Row renvoie la ligne de l'élément demandé.

Remarque : cette méthode, ainsi que d'autres, est annotée d'une balise @Synchronized. Cela est dû au fait que les appels à ces méthodes proviennent du thread Qt et accèdent aux données sous-jacentes éventuellement en même temps que les demandes provenant du thread Android via les méthodes "addRow()" et "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 -> ""
        }
    }

Pour permettre aux acteurs extérieurs de manipuler le QtAbstractItemModel, l'exemple ajoute deux méthodes supplémentaires à MyDataModel. Pour ajouter des données à la ligne, il dispose de la méthode "addRow()"; pour supprimer des données, il dispose de la méthode "removeRow()". Ces méthodes sont utilisées à partir de l'activité principale.

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

Activité principale

La classe MainActivity est une simple activité basée sur Kotlin, mais elle implémente également l'interface QtQmlStatusChangeListener pour écouter les événements de statut de chargement QML. Elle stocke également l'objet QtQuickViewContent pour la vue principale de l'application QML et une instance du modèle de données détaillé ci-dessus.

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

Lors de la création de l'activité principale de l'application, l'exemple crée d'abord une QtQuickView et la place dans la hiérarchie des vues.

        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)

Après avoir ajouté le QtQuickView à l'interface utilisateur, l'exemple trouve les boutons qui sont utilisés pour manipuler le modèle de données et définit des récepteurs de clics pour appeler addRow() et removeRow() sur le modèle de données membre.

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

Une fois la configuration de l'interface utilisateur et les récepteurs terminés, le composant QML peut être préparé et chargé. L'exemple définit le site MainActivity en tant qu'auditeur du signal de changement d'état du composant QML et indique à QtQuickView de charger le composant QML.

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

Enfin, une fois le composant QML chargé avec succès, l'exemple attribue la valeur de l'instance MyDataModel à la propriété dataModel du composant 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.