使用 ListView 拖放来创建清单 UI [英] Using drag and drop with ListView to create an inventory UI
问题描述
我想使用 ListView 为我的游戏创建一个物品栏 UI,可以通过在关卡中拖放物品来从物品栏中移除物品.如果物品没有被正确放下(仍在物品栏中),则应将其放回拖动前的位置.
I'd like to create an inventory UI for my game using ListView, where the items can be removed from the inventory by dragging and dropping them in the level. If an item was not dropped properly (still inside the inventory), it should be placed back where it was before the drag.
我有以下代码,但我不知道如何实现我所追求的,即使查看了 拖放示例.
I've got the following code, but I don't know how to achieve what I'm after, even after looking at the Drag and Drop example.
import QtQuick 2.3
Rectangle {
id: root
width: 400
height: 400
ListView {
id: listView
width: parent.width / 2
height: parent.height
model: ListModel {
Component.onCompleted: {
for (var i = 0; i < 10; ++i) {
append({value: i});
}
}
}
delegate: Item {
id: delegateItem
width: listView.width
height: 50
Rectangle {
id: dragRect
width: listView.width
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: "salmon"
border.color: Qt.darker(color)
Text {
anchors.centerIn: parent
text: modelData
}
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: dragRect
}
Drag.hotSpot.x: dragRect.width / 2
Drag.hotSpot.y: dragRect.height / 2
}
}
}
Rectangle {
width: parent.width / 2
height: parent.height
anchors.right: parent.right
color: "#aaff0011"
DropArea {
id: dropArea
anchors.fill: parent
}
}
}
推荐答案
您可以使用以下代码实现:
You can achieve this with the following code:
import QtQuick 2.3
Rectangle {
id: root
width: 400
height: 400
ListView {
id: listView
width: parent.width / 2
height: parent.height
property int dragItemIndex: -1
model: ListModel {
Component.onCompleted: {
for (var i = 0; i < 10; ++i) {
append({value: i});
}
}
}
delegate: Item {
id: delegateItem
width: listView.width
height: 50
Rectangle {
id: dragRect
width: listView.width
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: "salmon"
border.color: Qt.darker(color)
Text {
anchors.centerIn: parent
text: modelData
}
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: dragRect
drag.onActiveChanged: {
if (mouseArea.drag.active) {
listView.dragItemIndex = index;
}
dragRect.Drag.drop();
}
}
states: [
State {
when: dragRect.Drag.active
ParentChange {
target: dragRect
parent: root
}
AnchorChanges {
target: dragRect
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: dragRect.width / 2
Drag.hotSpot.y: dragRect.height / 2
}
}
}
Rectangle {
width: parent.width / 2
height: parent.height
anchors.right: parent.right
color: "#aaff0011"
DropArea {
id: dropArea
anchors.fill: parent
onDropped: {
listView.model.remove(listView.dragItemIndex);
listView.dragItemIndex = -1;
}
}
}
}
此示例中需要注意的一些事项:
Some things to notice in this example:
我们存储
dragItemIndex
以便我们知道哪个项目被拖动.我们也许可以通过查看 DropArea 的 drag.source 属性,但是我们必须在委托中公开一个索引属性,以及 文档不鼓励在委托中存储状态.
We store the
dragItemIndex
so that we know which item is being dragged. We might be able to achieve the same thing by looking at DropArea's drag.source property, but then we'd have to expose an index property in the delegate, and the documentation discourages storing state in delegates.
为了实现将项目放回不成功拖动的位置"功能,我们将 dragRect
设置为实际委托项目的子项,以便它有一个父项可以坚持.如果我们不这样做,该项目的父项将是 ListView,并且当不成功拖放时,它只会放在最后一次拖动的位置.
To achieve the "items get placed back where they were on unsuccessful drags" functionality, we make dragRect
a child of the actual delegate item, so that it has a parent to stick to. If we didn't do this, the item's parent would be the ListView, and when unsuccessfully dropped, it would just lay where it was last dragged.
我们使用与 拖放相同的状态更改行为例子;拖动时,我们希望从项目中移除锚点并让它自由拖动.如果拖动失败,状态 (dragRect.Drag.active
) 的 when
条件变为 false,并且该项目的父级返回到尚未移动的委托项目从其在列表视图中的原始位置.锚也恢复了.这是状态的一个有用特性;能够隐式恢复以前的状态.
We use the same state change behaviour as the Drag and Drop example; upon dragging we want to remove the anchors from the item and let it be dragged freely. If the drag fails, the when
condition for the state (dragRect.Drag.active
) becomes false, and the item is parented back to the delegate item that hasn't moved from its original place in the list view. The anchors are also restored. This is a useful feature of states; being able to implicitly restore previous state.
在 MouseArea
的 drag.onActiveChanged
信号处理程序中,我们调用 dragRect.Drag.drop()
以便我们可以在 DropArea
的 onDropped
信号处理程序中响应该事件,并删除该项目.删除项目后,我们将 dragItemIndex
重置为无效索引.
In the MouseArea
's drag.onActiveChanged
signal handler, we call dragRect.Drag.drop()
so that we can respond to that event in DropArea
's onDropped
signal handler, and remove the item. After the item has been removed, we reset the dragItemIndex
to an invalid index.
这篇关于使用 ListView 拖放来创建清单 UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!