6

我正在开发一个 Qt (5.3) 桌面应用程序(带有 QML ui 的 C++ 核心),其主窗口是 anApplicationWindow并且在某些时候会启动Dialogs。由于 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.

我找到了一种解决方法,方法是在发生这种情况时手动将对话框置于前面:

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

但我认为如果可能的话,最好避免这种变通办法。在没有任何运气的情况下深入研究 Qt 文档后,我决定发布这个问题,可以恢复如下:Is it possible to change the transient parent of a QML Window?如果是这样,请你指出如何?

欢迎提出有关可以避免重复内容的不同方法的建议。

4

1 回答 1

3

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

来自文档( QML 类型“Window”的默认属性“data”)

data : list data 属性允许您在一个窗口中自由混合可视子、资源和其他窗口。

如果您将另一个窗口分配给数据列表,则嵌套窗口将成为外部窗口的“瞬态”。

如果将一个 Item 分配给数据列表,它就会成为 Window 的 contentItem 的子项,因此它会出现在窗口内。项目的父项将是窗口的 contentItem,它是该窗口中项目所有权树的根。

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

通常不需要引用 data 属性,因为它是默认值

Window 的属性,因此所有子项都会自动分配给该属性。

由于 QML 绑定限制,“窗口”的所有动态创建似乎都有错误的瞬态父级。所有 QML 列表元素均不可修改。因此,不建议使用带有属性绑定的列表。如果它发生变化,您将永远不会收到通知信号。所以,我猜,QML 引擎永远不知道新的 QML 元素是“Window”类型,并且有必要将它添加到 Windows 层次结构中。

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

不能以任何其他方式修改列表属性。项目不能通过 JavaScript 操作动态添加到列表中或从列表中删除;列表上的任何 push() 操作只会修改列表的副本,而不是实际的列表。(这些当前的限制是由于对涉及列表的属性绑定的限制。)

也许这是一个错误,也许是功能。无论如何,目前不可能使用适当的瞬态父级动态加载“窗口”类型。

我发现的最佳解决方法 - 使用模态:Qt.ApplicationModal for dialog。

于 2015-01-10T00:42:46.533 回答