Mircea
Mircea

Reputation: 1999

QML - GridLayout - unable to center a page using it

I'm new to Qt and QML and while I'm trying to learn them I've encountered the following problem which I'm not sure why they appeared.

I'm having a button, at the moment when I'm pressing it will display a new purple Rectangle over the screen. I am trying to position it at the center of the screen, or in other words to fill the whole screen, but for some reason, I can't do that, and It's always going to start from the beginning of Item 2 instead of the beginning of the screen. Also, it's going to be placed under Item 1 and Item 3 instead to overlay them.

enter image description here

MY CODE:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.12

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

    GridLayout {
        id : grid
        anchors.fill: parent
        rows    : 12
        columns : 20
        property double colMulti : grid.width / grid.columns
        property double rowMulti : grid.height / grid.rows
        function prefWidth(item){
            return colMulti * item.Layout.columnSpan
        }
        function prefHeight(item){
            return rowMulti * item.Layout.rowSpan
        }
        Rectangle {
            id: id1
            color : 'red'
            Layout.column: 0
            Layout.rowSpan: 10
            Layout.columnSpan: 2
            Layout.preferredWidth  : grid.prefWidth(this)
            Layout.preferredHeight : grid.prefHeight(this)
        }
        Rectangle {
            id: id2
            color : 'green'
            Layout.column: 2
            Layout.rowSpan: 10
            Layout.columnSpan: 18
            Layout.preferredWidth  : grid.prefWidth(this)
            Layout.preferredHeight : grid.prefHeight(this)
            Button{
                width: 100
                height: 100
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.verticalCenter: parent.verticalCenter
                onClicked: {
                    id2.state = "STATE_1"
                }
            }

            StackView{
                id: st
                width: parent.width
                height: parent.height + 100
                
                anchors.horizontalCenter: grid.parent.horizontalCenter
                anchors.verticalCenter: grid.parent.verticalCenter

                visible: false
                Rectangle{
                    anchors.fill: parent
                    color: "purple"
                    opacity: 0.7
                    Button{
                        width: 100
                        height: 100
                        onClicked: {
                            id2.state = "STATE_2"
                        }
                    }
                }
            }

            states: [
                State{
                    name: "STATE_1"
                    PropertyChanges {
                        target: st;
                        visible: true
                    }
                },
                State{
                    name: "STATE_2"
                    PropertyChanges {
                        target: st;
                        visible: false
                    }
                }
            ]
        }
        Rectangle {
            id: id3
            color : 'blue'
            Layout.column: 18
            Layout.rowSpan: 10
            Layout.columnSpan: 2
            Layout.preferredWidth  : grid.prefWidth(this)
            Layout.preferredHeight : grid.prefHeight(this)
        }
    }
}

Can anyone explain to me what I am doing wrong?

Upvotes: 2

Views: 737

Answers (2)

pooya13
pooya13

Reputation: 2671

I'm having a button, at the moment when I'm pressing it will display a new purple Rectangle over the screen. I am trying to position it at the center of the screen, or in other words to fill the whole screen

As @talamaki mentioned if you want the purple to fill the whole background it is better to have it as child of the main Item instead of having it be part of the grid, and then have it extend the allocated space inside the grid.

but for some reason, I can't do that, and It's always going to start from the beginning of Item 2 instead of the beginning of the screen.

That is because of how grids work. Think of it as like a chess board, item 1 already occupies the first two columns so item 2 will start from 3rd column, and any child of item 2 stars from the coordinate system of item 2. You could make it extend beyond it's starting point but I think it would be cleaner to have the background on the root item.

Also, it's going to be placed under Item 1 and Item 3 instead to overlay them.

To have the purple be underneath 1 and 3 it has to be drawn first (should come first in the QML). If you don't want the button to be affected you should put it below the GridLayout in the QML file so that it is drawn last over it. Putting all this together would be something like this:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.12

Window {
    id: mainD
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
        
    Rectangle{
        id: background
        anchors.fill: parent
        color: "purple"
        opacity: 0.7
        visible: false
    }

    GridLayout {
        id : grid
        anchors.fill: parent
        rows    : 12
        columns : 20
        property double colMulti : grid.width / grid.columns
        property double rowMulti : grid.height / grid.rows
        function prefWidth(item){
            return colMulti * item.Layout.columnSpan
        }
        function prefHeight(item){
            return rowMulti * item.Layout.rowSpan
        }
        
        Rectangle {
            id: id1
            color : 'red'
            Layout.column: 0
            Layout.rowSpan: 10
            Layout.columnSpan: 2
            Layout.preferredWidth  : grid.prefWidth(this)
            Layout.preferredHeight : grid.prefHeight(this)
        }
        Rectangle {
            id: id2
            color : 'green'
            Layout.column: 2
            Layout.rowSpan: 10
            Layout.columnSpan: 16
            Layout.preferredWidth  : grid.prefWidth(this)
            Layout.preferredHeight : grid.prefHeight(this)
        }
        Rectangle {
            id: id3
            color : 'blue'
            Layout.column: 18
            Layout.rowSpan: 10
            Layout.columnSpan: 2
            Layout.preferredWidth  : grid.prefWidth(this)
            Layout.preferredHeight : grid.prefHeight(this)
        }
    }

    Button{
        width: 100
        height: 100
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        onClicked: {
            background.visible = !background.visible
        }
    }
}

From your question it is not clear to me if you want Item 2 to disappear, have its colour blended with background, or have it remain on top when you click the button.

Upvotes: 1

talamaki
talamaki

Reputation: 5472

Purple rectangle is an initial item of StackView object with an id "st". It is hidden initially. "id2" is a visual parent of "st". Coordinates of "st" are relative to its visual parent. You are setting its width to be its parent's width and height to be parent's height + 100 so its (0,0) coordinate goes to parent's (0,0). You should read more from the documentation: Visual Parent in Qt Quick.

If you want to fill the whole screen with purple rectangle and position it on top of other visual items you can do it by moving "st" out from the "grid" and place it on the same level with it. Now both "grid" and "st" are children of "mainD", and because StackView is below "grid" you don't need to play with z values but when "st" becomes visible it is rendered on top of "grid".

Window {
    id: mainD
    ...

    GridLayout {
        id : grid
        ...
    }
    StackView{
        id: st
        width: parent.width
        height: parent.height// + 100

        //anchors.horizontalCenter: grid.parent.horizontalCenter
        //anchors.verticalCenter: grid.parent.verticalCenter

        visible: false
        Rectangle{
            anchors.fill: parent
            color: "purple"
            opacity: 0.7
            Button{
                width: 100
                height: 100
                onClicked: {
                    id2.state = "STATE_2"
                }
            }
        }
    }
}

enter image description here

I recommend Positioning elements chapter from free Qt5 Cadaques book for further reading.

Upvotes: 2

Related Questions