简体   繁体   English

从QML ListView委托中调用JavaScript对象方法

[英]Calling JavaScript object method from QML ListView delegate

I have a ListView with a list of JavaScript objects as a model. 我有一个带有JavaScript对象列表的ListView作为模型。 The delegate needs to respond to click and I want to store click handler attached to model item ( action property): 委托需要响应点击,我想存储附加到模型项( 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()
            }
        }
    }
}

But when I click on an item i get 但是当我点击一个项目我得到

TypeError: Property 'action' of object [object Object] is not a function TypeError:对象[object Object]的属性'action'不是函数

What's the proper way to attach function to object and call it? 将函数附加到对象并调用它的正确方法是什么?

Unfortunately it is not possible to store a function inside a ListElement : 不幸的是,不可能在ListElement内存储一个函数:

Values must be simple constants; 值必须是简单常量; either strings (quoted and optionally within a call to QT_TR_NOOP), boolean values (true, false), numbers, or enumeration values (such as AlignText.AlignHCenter). 字符串(带引号,并且可以选择在调用QT_TR_NOOP的情况下),布尔值(真,假),数字或枚举值(例如AlignText.AlignHCenter)。

A simple way to call a function from a delegate is to keep the function outside of the model and reference its name in the model: 从委托调用函数的一种简单方法是将函数保留在模型之外,并在模型中引用其名称:

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

You should define function as a QML property. 您应该将函数定义为QML属性。 Object doesn't allow that so you could use ListModel instead: 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");
                }
            }
        }
    }
}

Another but a bit tricked solution: 另一个但有些欺骗的解决方案:

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");
                }
            }
        }
    }
}

I ran into a similar issue. 我遇到了类似的问题。 I wanted to have a Drawer containing a ListView of Action s. 我想要一个包含ActionListViewDrawer Some try and error and finally got it running (Qt 5.11). 一些尝试和错误,最后使它运行(Qt 5.11)。 May my code is of use for someone else. 愿我的代码对其他人有用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM