QML:如何在网格中移动项目

时间:2012-07-29 17:11:46

标签: qt grid qml qt-quick

我有一个4x4网格,我想将箭头键按下与网格中项目的移动相关联。如何做到这一点?

以下是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;
}

更新1:感谢sebasgo和alexisdm的回答。如果在网格内移动并不那么容易,为什么我们有move过渡属性[http://qt-project.org/doc/qt-4.8/qml-grid.html#move-prop]

5 个答案:

答案 0 :(得分:8)

您最好使用GridView项而不是Grid方法。

这样您可以使用它的currentIndex属性来选择要移动的项目:

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;
}

答案 1 :(得分:3)

网格无法直接操纵所包含项目的位置。相反,它们的位置直接来自网格子项的物理顺序。有no easy way来动态处理QML中的子项,所以我认为你应该放弃Grid项并使用x和{{1}明确指定子项的位置}属性。应用于您的代码可能如下所示:

y

更新1:

网格(与Repeater结合使用)可用于可视化模型,例如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; } 项或XmlListModel后代。

使用QAbstractItemModel属性,可以很容易地以动画方式对模型中的布局更改(如果删除/添加条目)做出反应。尽管如此,move中的项目严格按照模型条目的顺序排列。

因此,如果您希望手动控制商品的位置,即使在细胞布局中,也不建议使用Grid

答案 2 :(得分:1)

您可以更改要移动的项目之前的项目数以更改其位置:

import QtQuick 1.1

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

    property int emptyBlock: 16;

    property int posX: 0;
    property int posY: 0;

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

        Repeater {
            id: beforeTheItem
            model: main.posX + parent.columns * main.posY
            Rectangle {
                width: 118; height: 118; color: "transparent";
            }
        }

        Rectangle {
            id:theItem
            width: 118; height: 118; color: "darkblue";
        }
    }

    Keys.onPressed: {
        // To avoid flickering, the item is hidden before the change
        // and made visible again after
        theItem.visible = false;
        switch(event.key) {
        case Qt.Key_Left: if(posX > 0) posX--;
            break;
        case Qt.Key_Right: if(posX < grid.columns - 1) posX++;
            break;
        case Qt.Key_Up: if(posY > 0) posY--;
            break;
        case Qt.Key_Down: if(posY < grid.rows - 1) posY++;
            break;
        }
        theItem.visible = true;
    }

    focus: true;
}

答案 3 :(得分:0)

现在,使用Qt 5.1或更高版本以及GridLayout,您可以毫不费力地移动您的商品:

import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1

Window
{
    visible: true

    MainForm
    {
        GridLayout {
            id: gridLayout
            columns: 3

            property int oneRow: 0
            property int oneCol: 0

            Text { id: one; Layout.row :grid.oneRow; Layout.column: grid.oneCol; text: "My"; font.bold: true; }

            Text { text: "name"; color: "red" }
            Text { text: "is"; font.underline: true }
            Text { text: "not"; font.pixelSize: 20 }
            Text { text: "Ravan"; font.strikeout: true }
        }

        Component.onCompleted:
        {
            gridLayout.oneRow = 1
            gridLayout.oneCol = 2
        }
    }
}

答案 4 :(得分:0)

GridView是一个非常令人困惑的怪物。我只是从给定模型中填充一行,这会导致混淆,因为它被称为GRID。但它仍然可以用作固定大小的网格,如下面的示例所示。可以使用箭头键在4x4大小的网格上移动单个方块。

    GridView {
        id: grid16;
        anchors.fill: parent
        cellWidth:  parent.width  / 2
        cellHeight: parent.height / 2

        model: gridModel

        delegate:
          Rectangle {
            Component.onCompleted: if( index >= 1 ) visible = false
            width: grid16.cellWidth ; height: grid16.cellHeight ; color: "yellow";
            Text {
              anchors.centerIn: parent
              font.pixelSize: 20
              text: value
            }
        }

        move: Transition {
            NumberAnimation { properties: "x,y"; duration: 1000 }
        }
    }

    ListModel {
      id: gridModel
      ListElement {value: 1}
      //Necessary, otherwise the grid will have the dimension 1x1
      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) }
    Keys.onUpPressed:    { gridModel.move(grid16.currentIndex, grid16.currentIndex-2, 1) }
    Keys.onDownPressed:  { gridModel.move(grid16.currentIndex, grid16.currentIndex+2, 1) }

    focus: true;
}