'How to skip drawing an item when a Grid is populated via an Repeater in qml?

I want to fill a Grid with a Repeater but not all cells should get an Item. How to do that?

Rectangle {
    id: base

    Grid {
        id: grid
        anchors.fill: parent
        columns: 30
        rows: 20

        Repeater {
            model: grid.columns * grid.rows
            delegate: Item {
                // How to skip this at row 5, column 3, for example
                width: grid.width / grid.columns
                height: grid.height / grid.rows
            }
        }
    }
}
qml


Solution 1:[1]

This is basically the same problem, as how can I have different delegates in a Repeater depending on the model's data with the special case: The delegate is empty.

For this more general approach, you can use dynamic object creation like this:


    Window {
        id: root
        visible: true
        width: 400; height: 400


        // delegate 0 is skipped, 1 is circle, 2 is quadrangle
        ListModel {
            id: lm
            ListElement { delegate: 0 }
            ListElement { delegate: 1; color: 'red' }
            ListElement { delegate: 2; color: 'green' }
            ListElement { delegate: 1; color: 'blue' }
            ListElement { delegate: 0 }
            ListElement { delegate: 0 }
            ListElement { delegate: 1; color: 'orchid' }
            ListElement { delegate: 0 }
            ListElement { delegate: 1; color: 'red' }
            ListElement { delegate: 2; color: 'green' }
            ListElement { delegate: 1; color: 'blue' }
            ListElement { delegate: 0 }
            ListElement { delegate: 0 }
            ListElement { delegate: 1; color: 'orchid' }
        }


        Grid {
            anchors.fill: parent
            columns: 5
            Repeater {
                id: rep
                property var delegates: [function() { console.log('skipped'); return null }, circ.createObject, rect.createObject ]
                model: lm
                delegate: Item {
                    width: (delegate ? delegate.width : 1)
                    height: (delegate ? delegate.height : 1)
                    property var delegate: rep.delegates[model.delegate](this, { color: model.color })
                }
            }
        }


        Component {
            id: circ
            Rectangle {
                width: 20
                height: 20
                radius: 10
            }
        }

        Component {
            id: rect
            Rectangle {
                width: 20
                height: 20
            }
        }
    }

Of course you can use any cirterium and method to chose, whether or which delegate should be used. The ListModel and list of functions just seems to be convenient in lots of cases. You can also just use a switch-statement or anything else.

Instead of using the JS-function you could also use a Loader as toplevel element, and set or not set a source. You only need to make sure the toplevel delegate has dimensions (at least width and height of 1) otherwise the positioners (Grid/Column/Row) will ignore their existence.

The advantage of the dynamic creation is, that if the delegate is complex, it won't be created and just turned invisible, as it would be with the solution of Tony Clifton

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shirkrin