将 QtAbstractListModel 暴露给 QML
Qt Quick Android API 示例均为 Android Studio 项目
Qt Quick for Android API 示例以 Android Studio 项目形式提供。项目文件夹位于您的 Qt 安装目录中。
例如,在 Windows 的默认安装路径下,它们位于此处:
C:\Qt\Examples\Qt-<patch-release-number>\platforms\android\<example-name>这些项目已预先配置为使用与该 Qt 版本兼容的Qt Gradle 插件。
概述

本示例由两个独立的项目组成:一个 QML 项目和一个基于 Kotlin 的 Android 项目,后者将托管并显示 QML 内容。它演示了如何使用QtAbstractListModel将数据从 Android 端共享到 QML 视图,该视图通过ListView 显示数据。
运行示例
要运行此示例,您需要安装 Android Studio 和Qt for Android。
在 Android 项目构建过程中,将使用Qt Gradle 插件来构建 Qml 项目。为此,该示例在应用级别的 build.gradle.kts 文件中包含了一些插件配置,如果插件无法找到 Qt 套件目录等情况,可能需要修改这些配置。
QtBuild {
// Relative for Qt (Installer or MaintenanceTool) installations.
qtPath = file("../../../../../../../6.12.0")
projectPath = file("../../qtabstractlistmodel")
}有关插件的进一步配置,请参阅Qt Gradle 插件文档。
QML 项目
该 QML 项目非常简单,它将数据模型定义为根对象的属性,并定义了一些 UI 元素来显示该模型中的数据。
Rectangle {
id: mainRectangle
property AbstractItemModel dataModel为了显示模型中的数据,会创建一个ListView 。随后将model 属性设置为之前声明的数据模型。
ListView {
id: listView
model: mainRectangle.dataModel为了显示数据模型,ListView 需要一个委托,该委托将为数据模型中的每个项目分别实例化。在此示例中,该委托将是一个Rectangle ,它在Column 中包含两个Text 元素,用于显示数据模型中每个元素的数据。
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 项目
Android 端由一个Activity以及之前在 QML 视图中使用过的数据模型定义组成。
数据模型
数据模型MyListModel 是QtAbstractListModel 的子类,其内部数据存储系统为ArrayList<String> 。在MyListModel 的初始化块中,它会为列表生成一些随机数据。
class MyListModel : QtAbstractListModel() {
private val m_dataList = ArrayList<String>()
init {
synchronized(this) {
for (row in 0..4) {
m_dataList.add(UUID.randomUUID().toString())
}
}
}模型中的每个项目都关联着一组数据元素,每个元素都有其特定角色。 QtAbstractItemModel的自定义实现必须为每个数据元素定义一个自定义角色。每个角色都有一个关联的Int值(用于检索数据)和一个String值(用于在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
}虽然"roleNames()" 方法中的Int 值可能是硬编码的,但本示例在MyListModel 中定义了一个自定义枚举类DataRole ,用于引用这些值。在此示例中,我们定义了两个角色:UUID和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
}
}
}若要从数据模型中返回数据,该类必须重写"QtAbstractListModel::data()" 方法。该方法接受两个参数:QtModelIndex和Int ,它们分别指代数据元素的索引和角色。
在"MyDataModel::data()" 方法中,UUID 角色返回内部数据中给定索引处的数据,而Row 角色返回请求元素所在的行。
注意:此 方法与其他一些方法一样,标注了@Synchronized标签。这是因为来自 Qt 线程对这些方法的调用,可能与来自 Android 线程通过"addRow()" 和"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 -> ""
}
}为了允许外部组件操作QtAbstractItemModel,该示例在MyDataModel 中添加了两个额外的方法。用于向行中添加数据的是"addRow()" 方法;用于删除数据的是"removeRow()" 方法。这些方法在主活动(Main Activity)中使用。
@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()
}
}主活动
MainActivity 类是一个基于 Kotlin 的简单 Activity,但同时也实现了QtQmlStatusChangeListener接口,用于监听 QML 加载状态事件。它还存储了 QML 应用程序主视图的QtQuickViewContent对象,以及上述数据模型的一个实例。
class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener {
private val m_mainQmlContent: Main = Main()
private val m_listModel = MyListModel()在创建应用程序的主 Activity 时,本示例首先创建一个QtQuickView并将其放入视图层次结构中。
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)将 QtQuickView 添加到 UI 之后,本示例会查找用于操作数据模型的按钮,并为其设置一些点击监听器,以调用数据模型上的 `addRow() ` 和 `removeRow() ` 方法。
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()
}完成 UI 设置和监听器配置后,即可准备并加载 QML 组件。该示例将 `MainActivity ` 设置为 QML 组件状态变化信号的监听器,并指示QtQuickView加载该 QML 组件。
m_mainQmlContent.setStatusChangeListener(this)
qtQuickView.loadContent(m_mainQmlContent)最后,当 QML 组件成功加载后,示例将 MyDataModel 实例的值赋给 QML 组件中的dataModel 属性。
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.