正确关闭 qml 对话框

Posted

技术标签:

【中文标题】正确关闭 qml 对话框【英文标题】:Closing qml dialog properly 【发布时间】:2016-11-16 22:04:53 【问题描述】:

我一直在玩对话框,有些事情让我很困扰。

我有以下代码:

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"
            


        
    

当我第一次打开它时,我会在 TextField 中添加一些文本,然后关闭它。但是,如果我再次打开它,文本仍然存在。我想要的是在我第一次打开它时将对话框“重置”到它的原始状态(使用一个空的 TextField)。看来调用方法“close”和把 visible 改成 false 是一模一样的。

有没有办法“重置”?

我还有一个包含很多控件的对话框,手动恢复所有内容很烦人。

【问题讨论】:

【参考方案1】:

在您的代码中,您创建一次对话框,作为ApplicationWindow 的子项。 要“重置”它,您有两种选择:

有一个重置功能,您可以调用它并恢复所有内容。您也可以首先使用它进行设置 创建一个新对象,所有内容都已设置到位。

对于后者,您可以使用 javascript 动态对象创建或 Loader

JavaScript 动态对象创建:

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"
            
        
    

但是,当您销毁对象时,您的属性内容会丢失,您无法再访问它们。所以你需要确保,首先将它们复制(而不是绑定它们)到一些没有被破坏的属性。

使用Loader,您可以在再次加载对话框之前将其卸载,这基本上会重置它。但在您卸载它之前,您仍然可以访问它的值,正如您在 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"
            
        
    

当然,您也可以复制加载器项中的值,然后提前卸载它,以释放内存。

但如果Dialog 经常(大部分时间)显示,最明智的做法可能是避免创建和销毁对象,方法是重用它并手动重置它。

【讨论】:

你可以通过sourceComponent: Dialog ... 直接在LoadersourceComponent属性中声明Dialog组件。您不必显式创建 Component 对象,您可以像这样内联定义它,委托也是如此。 你是对的。但是,如果我使用 Component 来设置更复杂的结构,并设置多个属性,甚至可能是信号处理程序,我认为代码更具可读性。通常,我也会先在单独的文件中声明Dialog。但即便如此,如果需要的绑定太多,我还是先将其放在Component 中。但这可能只是个人口味。我不喜欢使用装载机的source,并在装载机准备就绪时设置所有内容。并使用ConnectionsBindings 等等... 这正是我所需要的!谢谢!

以上是关于正确关闭 qml 对话框的主要内容,如果未能解决你的问题,请参考以下文章

单击对话框关闭按钮时正确中止线程

QML 文件对话框(选择文件夹)

为啥当我打开对话框时它会禁用所有 qml 项目

Qt:Qml:创建对话框时关注文本字段

如何在消息对话框中正确使用命令“if”? [关闭]

如何“正确关闭 MFC 无模式对话框并修复资源泄漏”