Search code examples
qmlqt5qtquick2

Set maximum width for RowLayout


I'm trying to build a custom control where I can place other controls (Buttons, Sliders, edit fields, etc.) grouped together.

The control should appear on the right side of the window and should have a fixed width of 200. This works fine:

RowLayout {
    Item {
        Layout.fillWidth: true
    }
    MyControl {
        Layout.fillHeight: true
        Layout.preferredWidth: 200
    }
}

Now, the problem is with the layouts and controls I used inside MyControl. I'm using a Rectangle with a ColumnControl in it and in the ColumnControl nested the GroupBoxes (see code below).

In one of the GroupBoxes I want to place several Buttons in a row, so I am using a RowLayout (I tried Row also, same result). If I only put two or three Buttons in a row, the Buttons get stretched to fill the entire width and everything is fine. But when I use more Buttons, they are not shrunk below a certain size. Instead, the RowLayout grows to the right and some of the Buttons are not visible since they are positioned outside the window.

It seems that the RowLayout calculates the size of its children first and then resizes itself. Now what I want is that the RowLayout is fixed to the parent width and the children are shrunk to fit into the parent.

I managed to do that with a workaround, but I'm not happy with that. There must be a more elegant way. I also tried to set the width of the RowLayout to the parent.width but got binding loops. Everything looked fine, but I don't want to write code which starts with a couple of warnings.

Here's the code of the control:

Rectangle {
    id: rootRect

    ColumnLayout {
        anchors.fill: parent
        spacing: 4

        GroupBox {
            Layout.fillWidth: true
            title: "GroupBox Title"

            RowLayout {
                id: buttonGroupWithWorkaround
                enabled: false
                anchors.fill: parent

                //the workaround:
                property int numberOfButtons: 6
                property int buttonWidth: (rootRect.width - 2 * buttonGroupWithWorkaround.spacing) / numberOfButtons - buttonGroupWithWorkaround.spacing

                Button {
                    Layout.preferredWidth: buttonGroupWithWorkaround.buttonWidth
                    text: "|<"
                }
                Button {
                    Layout.preferredWidth: buttonGroupWithWorkaround.buttonWidth
                    text: "<<"
                }
                Button {
                    Layout.preferredWidth: buttonGroupWithWorkaround.buttonWidth
                    text: "<"
                }
                Button {
                    Layout.preferredWidth: buttonGroupWithWorkaround.buttonWidth
                    text: ">"
                }
                Button {
                    Layout.preferredWidth: buttonGroupWithWorkaround.buttonWidth
                    text: ">>"
                }
                Button {
                    Layout.preferredWidth: buttonGroupWithWorkaround.buttonWidth
                    text: ">|"
                }
            }
        }

        GroupBox {
            Layout.fillWidth: true
            title: "NextGroupBox Title"

            RowLayout {
                id: theButtonGroup
                enabled: false
                anchors.fill: parent

                Button {
                    //this doesn't work
                    Layout.fillWidth: true
                    text: "|<"
                }
                Button {
                    Layout.fillWidth: true
                    text: "<<"
                }
                Button {
                    Layout.fillWidth: true
                    text: "<"
                }
                Button {
                    Layout.fillWidth: true
                    text: ">"
                }
                Button {
                    Layout.fillWidth: true
                    text: ">>"
                }
                Button {
                    Layout.fillWidth: true
                    text: ">|"
                }
            }
        }

        GroupBox {
            Layout.fillWidth: true
            title: "OtherGroupBox Title"
            //some other controls
        }
    }
}

Solution

  • Sizing can be sometimes a little bit tricky.

    fillWidth ensures that the Buttons grow or shrink to fill the available space. However, this behaviour is not arbitrary. It follows other constraints set on the Item. In particular, the size is never shrunk under the implicitWidth of the Item.

    Hence, in this case you can solve the issue by setting a smaller implicitWidth, like this:

    Button {
        Layout.fillWidth: true
        text: ">"
        implicitWidth: 20     // the minimum width will be 20!
    }
    

    Alternatively you can define a custom ButtonStyle which defines a well-sized label but it really sounds overkilling in this specific case.

    Have also a look at this answer (or other resources on SO) to have a better grasp about layouts/sizing.