Rich von Lehe
Rich von Lehe

Reputation: 1542

QML Layout.alignment not behaving as expected

In the QML below, I have three items in a row layout with each item needing to be centered vertically in that layout.

The middle item is a PlayerSelector, which creates a varying number of text edit boxes to change the name of each player. I've tried two different ways to keep the PlayerSelector vertically centered. The one that works for me causes a runtime warning, the suggested method doesn't keep that item centered vertically. See these screen caps and the code below:

Method 1&2 both center initially Each method correctly centers the default player set

Method 1 correctly maintains vertical centering (anchors.verticalCenter) Correct centering using anchors.verticalCenter

Method 2 does not maintain vertical centering (Layout.alignment) Incorrect centering using Layout.alignment

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12

Item {
    id: gameStart
    anchors.top: parent.top
    height: parent.height
    width: parent.width
    signal playGame

    RowLayout {
        id: layout
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter

        RoundButton {
            id: playButton
            text: "Play"
            width: 40
            radius: 2
            font.pointSize: 12
            onClicked: {
                var players = selector.playerArray
                for (var i =0; i < players.count; i++) {
                    console.log(players.itemAt(i).playerName)
                    game.addPlayer(players.itemAt(i).playerName)
                }
                gameStart.playGame()

            }
        }

        PlayerSelector {
            id: selector
//            Layout.alignment: Qt.AlignVCenter             // method 2
            anchors.verticalCenter: layout.verticalCenter  // method 1
        }

        RoundButton {
            id: quitButton
            text: "Quit"
            width: 40
            radius: 2
            font.pointSize: 12
            onClicked: {
                game.quit()
            }
        }
    }
}

The problem with method 1 is that although it works, it shows this runtime warning:

qrc:/qml/GameStart.qml:41:9: QML PlayerSelector: Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.

Is there a way to get the alignment I'm after but not have the runtime warning? I'm worried about the undefined behavior part.

Upvotes: 0

Views: 2425

Answers (1)

pooya13
pooya13

Reputation: 2671

Alignment only works when the Layout size is bigger than the item size. So for example if layout's height is 200 and item's height is 100, then when you align vertically, the item will have 50 pixels on either side. But if the item is also 200 pixels, then it just fills it. In your case the PlayerSelector has the same height as the RowLayout, and is therefore aligned. The other items are not aligned in this case.

IMO there are two approaches in sizing a layout and its children:

1- Explicit sizes go from parents to children: you explicitly specify the size for the layout, and the size of children is relative to the size of layout. This is my personal preference since it is easier to make sure everything is sized and aligned correctly. When screen is resized things just shrink or stretch proportionately. In this approach only use Layout attached properties for both size and alignment.

2- Size of layout is implicitly defined from the size of the child items. (your approach) This approach can be more flexible and give you non-stretched but functional layouts when screen size changes, but there are more degrees of freedom for things to go wrong when screen is resized. In this approach, you can use (preferably) implicit or explicit sizes for children, but alignment still should be handled by Layout attached properties.

In your case it seems that the layout's height is set to the height of PlayerSelector (the largest height), so the other items are at the top of their row placement, and PlayerSelector is actually the only item that is vertically centered (it fills the whole height). So you could set alignment for all other items as well to make sure everything is centered.

Upvotes: 3

Related Questions