Unable to change parent and child window Z order after calling loader
-
I have a QML application that uses a "Loader":http://qt-project.org/doc/qt-5/qml-qtquick-loader.html" type to load another QML page that creates multiple top-level windows that displays images. I want to be able to change the Z order of the image windows with respect to the main QML application window. This works fine until I use the loader to load another QML file, at which point the relative Z order of the main application window and the image windows becomes locked (e.g. calling raise() on the image window raises both main window and the image windows). Here is a test QML application that shows the problem.
Main.qml:
@
import QtQuick 2.1
import QtQuick.Window 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0import "."
Item {
id: rctMainContainerproperty bool childOnTop: false signal reload() width: 1024 height: 1024 Rectangle { id: rctParent width: 1024 height: 1024 color: "blue" Item { id: itmContent anchors.fill: parent Loader { id: contentLoader source: "Container.qml" anchors { fill: parent } Connections { target: rctMainContainer onReload: { contentLoader.source = ""; contentLoader.source = "Container.qml"; } } Component.onCompleted: { if (contentLoader.status === Loader.Error) { rctParent.color = "red"; } else if (contentLoader.status === Loader.Null) { rctParent.color = "magenta"; } else if (contentLoader.status === Loader.Ready) { rctParent.color = "green"; } else if (contentLoader.status === Loader.Loading) { rctParent.color = "yellow"; } else { rctParent.color = "white"; } } } } Button { id: btnSwap width: 100 height: 36 anchors{ top: parent.top left: parent.left margins:10 } visible: true enabled: true Text { id: lblSwapText anchors.fill: parent text: "Swap" } onClicked: { childOnTop = !childOnTop; } } Button { id: btnReload width: 100 height: 36 anchors{ top: btnSwap.bottom left: parent.left margins:10 } visible: true enabled: true Text { id: lblReloadText anchors.fill: parent text: "Reload" } onClicked: { reload(); } } Rectangle { id: rctHeaderCloseContainer width: 27 height: 27 anchors.right: parent.right anchors.top: parent.top Image { id:imgClose anchors.fill: parent source: "../images/close.png" } MouseArea { id: btnClose_mouseArea anchors.fill: imgClose cursorShape: Qt.PointingHandCursor; onClicked: Qt.quit() } } }
}
@Container.qml
@
import QtQuick 2.1
import QtQuick.Window 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0import "."
Item {
id: itmWindowContainerRepeater { id: rptWindow model: 2 anchors.fill: parent Item { id: itmWindow MyWindow { id: winMyWindow x: 500 + (index*300) y: 800 + (index*300) width: 300 height: 300 visible: true } } }
}
@MyWindow.qml
@
import QtQuick 2.1
import QtQuick.Window 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0Window{
id: winNewflags: Qt.FramelessWindowHint Connections { target: rctMainContainer onChildOnTopChanged: { if (childOnTop) { winNew.raise(); } else { winNew.lower(); } } } Rectangle { id: rctWindow anchors.fill: parent color: "cyan" }
}
@To test, save all three QML files into a directory and run "qmlscene main.qml" from the command line inside that directory.
When the application first opens, you can use the SWAP button to bring the cyan colored windows in front of or behind the main application window. However, after clicking the RELOAD button which loads the same Container.qml file, the cyan colored windows are now locked to appear in front of the main application window.
Does anyone have any ideas on a way to get around this?
In case you are wondering why I load the same QML file twice...the real application uses a Loader to load different QML files, and some of those QML files create windows to display images while others do not. The behavior is the same as the test application I provided.
-
I think what happens is once you reload, the main window becomes active. Then calling raise and lower is raising and lower the main window (and its child) relative to the other windows in the OS. I just experimented and found that changing your onTopChildChanged handler as follows results in the desired behavior (at least under windows 7):
@ onChildOnTopChanged: {
if (childOnTop) {
winNew.requestActivate()
winNew.raise();
}
else {
winNew.requestActivate()
winNew.lower();
}
}@