Using drag and drop with a ListView to create an inventory UI
I would like to create an inventory UI for my game using a ListView where items can be removed from the inventory by dragging and dropping them onto the level. If the item has not dropped properly (still inside the inventory), it should be placed where it was before being dragged.
I have the following code, but I don't know how to achieve what I need, even by 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
}
}
}
source to share
This can be done 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;
}
}
}
}
In this example, you can notice some things:
-
We save
dragItemIndex
so we know which element is being dragged. Perhaps we can achieve the same by looking at the DropArea drag.source property , but then we would need to open the index property in the delegate, and <documentation href = "http://qt-project.org/doc/qt-5/qml -qtquick-listview.html # example-usage "> prevents state from being persisted in delegates. -
To ensure that the "items are returned to where they were on unsuccessful drags" function, we make the
dragRect
actual delegate item a child so that it has a parent. If we didn't, the parent of the item was the ListView, and on unsuccessful failure, it just lay where it was last time. -
We use the same state changing behavior as in the drag and drop example ; when dragging, we want to remove the anchors from the element and allow it to move freely. If the drag fails, the condition
when
for state (dragRect.Drag.active
) becomes false, and the item falls back to the delegate item, which does not move from its original location as a list. Anchors are also fixed. This is a useful function of states; the ability to implicitly restore the previous state. -
In the signal handler,
MouseArea
drag.onActiveChanged
we calldragRect.Drag.drop()
so that we can respond to this event in the signal handlerDropArea
onDropped
and remove the element. After deleting the item, we reset itdragItemIndex
to an invalid index.
source to share