Search code examples
qtqmlgrid-layoutqqmlcomponent

QML - GridLayout - ROW and COLUMN Span - Understanding


I'm trying to learn QML and at this moment I'm having some problems with understanding of rowSpan and columnSpan, so sorry if this question may sound stupid for some of you.


WHAT I LEARNED:

Correct me if I'm wrong but in a GridLayout should be like this:

  • Layout.row - indicates the line where the object is located;
  • Layout.column - indicates the column in which the object is located;
  • Layout.rowSpan - indicates how many lines should be stretched object;
  • Layout.columnSpan - indicates how many columns should be stretched object;

WHAT I'M TRYING TO DO:

Well, in this case, I'm trying to recreate this layout over here enter image description here

This layout, in theory, should have the followings:

  • The actual GridLayout should be composed out of 24 columns and 9 rows
  • RED shape should be at -> col 0, row 1 -> colSpan 3, rowSpan 7
  • BLUE shape should be at -> col 3, row 1 -> colSpan 8, rowSpan 1
  • PURPLE shape should be at -> col 3, row 4 -> colSpan 6, rowSpan 3

Or at least that's what I've understood so far.


THE PROBLEM:

After I've coded the QML with the col, row accordantly, and also colSpan and rowSpan I've obtained this instead.

enter image description here


MY CODE:

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1

Item {
    width: 1366
    height: 512

    GridLayout {
        id: grid

        columns: 24
        rows: 9
        anchors.fill: parent

        Rectangle {

            property var rowSpan: 7
            property var columSpan: 3

            Layout.column: 0
            Layout.row: 1

            Layout.preferredWidth: (parent.width / parent.columns) * columSpan
            Layout.preferredHeight: (parent.height / parent.rows) * rowSpan

            Layout.columnSpan: columSpan
            Layout.rowSpan: rowSpan

            color: "red"

        }

        Rectangle {
            property var rowSpan: 1
            property var columSpan: 8

            Layout.column: 3
            Layout.row: 1

            Layout.preferredWidth: (parent.width / parent.columns) * columSpan
            Layout.preferredHeight: (parent.height / parent.rows) * rowSpan

            Layout.columnSpan: columSpan
            Layout.rowSpan: rowSpan

            color: "blue"
        }
        Rectangle {
            property var rowSpan: 3
            property var columSpan: 6

            Layout.column: 4
            Layout.row: 3

            Layout.preferredWidth: (parent.width / parent.columns) * columSpan
            Layout.preferredHeight: (parent.height / parent.rows) * rowSpan

            Layout.columnSpan: columSpan
            Layout.rowSpan: rowSpan

            color: "purple"
        }
    }
}

Could anyone explain to me what I'm doing wrong or which part of GridLayout I didn't get it right?


Solution

  • You seem to want to use the GridLayout as if the given space is divided into the given column/row count and each cell is a fixed size. However, the idea behind the GridLayout is that it adjusts each column and each row to the needs of the items in the cells.

    So what happens is that you leave some cells empty, however the GridLayout will make these rows/columns 0 pixels high/wide, leading to a chaotic result far from your expectation.

    In order to make GridLayout play nice with your setup you can put empty Item's in between, with the preferredWidth/Height set similar to your code, leading to quite some unused QML, and an unreadable piece of code.

    In order to have a better setup, you could create your own layout item. The following should work:

    import QtQuick 2.0
    import QtQuick.Layouts 1.3
    
    Item {
        id: layout
    
        property int columns: 1
        property int rows: 1
    
        onChildrenChanged: updatePreferredSizes()
        onWidthChanged: updatePreferredSizes()
        onHeightChanged: updatePreferredSizes()
        onColumnsChanged: updatePreferredSizes()
        onRowsChanged: updatePreferredSizes()
    
        function updatePreferredSizes()
        {
            if(layout.children.length === 0)
            {
                return
            }
    
            var cellWidth = layout.width / columns;
            var cellHeight = layout.height / rows;
            for(var i=0;i<layout.children.length;++i)
            {
                var obj = layout.children[i]
    
                var c = obj.Layout.column
                var r = obj.Layout.row
                var cs = obj.Layout.columnSpan
                var rs = obj.Layout.rowSpan
    
                obj.x = c * cellWidth;
                obj.y = r * cellHeight;
                obj.height = cs * cellHeight;
                obj.width = rs * cellWidth;
            }
    
        }
    }
    

    Btw, your main code can be reduced to this (where MyGrid is the above QML):

    MyGrid {
        id: grid
        columns: 24
        rows: 9
        anchors.fill: parent
    
        Rectangle {
            Layout.column: 0
            Layout.row: 1
            Layout.columnSpan: 7
            Layout.rowSpan: 3
    
            color: "red"
        }
    
        Rectangle {
            Layout.column: 3
            Layout.row: 1
            Layout.columnSpan: 1
            Layout.rowSpan: 8
    
            color: "blue"
        }
        Rectangle {
            Layout.column: 4
            Layout.row: 3
            Layout.columnSpan: 3
            Layout.rowSpan: 6
    
            color: "purple"
        }
    }