Storing a function in a js object
-
Hello, I want to create a GridView that will contain different elements: Button, Text, Switch. I know that it is possible to use Delegate Chooser for this. The problem arises at the stage of creating a model that will store fields for the appropriate display (I will add the type field later). Now I'm faced with adding the nit300.focus is not allowed in the ListModel, so I decided to use the js model. I'm trying to store the function I'm going to call in it, but I get the following error
TypeError: Property 'onClicked' of object [object Object] is not a function
Code:
GridView { id:grid anchors.fill: parent model: [ {name: "Фокус Far", onClicked: function() {}}, // todo {name: "Фокус Near", onClicked: function() {print("near")}}, // todo {name: "Автофокус"}, {name: "f ' = " + nit300.focus/100.0 + " mm"}, {name: "Зум+"}, {name: "Зум-"}, {name: "E-Zoom 2X"}, {name: "FoV"}, {name: "Время интегрирования+"}, {name: "Время интегрирования-"}, {name: "Коррекция"}, {name: "Зум не норма"}, {name: "Яркость+"}, {name: "Яркость-"}, {name: "Manual BrightContrast"}, {name: "Фокус не норма"}, {name: "Контраст+"}, {name: "Контраст-"}, {name: "Positive/Negative"}, {name: "Кулер не норма"}, {name: "DDE--"}, {name: "DDE++"}, {name: "Self Check"}, {name: "Температура не норма"}, {name: "Ошибка связи"}, {name: "ИК не норма"}, {name: "Тестовый кадр"}, {name: "Self Check Fail"}, ] cellHeight: height / 7 cellWidth: width / 4 delegate: MyButton2 { width: grid.cellWidth height: grid.cellHeight text: modelData.name onClicked: { if (modelData.onClicked !== null) { modelData.onClicked() } } } }
I know that the following method may work
property var actions: {"Фокус Near" : [function () {print("near";} ...}
The model in C++ that I use is large and is not a QAbstractListModel, so I do it in qml. Tell me what is the best way to act in such cases
-
Hello, I want to create a GridView that will contain different elements: Button, Text, Switch. I know that it is possible to use Delegate Chooser for this. The problem arises at the stage of creating a model that will store fields for the appropriate display (I will add the type field later). Now I'm faced with adding the nit300.focus is not allowed in the ListModel, so I decided to use the js model. I'm trying to store the function I'm going to call in it, but I get the following error
TypeError: Property 'onClicked' of object [object Object] is not a function
Code:
GridView { id:grid anchors.fill: parent model: [ {name: "Фокус Far", onClicked: function() {}}, // todo {name: "Фокус Near", onClicked: function() {print("near")}}, // todo {name: "Автофокус"}, {name: "f ' = " + nit300.focus/100.0 + " mm"}, {name: "Зум+"}, {name: "Зум-"}, {name: "E-Zoom 2X"}, {name: "FoV"}, {name: "Время интегрирования+"}, {name: "Время интегрирования-"}, {name: "Коррекция"}, {name: "Зум не норма"}, {name: "Яркость+"}, {name: "Яркость-"}, {name: "Manual BrightContrast"}, {name: "Фокус не норма"}, {name: "Контраст+"}, {name: "Контраст-"}, {name: "Positive/Negative"}, {name: "Кулер не норма"}, {name: "DDE--"}, {name: "DDE++"}, {name: "Self Check"}, {name: "Температура не норма"}, {name: "Ошибка связи"}, {name: "ИК не норма"}, {name: "Тестовый кадр"}, {name: "Self Check Fail"}, ] cellHeight: height / 7 cellWidth: width / 4 delegate: MyButton2 { width: grid.cellWidth height: grid.cellHeight text: modelData.name onClicked: { if (modelData.onClicked !== null) { modelData.onClicked() } } } }
I know that the following method may work
property var actions: {"Фокус Near" : [function () {print("near";} ...}
The model in C++ that I use is large and is not a QAbstractListModel, so I do it in qml. Tell me what is the best way to act in such cases
@Idodoqdo when I did something similar, I used a
ListModel
that I initialised from a js array:ListModel { id: myModel readonly property modelItems: [ { name: "bob", onClicked: function() {console.log("Hello")} }, ... ] function init() { modelItems.forEach(function(item) { myModel.append(item) }); } }
You can call
init()
in aComponent.onCompleted
of your containing component.Then in the delegate, I do something like this:
delegate: MyButton { ... onClicked: myModel.modelItems[index].onClicked() }
The basic issue I was working around was that it wasn't possible to store (in such a way that it can be accessed and used) a function in the model. The idea is to have the model definition data outside of the model, to initialise the model from the data, but for function fields just to use the current index in the delegate to refer back to the original data to obtain the function.
I think this works if the model is static. It would probably get trickier if the model needs to be more dynamic. There might be a better approach but this has been working for me.
-
@Idodoqdo when I did something similar, I used a
ListModel
that I initialised from a js array:ListModel { id: myModel readonly property modelItems: [ { name: "bob", onClicked: function() {console.log("Hello")} }, ... ] function init() { modelItems.forEach(function(item) { myModel.append(item) }); } }
You can call
init()
in aComponent.onCompleted
of your containing component.Then in the delegate, I do something like this:
delegate: MyButton { ... onClicked: myModel.modelItems[index].onClicked() }
The basic issue I was working around was that it wasn't possible to store (in such a way that it can be accessed and used) a function in the model. The idea is to have the model definition data outside of the model, to initialise the model from the data, but for function fields just to use the current index in the delegate to refer back to the original data to obtain the function.
I think this works if the model is static. It would probably get trickier if the model needs to be more dynamic. There might be a better approach but this has been working for me.
@Bob64
Thanks I was doing something like thisListModel { id: buttonsModel property var actions: { "Config" : [function () {gcpp.openConfFile();}, null, null], // clicked, pressed, released "Wide" : [null, function() {bhz.setContZoom(-1);}, function() {bhz.setContZoom(0);}], "Tele" : [null, function() {bhz.setContZoom(1);}, function() {bhz.setContZoom(0);}], "Near" : [null, function() {bhz.setContFocus(-1);}, function() {bhz.setContFocus(0);}], "Far" : [null, function () {bhz.setContFocus(1)}, function () {bhz.setContFocus(0)}], "Open" : [null, function() {bhz.setContIris(1)}, function() {bhz.setContIris(0)}], "Close" : [null, function() {bhz.setContIris(-1)}, function() {bhz.setContIris(0)}], } ListElement { name: "Config" } ListElement { name: "" } ListElement { name: "Wide" } ListElement { name: "Tele" } ListElement { name: "Near" } ListElement { name: "Far" } ListElement { name: "Open" } ListElement { name: "Close" } }
I thought there was a more concise way.
-