Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QML: How to move items within a grid

I have a 4x4 grid and I want to associate arrow key presses with the movement of items within the grid. How does one do that?

Here is a sample QML:

import QtQuick 1.1

Rectangle {
    id: main;
    width: 500; height: 500;
    color: "darkgreen";

    property int emptyBlock: 16;

    Grid {
        id: grid16;
        x: 5; y: 5;
        width: 490; height: 490;
        rows: 4; columns: 4; spacing: 5;

        Repeater {
            model: 1;
            Rectangle {
                width: 118; height: 118; color: "darkblue";
            }
        }
    }

    Keys.onRightPressed: pressRight();

    function pressRight() {
        console.log("Left key pressed");
    }

    focus: true;
}

Update 1: Thanks to sebasgo and alexisdm for the answers. If moving within a grid is not that easy why we have the move transition property [http://qt-project.org/doc/qt-4.8/qml-grid.html#move-prop]

like image 424
Xolve Avatar asked Jul 29 '12 17:07

Xolve


2 Answers

You'd better use a GridView Item instead of your Grid approach.

This way you can use it's currentIndex property to choose which item to move like this:

import QtQuick 1.1

Rectangle {
    id: main;
    width: 500; height: 500;
    color: "darkgreen";

    property int emptyBlock: 16;

    GridView {
        id: grid16;
        x: 5; y: 5;
        width: 490; height: 490;

        model: gridModel

        delegate: Component{
          Rectangle {
            width: 118; height: 118; color: "darkblue";
            Text {
              anchors.centerIn: parent
              font.pixelSize: 20
              text: value
            }
          }
        }
    }

    ListModel {
      id: gridModel
      ListElement {value: 1}
      ListElement {value: 2}
      ListElement {value: 3}
      ListElement {value: 4}
    }

    Keys.onRightPressed: {
      gridModel.move(grid16.currentIndex, grid16.currentIndex+1, 1)
    }

    Keys.onLeftPressed: {
      gridModel.move(grid16.currentIndex, grid16.currentIndex-1, 1)
    }

    focus: true;
}
like image 123
TheHuge_ Avatar answered Oct 01 '22 23:10

TheHuge_


Grids give you no way to manipulate the position of the contained items directly. Instead their position is directly derived from the physically order of the child items of the grid. There is no easy way to to manipulate child items in QML dynamically, so I think you should abandon the Grid item and specify the position of the child items explicitly with the x and y properties. Applied to your code this could look like:

Rectangle {
    id: main;
    width: 500; height: 500;
    color: "darkgreen";

    Item {
        x: 5; y: 5;
        width: 490; height: 490;

        Repeater {
            id: pieces
            model: 1;
            Rectangle {
                property int column: 0
                property int row: 0
                x: column * 123
                y: row * 123
                width: 118; height: 118; color: "darkblue";
            }
        }
    }

    Keys.onRightPressed: pressRight();

    function pressRight() {
        console.log("Left key pressed");
        pieces.itemAt(0).column++
    }

    focus: true;
}

Update 1:

Grids (in combination with a Repeater) can be used to visualize models, e.g., a XmlListModel item or an QAbstractItemModel descendent.

With move property it's easy to react to layout changes in the model (if an entry is removed/added) in an animated way. Still, the items in the Grid are laid out strictly in the order of the entries of the model.

So if you want have manual control over the position of your items, even in cellular layout, use of a Grid is not advisable.

like image 24
sebasgo Avatar answered Oct 02 '22 00:10

sebasgo