Search code examples
frontendqmlqtquick2qt-quickqqmlcomponent

How do I create a scaleable GridLayout in QML?


I am currently trying to create an application that includes a Periodic table. I want to to display this as a GridLayout where each Element is represented as a GroupBox inside the Layout. The problem I am facing is that the GridLayout wont scale properly with the window that it is positioned in. It opens up as follows:

GridLayout on first start

I can also scale up the window like this:

GridLayout after upsizing the window

or donwscale it like the following:

GridLayout after downsizing the window

As you can see, the GridLayout doesnt seem to scale with the window size. Instead it seems to have a fixed size (Some elements are cut off from the beginning, if I scale down the window the elements are also being cut off)

Here is my code:

Item {
    id: root
    Button {
        id: button
        checkable: true
        text: qsTr("Show")

        onClicked: window.show()
    }
    Window {
        id: window
        Material.accent: parent.Material.accent
        Material.background: parent.Material.background
        Material.foreground: parent.Material.foreground
        Material.primary: parent.Material.primary
        Material.theme: parent.Material.theme
        color: Material.background
        height: parent.height
        title: qsTr("Periodic table")
        width: parent.width

        GridLayout {
            id: grid
            columns: 18

            PeriodicTableElement {
                Layout.fillHeight: true
                Layout.fillWidth: true
                atomicWeight: qsTr("1.00794")
                electronConfiguration: qsTr("1s")
                elementName: qsTr("Hydrogen")
                elementSign: qsTr("H")
                ionizationEnergy: qsTr("13 5984")
                ordinalNumber: qsTr("1")
                unknownNumber: qsTr("S1/2")
            }
            Repeater {
                model: 16

                GroupBox {
                    background: Item {
                    }
                }
            }
            Repeater {
                model: 3

                PeriodicTableElement {
                    Layout.fillHeight: true
                    Layout.fillWidth: true
                    atomicWeight: qsTr("1.00794")
                    electronConfiguration: qsTr("1s")
                    elementName: qsTr("Hydrogen")
                    elementSign: qsTr("H")
                    ionizationEnergy: qsTr("13 5984")
                    ordinalNumber: qsTr("1")
                    unknownNumber: qsTr("S1/2")
                }
            }
            Repeater {
                model: 10

                GroupBox {
                    background: Item {
                    }
                }
            }
            Repeater {
                model: 6

                PeriodicTableElement {
                    Layout.fillHeight: true
                    Layout.fillWidth: true
                    atomicWeight: qsTr("1.00794")
                    electronConfiguration: qsTr("1s")
                    elementName: qsTr("Hydrogen")
                    elementSign: qsTr("H")
                    ionizationEnergy: qsTr("13 5984")
                    ordinalNumber: qsTr("1")
                    unknownNumber: qsTr("S1/2")
                }
            }
            Repeater {
                model: 100

                PeriodicTableElement {
                    Layout.fillHeight: true
                    Layout.fillWidth: true
                    atomicWeight: qsTr("1.00794")
                    electronConfiguration: qsTr("1s")
                    elementName: qsTr("Hydrogen")
                    elementSign: qsTr("H")
                    ionizationEnergy: qsTr("13 5984")
                    ordinalNumber: qsTr("1")
                    unknownNumber: qsTr("S1/2")
                }
            }
        }
    }
}

I already tried using anchors.fill: window for the GridLayout but it didnt seem to have any effect.

So do I make this GridLayout scale with the window item which is his parent?

Thanks in advance for any helpful comment.


Solution

  • Have you considered GridView instead? This will have the following advantages:

    • Provide the dimension of each delegate via cellWidth and cellHeight
    • Provide a ListModel that helps us render the periodic table

    Here's a mock implementation of the first two lines of the periodic table using this approach:

    import QtQuick
    import QtQuick.Controls
    import QtQuick.Layouts
    Page {
        GridView {
            id: grid
            anchors.fill: parent
            cellWidth: parent.width / 18
            cellHeight: cellWidth * 2
            model: ElementsModel { }
            delegate: ElementDelegate { }
        }
    }
    
    // ElementsModel.qml
    import QtQuick
    import QtQuick.Controls
    ListModel {
        id: elems
        ListElement { at: 1; sy: "H"; na: "Hydrogen"; co: "#ccf" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 2; sy: "He"; na: "Helium"; co: "pink" }
        ListElement { at: 3; sy: "Li"; na: "Lithum"; co: "#cff" }
        ListElement { at: 4; sy: "Be"; na: "Beryllium"; co: "#fcc" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 0; sy: ""; na: ""; co: "" }
        ListElement { at: 5; sy: "B"; na: "Boron"; co: "#ffe" }
        ListElement { at: 6; sy: "C"; na: "Carbon"; co: "#ccf" }
        ListElement { at: 7; sy: "N"; na: "Nitrogen"; co: "#ccf" }
        ListElement { at: 8; sy: "O"; na: "Oxygen"; co: "#ccf" }
        ListElement { at: 9; sy: "F"; na: "Flourine"; co: "#ccf" }
        ListElement { at: 10; sy: "Ne"; na: "Neon"; co: "pink" }
    }
    
    // ElementDelegate.qml
    import QtQuick
    import QtQuick.Controls
    import QtQuick.Layouts
    Rectangle {
        property int cellWidth: GridView.view.cellWidth
        property int cellHeight: GridView.view.cellHeight
        width: cellWidth
        height: cellHeight
        color: co ? co : "#eee"
        Text {
            anchors.centerIn: parent
            text: sy
            font.pixelSize: cellHeight / 4
        }
        Text {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            text: na
            font.pixelSize: tm.scaledPixelSize
        }
        Text {
            text: at
            visible: at
            font.pixelSize: cellWidth / 5
        }
        TextMetrics {
            id: tm
            text: na
            font.pixelSize: 10
            property real scaledPixelSize: cellWidth / tm.width * font.pixelSize * 0.9
        }
    }
    

    You can Try it Online!