Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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.


  • Moderators

    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 via

    plugModel.get(plugListView.currentIndex).timerduration
    

    I'll keep the code condensed in future posts, thank you.


  • Moderators

    Nice, thanks for posting the solution, it might help others, too!


Log in to reply