使用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的拖动,我们也许可以实现相同的目的.source 属性,但随后我们必须在委托中公开index属性,并
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屋!