Search code examples
qtqmlqtquick2qtquickcontrols

Closing qml dialog properly


I've been playing around with dialogs and there is something that bothers me.

I have the following code:

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Button {
        id: click
        x: 285
        y: 189
        text: qsTr("Click")
        onClicked: dlgTest.open()
    }

    Dialog{
        id:dlgTest
        visible:false
        contentItem: Rectangle{
            width: 300
            height: 300
            TextField{
                id: tfText
                anchors.top: parent.top
            }
            Button{
                anchors.top: tfText.bottom
                onClicked: dlgTest.close()
                text: "Close"
            }


        }
    }
}

When I open it the first time I add some text to the TextField and then I close it. However, If I open it again, the text will still be there. What I want is to "reset" the dialog to it's original state when I opened it the first time (with an empty TextField). It seems that calling the method "close" is exactly the same as changing visible to false.

Is there a way of doing this "reset"?

I have an other dialog with a lot of controls and it's annoying having to restore everything manually.


Solution

  • In your code you create the Dialog once, as a child of the ApplicationWindow. To 'reset' it, you have two options:

    • Have a reset-function, that you call, and restores everything. You can use this to set it up in the first place as well
    • Create a new Object with everything set in place.

    For the latter you can either use JavaScript Dynamic Object Creation or a Loader.

    JavaScript Dynamic Object Creation:

    Button {
        id: click
        x: 285
        y: 189
        text: qsTr("Click")
        onClicked: {
            var d = diaComp.createObject(null)
            d.open()
        }
    }
    
    
    Component {
        id: diaComp
        Dialog{
            id:dlgTest
            visible:false
            contentItem: Rectangle{
                width: 300
                height: 300
                TextField{
                    id: tfText
                    anchors.top: parent.top
                }
                Button{
                    anchors.top: tfText.bottom
                    onClicked: {
                        dlgTest.close()
                        dlgTest.destroy()
                    }
                    text: "Close"
                }
            }
        }
    }
    

    However, as you destroyed the Object, the contents of your properties are lost, and you can't access them anymore. So you need to make sure, to copy them (not bind them) to some property that is not destroyed, first.

    With the Loader you have the posibility to unload the Dialog right before you load it again, which basically resets it. But until you unloaded it, you can still access it's values, as you can see in the Buttons onClicked-handler.

    Button {
        id: click
        x: 285
        y: 189
        text: qsTr("Click")
        onClicked: {
            console.log((dlgLoad.status === Loader.Ready ? dlgLoad.item.value : 'was not loaded yet'))
            dlgLoad.active = false
            dlgLoad.active = true
            dlgLoad.item.open()
        }
    }
    
    Loader {
        id: dlgLoad
        sourceComponent: diaComp
        active: false
    }
    
    
    Component {
        id: diaComp
        Dialog{
            id:dlgTest
            visible:false
            property alias value: tfText.text
            contentItem: Rectangle{
                width: 300
                height: 300
                TextField{
                    id: tfText
                    anchors.top: parent.top
                }
                Button{
                    anchors.top: tfText.bottom
                    onClicked: {
                        dlgTest.close()
                    }
                    text: "Close"
                }
            }
        }
    }
    

    Of course, you could also copy the values from the Loader's item as well, and then unload it earlier, to possible free the memory.

    But if the Dialog is frequently (most of the time) shown, it might be the wisest to avoid the creation and destruction of the objects, by reusing it and resetting it manually.