QML:Cómo mover elementos dentro de una cuadrícula
Pregunta
Tengo una cuadrícula de 4x4 y quiero asociar las pulsaciones de las teclas de flecha con el movimiento de elementos dentro de la cuadrícula.¿Cómo se hace eso?
Aquí hay un QML de muestra:
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;
}
Actualización 1: Gracias a sebasgo y alexisdm por las respuestas.Si moverse dentro de una cuadrícula no es tan fácil, ¿por qué tenemos la move
propiedad de transición [http://qt-project.org/doc/qt-4.8/qml-grid.html#move-prop]
Solución
Será mejor que uses un GridView
Artículo en lugar de tu Grid
acercarse.
De esta manera puedes utilizarlo. currentIndex
propiedad para elegir qué elemento mover de esta manera:
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;
}
Otros consejos
Las cuadrículas no le permiten manipular directamente la posición de los elementos contenidos.En cambio, su posición se deriva directamente del orden físico de los elementos secundarios de la cuadrícula.Hay no hay manera fácil para manipular elementos secundarios en QML dinámicamente, por lo que creo que deberías abandonar el Grid
elemento y especifique la posición de los elementos secundarios explícitamente con el x
y y
propiedades.Aplicado a su código, esto podría verse así:
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;
}
Actualización 1:
Las cuadrículas (en combinación con un repetidor) se pueden utilizar para visualizar modelos, por ejemplo, un XmlListModel
artículo o un QAbstractItemModel
descendiente.
Con move
propiedad es fácil reaccionar a los cambios de diseño en el modelo (si se elimina/agrega una entrada) de forma animada.Aun así, los elementos del Grid
se presentan estrictamente en el orden de las entradas del modelo.
Entonces, si desea tener control manual sobre la posición de sus artículos, incluso en el diseño celular, use un Grid
no es aconsejable.
Puede cambiar el número de elementos antes del elemento que desea mover para cambiar su posición:
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;
}
ahora, al usar qt 5.1 o superior y GridLayout Puede mover sus artículos sin problemas:
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
}
}
}
El GridView es un monstruo muy confuso.Simplemente pongo una fila de un modelo dado, lo que conduce a la confusión, ya que se llama cuadrícula.Pero aún se puede usar como una cuadrícula de tamaño fijo, ya que me muestro en el siguiente ejemplo.Un solo cuadrado se puede mover con las teclas de flecha en una cuadrícula de 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;
}