如何更改QML对话框/窗口的临时父代?

时间:2014-05-19 05:18:15

标签: qt qml qt5 qt5.3

我正在开发一个Qt(5.3)桌面应用程序(带有QML ui的C ++核心),其主窗口是ApplicationWindow,并且在某个时刻启动Dialog。 由于在Windows和Mac OS X之间使用对话框模式存在差异(例如,关于对话框在Mac OS X上很少是模态的,但在Windows上几乎总是模态的),而且在呈现一些对话框的内容方面,我也是我们改变了设计,允许实现特定于平台的对话框版本。

为此,我创建了以下 DialogLoader

Loader {
    id: dialogFactory
    property string dialogName
    function platformFolder() {
        if (Qt.platform.os === "osx")
            return "osx"
        return "win"
    }
    onDialogNameChanged: { source = platformFolder() + "/" + dialogName + ".qml" }
    onStatusChanged: {
        if (dialogFactory.status === Loader.Error)
            console.log("DialogFactory: failed to load file: " + source);
        else if (dialogFactory.status === Loader.Ready)
            console.log("DialogFactory: file \"" + source + "\" loaded")
    }
}

我使用如下:

ApplicationWindow {
    // …
    property alias aboutDialog: aboutDialogLoader.item
    // …
    DialogLoader { id: aboutDialogLoader; dialogName: "AboutDialog" }
    // …
    Action { text: qsTr("About..."); onTriggered: aboutDialog.show() }
    // …
}

这种方法工作正常,除了一件事,它符合我的需要: Windows上的模态对话框的行为与我在ApplicationWindow中直接声明它们时的行为不同。如果在打开模态窗口并且再次授予焦点时应用程序失去焦点,则主窗口后面会出现模态窗口,导致应用程序无法运行。

经过一番研究后,我意识到问题的原因在于,使用加载器方法ApplicationWindow并不是Dialog的短暂父项。

我已经找到了解决方法,通过在发生这种情况时手动将Dialog置于前面:

MainWindow {
    // ...
    onActiveChanged: {
        if (Qt.platform.os === "windows") {
            if (active) {
                // ...
                if (aboutDialog.visible) {
                    aboutDialog.requestActivate()
                }
                // ...
            }
        }
    }
    // ...
}

但我认为如果可能的话,最好避免这种解决方法。在没有任何运气的情况下深入研究Qt文档之后,我决定发布这个问题,可以恢复如下: 是否可以更改QML窗口的瞬态父级?如果是这样,请你指出怎么做?

欢迎提出有关避免重复使用的不同方法的建议。

1 个答案:

答案 0 :(得分:3)

我想这是不可能的。至少在Qt 5.4中。

来自文档(默认属性"数据" QML类型" Window")

  

data:list data属性允许您自由混合视觉   窗口中的子项,资源和其他Windows。

     

如果您将另一个窗口指定给数据列表,嵌套窗口将会   成为"瞬态的"外窗。

     

如果您将一个项目分配给数据列表,它将成为该项目的子项   Window的contentItem,以便它出现在窗口内。该项目   parent将是窗口的contentItem,它是Item的根   该窗口内的所有权树。

     

如果您指定任何其他对象类型,则会将其添加为资源。

     

通常不需要引用data属性,如   这是默认的

     Window的

属性,因此所有子项都是自动的   分配给这家酒店。

似乎所有动态创建" Window"由于QML绑定限制,有错误的瞬态父。所有QML列表元素都不可修改。因此,不建议使用具有属性绑定的列表。如果发生变化,您将永远不会收到通知信号。所以,我想,QML引擎永远不会知道新的QML元素是" Window"输入并将其添加到Windows层次结构中。

来自文档(https://www.ics.com/files/qtdocs/qml-list.html):

  

无法以任何其他方式修改列表属性。物品不能   通过JavaScript动态添加到列表或从列表中删除   操作;列表上的任何push()操作只会修改一个副本   列表而不是实际列表。 (这些当前的限制是应该的   限制涉及列表的属性绑定。)

也许这是一个错误,也许是功能。无论如何,现在无法加载" window"使用适当的瞬态父动态进行动态输入。

我找到的最佳解决方法 - 使用模态:Qt.ApplicationModal 进行对话。