Cant access model data from dialog
-
Hello everyone,
I am currently using a ListView to display data about a type of smart plug. The data I get from the plug is stored inside the associated ListModel.
I can access the model data from inside the ListViews delegate.Now here is my problem: Inside of the delegate I have a button that opens a dialog to set a timer. The dialog itself does open fine inside the displayed device delegate and I can use it, the problem is I cannot access the associated model data (e.g. the time I set in the timer).
Is there no way to access the model data from outside the delegate? What would be the better way of going about this?
The following code illustrates my problem:
main.qml
import QtQuick 2.7 import QtQuick.Controls 2.4 import QtQuick.Layouts 1.11 import QtQuick.Window 2.11 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") SwipeView { id: view currentIndex: 0 anchors.fill: parent Item { id: firstPage ListView { id: plugListView model: PlugModel {} delegate: PlugDelegate {} anchors.fill: parent } PlugModel { id: plugModel } PlugDialog { id: plugDialog x: Math.round((parent.width - width) / 2) y: Math.round((parent.height - height) / 2) plugModel: plugListView.model } RoundButton { id: addplugButton text: "+" anchors.bottom: parent.bottom anchors.bottomMargin: 16 anchors.horizontalCenter: parent.horizontalCenter onClicked: plugDialog.open() } TimerDialog { id: timerDialog x: Math.round((parent.width - width) / 2) y: Math.round((parent.height - height) / 2) plugModel: plugModel } } } }
PlugDelegate.qml
import QtQuick 2.9 import QtQuick.Controls 2.4 import QtQuick.Layouts 1.11 ItemDelegate { id: root width: parent.width checkable: true onClicked: ListView.view.currentIndex = index Label { id: nameLabel font.pixelSize: Qt.application.font.pixelSize * 2 text: model.name } Button { id: alarmButton text: qsTr("Set timer") width: 40 height: 20 visible: root.checked onClicked: timerDialog.open() } }
PlugDialog.qml
import QtQuick 2.11 import QtQuick.Controls 2.4 import QtQuick.Layouts 1.11 import QtQuick.Window 2.11 Dialog { id: plugDialog title: "Add new plug" width: 200 height: 200 modal: true standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel property PlugModel plugModel TextField { Layout.fillWidth: true anchors.left: parent.left id: plugDescriptionTextField width: 150 placeholderText: qsTr("Enter plug name...") cursorVisible: true visible: plugModel.checked text: PlugModel.name onTextEdited: PlugModel.name = text } TextField { Layout.fillWidth: true anchors.top: plugDescriptionTextField.bottom id: plugIpAdrTextField width: 150 placeholderText: qsTr("Enter plug IpAdr...") cursorVisible: true visible: PlugModel.checked text: PlugModel.ipadr onTextEdited: PlugModel.ipadr = text } onAccepted: { plugModel.append({ "name": plugDescriptionTextField.text, "ipadr": plugIpAdrTextField.text, "timerduration": 0 }) } onRejected: plugDialog.close() }
PlugModel.qml
import QtQuick 2.13 ListModel { id: plugModel ListElement { name: "Test plug" ipadr: "192.168.1.1" timerduration: 12 } }
TimerDialog.qml
import QtQuick 2.11 import QtQuick.Controls 2.4 import QtQuick.Layouts 1.11 import QtQuick.Window 2.11 Dialog { id: timerDialog title: "Set new timer" modal: true standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel property PlugModel plugModel function formatNumber(number) { return number < 10 && number >= 0 ? "0" + number : number.toString() } onAccepted: { var timer = hoursTumbler.currentIndex * 3600 + minutesTumbler.currentIndex * 60 + secondsTumbler.currentIndex +1 PlugModel.timerduration = timer var ip = plugModel.currentItem.ipadr console.log(PlugModel.timerduration) } onRejected: timerDialog.close() RowLayout { id: rowTumbler Tumbler { id: hoursTumbler model: 24 delegate: TumblerDelegate { text: formatNumber(modelData) } } Tumbler { id: minutesTumbler model: 60 delegate: TumblerDelegate { text: formatNumber(modelData) } } Tumbler { id: secondsTumbler model: 60 delegate: TumblerDelegate { text: formatNumber(modelData) } } } }
TumblerDelegate.qml
import QtQuick 2.11 import QtQuick.Controls 2.4 import QtQuick.Controls.Material 2.4 Text { text: modelData color: Tumbler.tumbler.Material.foreground font: Tumbler.tumbler.font opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter }
After clicking on the device you can open the dialog to set a timer. Accepting the timer dialog always yields some form of "Cannot read property x of undefined"/Unable to assign undefined to QString etc.. I have tried accessing the model data via PlugModel, plugModel, plugListView.model etc.
Thanks for the help.
-
First: when reporting a problem, please try to condense it into a minimal amount of code and text that describes it. It is hard to get through all this and reason about it. And it is even harder when one realizes most of this code does not matter for the issue at hand.
@FrecciaGLT said in Cant access model data from dialog:
[...]
property PlugModel plugModel
[...]
After clicking on the device you can open the dialog to set a timer. Accepting the timer dialog always yields some form of "Cannot read property x of undefined"/Unable to assign undefined to QString etc.. I have tried accessing the model data via PlugModel, plugModel, plugListView.model etc.I think you may be mixing up 2 ideas: model and view. You are passing the model to your dialog, but model by itself does not know anything about currently selected index in a particular view. Model is there to serve (and manipulate) data, it can handle multiple views at once etc. It has no idea which index is "current". The view knows which index is current or selected.
So, you can get out of this problem in several ways:
- pass index to your dialog before (or while) you are opening it. Then the dialog can operate on your model using this index (using data() and setData() methods of the model)
- if your model items are QObjects, you can just pass the data object instead, and operate directly on it
-
@sierdzio
Thank you for your answer, that gave me the nudge in the right direction.
I managed to access the data viaplugModel.get(plugListView.currentIndex).timerduration
I'll keep the code condensed in future posts, thank you.
-
Nice, thanks for posting the solution, it might help others, too!