从 QML ListView 委托调用 JavaScript 对象方法
Posted
技术标签:
【中文标题】从 QML ListView 委托调用 JavaScript 对象方法【英文标题】:Calling JavaScript object method from QML ListView delegate 【发布时间】:2018-05-31 11:10:04 【问题描述】:我有一个以 javascript 对象列表作为模型的 ListView。委托需要响应点击,我想存储附加到模型项的点击处理程序(action
属性):
ListView
id: idListView
model: [
name: "Item 1",
icon: "icon1.svg",
action: function()
//do stuff
,
/* other items */
]
delegate: MyDelegate
name: modelData.name
icon: modelData.icon
MouseArea
anchors.fill: parent
onClicked
modelData.action()
但是当我点击一个项目时,我得到了
TypeError: 对象 [object Object] 的属性“动作”不是函数
将函数附加到对象并调用它的正确方法是什么?
【问题讨论】:
【参考方案1】:您应该将函数定义为 QML 属性。 Object
不允许这样做,因此您可以改用 ListModel
:
import QtQuick 2.11
import QtQuick.Window 2.11
Window
id: root
visible: true
width:480
height: 640
title: qsTr("Hello World")
ListView
anchors.fill: parent
spacing: 2
model: ListModel
ListElement
name: "Item 1"
property var func: function() console.log("Item 1 clicked");
ListElement
name: "Item 2"
property var func: function() console.log("Item 2 clicked");
delegate: Rectangle
height: 30
color: "#EFEFEF"
border width: 1; color: "#CCC"
width: parent.width
Text
text: name
anchors.centerIn: parent
MouseArea
anchors.fill: parent
onClicked:
if(typeof func === "function")
func();
else
console.error("Click handler not defined");
另一个但有点被欺骗的解决方案:
import QtQuick 2.11
import QtQuick.Window 2.11
Window
id: root
visible: true
width:480
height: 640
title: qsTr("Hello World")
ListView
anchors.fill: parent
spacing: 2
property list<QtObject> arr: [
QtObject
property string name: "Item 1"
property var func: function() console.log("Item 1 clicked");
,
QtObject
property string name: "Item 2"
property var func: function() console.log("Item 2 clicked");
]
model: arr
delegate: Rectangle
height: 30
color: "#EFEFEF"
border width: 1; color: "#CCC"
width: parent.width
Text
text: modelData.name ? modelData.name : "Undefined item"
anchors.centerIn: parent
MouseArea
anchors.fill: parent
onClicked:
if(typeof modelData.func === "function")
modelData.func();
else
console.error("Click handler not defined");
【讨论】:
你测试了第一个sn-p吗?我不认为函数可以在ListElement
中使用。
是的,在 5.11 中测试。拳头我已经发布了第二个例子,QtObject
s 然后我决定用ListElement
尝试同样的事情,并惊讶地发现它有效。 ListElement
只能有简单类型,但没有提到 property
:-)
直接使用 ListElement 对我不起作用,因为它不处理 QmlEngine 动态重新翻译。第二个选项看起来不错(并且有效),尽管更冗长 - 我正在寻找一种将处理程序附加到模型项的方法。
这确实是 Qt 5.11 中的新功能:doc.qt.io/qt-5/qml-qtqml-models-listelement.html - “从 Qt 5.11 开始,ListElement 还允许将函数声明分配给角色。这允许使用可调用操作定义 ListElements。”
第一个变体在 5.12 中仍然返回错误:ListElement: cannot use script for property value
。这里应该有什么正确的语法?文档中没有示例。【参考方案2】:
很遗憾,无法在ListElement
中存储函数:
值必须是简单的常量;任一字符串(带引号和可选 在对 QT_TR_NOOP 的调用中)、布尔值(真、假)、数字、 或枚举值(如 AlignText.AlignHCenter)。
从委托中调用函数的一种简单方法是将函数保留在模型之外并在模型中引用其名称:
ListView
id: idListView
readonly property var actions:
"action1": function()
console.log("called action 1!");
,
"action2": function()
console.log("called action 2!");
model: [
name: "Item 1",
icon: "icon1.svg",
action: "action1"
,
name: "Item 2",
icon: "icon2.svg",
action: "action2"
,
/* other items */
]
delegate: MyDelegate
name: modelData.name
icon: modelData.icon
MouseArea
anchors.fill: parent
onClicked:
if (typeof idListView.actions[modelData.action] === "function")
idListView.actions[modelData.action]()
【讨论】:
感谢您的建议!那么,不管模型类型如何,模型项都会转换为 ListElements? 不,我不这么认为。我认为 augre 指的是 folibis 的回答。 我不确定。我使用了ListElement
的文档,因为我相信它与使用模型对象的行为相同(具有相同的可能值)。但我并不真正了解模型是如何使用对象 VS ListModel
管理的。无论如何,我没想过使用属性,如果您不介意使用 ListModel
,我发现 fobilis 的答案是一个不错的选择,因为您不必依赖函数名称!
非常感谢!以上是QTBUG-80041 的唯一解决方法。【参考方案3】:
我遇到了类似的问题。我想要一个包含ListView
的Action
s 的Drawer
。一些尝试和错误最终让它运行(Qt 5.11)。愿我的代码对其他人有用。
Action
id: aboutAction
text: "About"
icon.source: "icon_info.png"
Drawer
edge: Qt.LeftEdge
width: Screen.pixelDensity * 100 // mm
height: parent.height
ListView
id: listView
anchors.fill: parent
model: ListModel
delegate: ItemDelegate
width: parent.width
action: action_
Component.onCompleted:
listView.model.append(action_: aboutAction);
【讨论】:
以上是关于从 QML ListView 委托调用 JavaScript 对象方法的主要内容,如果未能解决你的问题,请参考以下文章
如何从 QML 中的 GridView 或 ListView 获取实例化的委托组件
QMLProfiler 中的 QML Listview 报告两次委托创建