Home > Back-end >  Combination of Stackview with GridLayout with QML and PySide6
Combination of Stackview with GridLayout with QML and PySide6

Time:09-09

I have the following small Application:

main.py:

import sys
from pathlib import Path
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine



if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    # Get the path of the current directory, and then add the name
    # of the QML file, to load it.
    qml_file = Path(__file__).parent / "view.qml"
    engine.load(qml_file)

    if not engine.rootObjects():
        sys.exit(-1)

    sys.exit(app.exec())

and the

view.qml:

import QtQuick 2.0
import QtQuick.Layouts 1.11
import QtQuick.Controls 2.15
import QtQuick.Window 2.1

ApplicationWindow {
    id: main
    title: qsTr("Hello World")
    width: 640
    height: 480
    visible: true

    header: ToolBar {
        RowLayout {
            anchors.fill: parent
            ToolButton {
                text: qsTr("GridView1")
                onClicked: stack.push(grid_1)
            }
            ToolButton {
                text: qsTr("GridView2")
                onClicked: stack.push(grid_2)
            }
        }
    }

    StackView {
        id: stack
        initialItem: grid_1
        anchors.fill: parent
    }

    Component {
        id: grid_1

        GridLayout {
            id: grid
            columns: 3
            columnSpacing: 0

            Rectangle {
                id: red_1
                width: parent.width/5
                height: parent.height
                color: "red"
                border.color: "black"
                border.width: 5
                radius: 10

                Text {
                    text: grid.width
                    anchors.centerIn: red_1
                }
            }

            Rectangle {
                id: red_2
                width: parent.width*2/5
                height: parent.height/2
                color: "red"
                border.color: "green"
                border.width: 5
                radius: 10

                Text {
                    text: red_2.width
                    anchors.centerIn: red_2
                }
            }

            Rectangle {
                id: red_3
                width: parent.width*2/5
                height: parent.height
                color: "red"
                border.color: "blue"
                border.width: 5
                radius: 10

                Text {
                    text: red_3.width
                    anchors.centerIn: red_3
                }
            }
        }
    }

    Component {
        id: grid_2

        Rectangle {
            width: 100
            height: 100
            color: "green"
            border.color: "black"
            border.width: 5
            radius: 10
        }
    }
}

Now we come to the issue:

After launch the Window should look like this:

enter image description here

But instead it looks like this:

enter image description here

It seems like that the rectangle red_3 is stacked above the other rectangles. Only switching to GridView2 resolves this issue. But this brings another issue on the plan: While after a fresh restart of the Application a resizing of the Window results in a resizing of red_3 as wanted. After Switching between GridView2 and GridView1 and the Application looks like as in figure 1, resizing the Window, does not effect the rectangles anymore. The Resizing takes only place after switching between the GridViews

From my perspective it looks like InitialItem does not load the GridLayout correctely and push destroys some event handling. Am I wrong or/and how to solve this?

CodePudding user response:

Because you're using GridLayout, you should use Layout.preferredWidth and Layout.preferredHeight instead of width and height. Here's critical edits you need to make to your grid_1 component.

            Rectangle {
                id: red_1
                Layout.preferredWidth: parent.width/5
                Layout.preferredHeight: parent.height
                // ...
            }
            Rectangle {
                id: red_2
                Layout.preferredWidth: parent.width*2/5
                Layout.preferredHeight: parent.height/2
                // ...
            }
            Rectangle {
                id: red_3
                Layout.preferredWidth: parent.width*2/5
                Layout.preferredHeight: parent.height
                // ...
            }

However, because you are using Layouts, we can minimize the need for arithmetic in our geometry by using better Layout semantics such as Layout.fillWidth: true and Layout.fillHeight: true. In the case of the Layout.fillWidth: true because I also set Layout.preferredWidth to be 100, 200, 200 respectively it will achieve the 1/5, 2/5, 2/5 split you want.

            Rectangle {
                id: red_1
                Layout.preferredWidth: 100
                Layout.fillWidth: true
                Layout.fillHeight: true
                // ...
            }
            Rectangle {
                id: red_2
                Layout.preferredWidth: 200
                Layout.fillWidth: true
                Layout.preferredHeight: parent.height/2
                // ...
            }
            Rectangle {
                id: red_3
                Layout.preferredWidth: 200
                Layout.fillWidth: true
                Layout.fillHeight: true
                // ...
            }

I was able to run the above on pyside6 on Ubuntu 20 with https://github.com/stephenquan/pyside-stackoverflow/tree/master/73640872

  • Related