列表拖动排序在很多应用中都存在, 在 Qt Quick 中如何实现呢。网上查了下没有太多相关资料,于是决定自己写一个。
原理
MouseArea 中可以可以设置 DragEvent 来对某个 Item 进行拖动。Drag 这个类一般附着在可能被拖动的 Item 上,用来设置相关的信息。它提供了很多附加属性。如
- Drag.active: bool 这个属性用来指示控件是否正在被拖动。可以用来绑定 MouseArea 的 MouseArea::drag 属性,当用户拖动鼠标的时候就会产生 drag 事件。
- Drag.target : Object 当 active 为 true (拖动处于活跃状态)时,这个属性保存最后一个被拖动的 dragged item。
DropArea 定义了一个可以接收拖放的区域。它的 entered 信号在有物体被拖入区域时发射,exited 信号在物体被拖出区域时发射,当物体在区域内被拖着来回移动时会不断发射 positionChanged 信号,当用户释放了物体,dropped 信号被发射。
在这个例子中,我们需要在整个 ListView 中填充一个 DropArea 用来接收释放的 Item。Item 中绑定 MouseArea 的 drag 事件。释放的时候计算相应的位置并把拖动位置的 Item 移到释放位置。需要注意的是列表滚动之后要加上滚动的距离。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| Item { id:root anchors.fill: parent ListView { id: listView width: parent.width / 2 height: parent.height property int dragItemIndex: -1 ScrollBar.vertical: ScrollBar{id:scrollBar}
DropArea { id: dropArea anchors.fill: parent onDropped: { var targetIndex = listView.indexAt(drag.x, drag.y + listView.contentY) listView.model.move(listView.dragItemIndex, targetIndex, 1) listView.dragItemIndex = -1; } }
model: ListModel { Component.onCompleted: { for (var i = 0; i < 30; ++i) { append({value: i}); } } }
delegate: Item { id: delegateItem width: listView.width height: 30
Rectangle { anchors.fill: parent Label { text: index+1 anchors.verticalCenter: parent.verticalCenter }
Rectangle { id: dragRect width: listView.width-50 height: 30 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.axis: Drag.YAxis
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 }
} } }
}
|