Defining a function in ListElement - Not working with append
-
wrote on 24 Jun 2020, 07:36 last edited by
Hi all,
I want to assign a function declaration to a role in a ListElement in a ListModel. I understand from the docs that this has been allowed since 5.11. "Beginning with Qt 5.11 ListElement also allows assigning a function declaration to a role. This allows the definition of ListElements with callable actions." - ListElement QML Type
Searching around I found a few places where people were having issues with this, including:
https://stackoverflow.com/questions/50622945/calling-javascript-object-method-from-qml-listview-delegate/
https://bugreports.qt.io/browse/QTBUG-80041
https://forum.qt.io/topic/95918/problem-dynamically-adding-items-in-a-listmodelMy current findings are:
- Defining function as a role inside a ListElement declaration works
- Defining function inside JS object that is appended to ListModel, does not work
- From this forum post, adding function as a role to existing ListElement by using setProperty works
Here is some sample code (portions borrowed from links above) that tries to illustrate the scenarios. Item 1 and Item 3 work. Item 2/Scenario 2 gets the following error: Can't assign to existing role 'func' of different type [VariantMap -> Function].
If you comment out the first and third ListElement declarations, this error doesn't happen. But the typeof model.func == object and not function. And I'm not sure if there's a way to invoke the function or define it differently so that it would be invocable.
Any thoughts?
import QtQuick 2.14 import QtQuick.Controls 2.14 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("TestListElement") ListView { id: myListView anchors.fill: parent spacing: 2 model: ListModel { id: myListModel ListElement { name: "Item 1" func: function(){ console.log("Item 1 clicked"); } } } Component.onCompleted: { myListModel.append({ name: "Item 2", func: function (){ console.log("Item 2 clicked");} }); myListModel.append({ name: "Item 3"}); myListModel.setProperty(myListModel.count-1, "func", function (){ console.log("Item 3 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 model.func === "function") model.func(); else console.error("Click handler not defined. Func typeof == " + typeof model.func); } } } } }
-
Hi all,
I want to assign a function declaration to a role in a ListElement in a ListModel. I understand from the docs that this has been allowed since 5.11. "Beginning with Qt 5.11 ListElement also allows assigning a function declaration to a role. This allows the definition of ListElements with callable actions." - ListElement QML Type
Searching around I found a few places where people were having issues with this, including:
https://stackoverflow.com/questions/50622945/calling-javascript-object-method-from-qml-listview-delegate/
https://bugreports.qt.io/browse/QTBUG-80041
https://forum.qt.io/topic/95918/problem-dynamically-adding-items-in-a-listmodelMy current findings are:
- Defining function as a role inside a ListElement declaration works
- Defining function inside JS object that is appended to ListModel, does not work
- From this forum post, adding function as a role to existing ListElement by using setProperty works
Here is some sample code (portions borrowed from links above) that tries to illustrate the scenarios. Item 1 and Item 3 work. Item 2/Scenario 2 gets the following error: Can't assign to existing role 'func' of different type [VariantMap -> Function].
If you comment out the first and third ListElement declarations, this error doesn't happen. But the typeof model.func == object and not function. And I'm not sure if there's a way to invoke the function or define it differently so that it would be invocable.
Any thoughts?
import QtQuick 2.14 import QtQuick.Controls 2.14 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("TestListElement") ListView { id: myListView anchors.fill: parent spacing: 2 model: ListModel { id: myListModel ListElement { name: "Item 1" func: function(){ console.log("Item 1 clicked"); } } } Component.onCompleted: { myListModel.append({ name: "Item 2", func: function (){ console.log("Item 2 clicked");} }); myListModel.append({ name: "Item 3"}); myListModel.setProperty(myListModel.count-1, "func", function (){ console.log("Item 3 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 model.func === "function") model.func(); else console.error("Click handler not defined. Func typeof == " + typeof model.func); } } } } }
wrote on 20 Mar 2021, 23:52 last edited by@bkeller came here looking for a example of a function declaration in a ListElement, so thanks for that.
Haven’t tried the code but reviewing it, here’s my suggestion.
I would suggest the answer to this topic that function declarations can only be made in a ListElement when it’s initialised in a model and not dynamically as your code suggests.
Therefore the probably solution is a functionid element holding an integer or enumeration, and use a switch function to execute the code you are after.
-
wrote on 14 Dec 2022, 20:55 last edited by Ankalagon
In case someone is looking for this, my approach is the following:
ListModel { id: buttons ListElement { title: "Test Button" onButtonClicked: function(value) { console.log("clicked", value) } } } ListView { id: buttonListView width: 100 height: 500 model: buttons delegate: Button { text: title width: buttonListView.width height: 50 onClicked: onButtonClicked(title) } }
Important in this case is that onButtonClicked begins with function(value), only function() did not work for me.