Как изменить временного родителя QML Dialog/Window?

Я работаю над настольным приложением Qt (5.3) (ядро C++ с интерфейсом QML), главное окно которого - ApplicationWindow и что в какой-то момент запускает Dialogs. Поскольку существуют различия в использовании модальности диалогов между Windows и Mac OS X (например, диалоговое окно about редко бывает модальным в 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, я решил опубликовать этот вопрос, который можно возобновить следующим образом: возможно ли изменить временного родителя окна QML? Если да, пожалуйста, укажите, как?

Приветствуются предложения о другом подходе, который мог бы избежать повторяющихся вещей.

1 ответ

Решение

Я думаю, что это невозможно сделать. По крайней мере, в Qt 5.4.

Из документации (свойство поумолчанию "data" типа QML "Window")

data: list Свойство data позволяет свободно смешивать визуальные дочерние элементы, ресурсы и другие окна в окне.

Если вы назначите другое окно для списка данных, вложенное окно станет "временным" для внешнего окна.

Если вы присваиваете элемент списку данных, он становится дочерним по отношению к contentItem окна, так что он появляется внутри окна. Родителем элемента будет contentItem окна, который является корнем дерева владения Item в этом окне.

Если вы назначаете любой другой тип объекта, он добавляется в качестве ресурса.

Как правило, нет необходимости ссылаться на свойство данных, так как оно используется по умолчанию.

свойство для Window и, следовательно, все дочерние элементы автоматически присваиваются этому свойству.

Кажется, что все динамическое создание "Окна" имеет неправильный переходный родительский элемент из-за ограничения привязки QML. Все элементы списка QML не могут быть изменены. Таким образом, не рекомендуется использовать списки с привязками свойств. Вы никогда не получите сигнал уведомления, если он изменится. Поэтому, я думаю, QML Engine никогда не знает, что новый элемент QML имеет тип "Window", и его необходимо добавить в иерархию Windows.

Из документации ( https://www.ics.com/files/qtdocs/qml-list.html):

Свойство списка не может быть изменено любым другим способом. Элементы нельзя динамически добавлять или удалять из списка с помощью операций JavaScript; любые операции push() в списке изменяют только копию списка, а не фактический список. (Эти текущие ограничения связаны с ограничениями привязки свойств в тех случаях, когда используются списки.)

Может быть, это ошибка, может быть, функция. В любом случае, пока невозможно динамически загрузить тип "окна" с соответствующим временным родителем.

Лучший обходной путь, который я нашел, - использовать модальность: Qt.ApplicationModal для диалога.

Другие вопросы по тегам