我尝试在Qt 5.3中使用新的QML类型Drag
, DragEvent
和DropArea
来实现拖放。这是QML Drag
类型文档中的原始示例,进行了一些小修改:
import QtQuick 2.2
Item {
width: 800; height: 600
DropArea {
width: 100; height: 100; anchors.centerIn: parent
Rectangle {
anchors.fill: parent
color: parent.containsDrag ? "red" : "green"
}
onEntered: print("entered");
onExited: print("exited");
onDropped: print("dropped");
}
Rectangle {
x: 15; y: 15; width: 30; height: 30; color: "blue"
Drag.active: dragArea.drag.active
// Drag.dragType: Drag.Automatic
Drag.onDragStarted: print("drag started");
Drag.onDragFinished: print("drag finished");
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
}
}
}
预期行为:可以用鼠标拖动小蓝色矩形(拖动目标)。如果拖动到窗口中心较大的绿色矩形上,则该矩形将变为红色,并在离开时变回绿色。此外,及时发出dragStarted、entered、exit 、dropped和dragFinished信号,并由相应的信号处理程序打印出它们的消息。
<<p> 经验丰富的行为/strong>:依赖于Drag.dragType
(见上面的注释行):
Drag.dragType
未设置(默认为Drag.Internal
):拖放按描述的方式工作,但只发出输入和退出的信号。其他信号(dragStarted、dragFinished和dropped)被抑制。所以没有办法对
DropArea
的下降做出反应。Drag.dragType
设置为Drag.Automatic
:现在发出了所有的信号,但是蓝色矩形(拖动目标)不随鼠标移动。相反,鼠标光标改变其形状以显示可能的投放目标。鼠标被释放后,蓝色矩形会跳转到鼠标的最新位置。
这两种变体都不令人满意。我怎样才能得到所有的信号,并且仍然能够在拖动目标周围拖动?不幸的是,文档中对QML中的拖放操作的描述非常不清楚,特别是关于不祥的Drag.dragType
。
如果您打开QQuickDrag
源代码并查看Drag.Internal
使用的start()
和Drag.Automatic
使用的startDrag()
之间的差异,差异非常明显。start()
设置了一个事件更改监听器,然后使用它来更新附加对象的位置。startDrag()
不这样做。
为什么会这样?我不知道!qtquick2的拖放文档当然还有改进的空间。
有一个相当简单的解决方法:从两个世界中取其精华。使用Drag.Automatic
,但不设置Drag.active
,而是手动调用start()
和drop()
。它不会调用Drag.onDragStarted()
和Drag.onDragFinished()
,但是通过侦听MouseArea
的drag.active
的变化,您基本上可以免费获得它们。
下面是实际的概念:
import QtQuick 2.0
Item {
width: 800; height: 600
DropArea {
width: 100; height: 100; anchors.centerIn: parent
Rectangle {
anchors.fill: parent
color: parent.containsDrag ? "red" : "green"
}
onEntered: print("entered");
onExited: print("exited");
onDropped: print("dropped");
}
Rectangle {
x: 15; y: 15; width: 30; height: 30; color: "blue"
// I've added this property for simplicity's sake.
property bool dragActive: dragArea.drag.active
// This can be used to get event info for drag starts and
// stops instead of onDragStarted/onDragFinished, since
// those will neer be called if we don't use Drag.active
onDragActiveChanged: {
if (dragActive) {
print("drag started")
Drag.start();
} else {
print("drag finished")
Drag.drop();
}
}
Drag.dragType: Drag.Automatic
// These are now handled above.
//Drag.onDragStarted: print("drag started");
//Drag.onDragFinished: print("drag finished");
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
}
}
}
我知道这不是一个完全令人满意的解决方案,但它确实符合你期望的行为。
这个解决方案提供:
- 所有所需事件的通知:拖拽开始,拖拽完成,进入拖拽区域,退出拖拽区域,以及拖拽区域。
- 拖动动画由QtQuick自动处理。当使用
Drag.Automatic
运行样例代码时,方块不会原地冻结。
不提供:
- 解释为什么QtQuick的拖放功能以这种方式工作,或者它是否甚至是开发者的预期行为。当前的文档似乎模棱两可。
刚刚遇到这个我自己(使用Qt 5.2,但同样的问题存在那里)。我在x轴上有一个"滑动框",我只是想知道拖动何时完成……而不是对每一个位置的变化都做出反应。我的解决方法涉及破解状态/转换,使用ScriptAction
来提供逻辑。这是模拟对"onDragFinished"信号响应的简化版本。因此,虽然它没有涵盖所有的拖放信号,但它可能会为您指出正确的方向。
Rectangle {
id: sliderControl
height: coordinates.height
width: 80
color: "#F78181"
border.color: "#FE2E2E"
border.width: 1
opacity: 0.4
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: sliderControl
drag.axis: Drag.XAxis
drag.minimumX: 0
drag.maximumX: view.width - sliderControl.width
hoverEnabled: true
}
states: [
State {
name: "dragging"
when: mouseArea.drag.active
},
State {
name: "finished_dragging"
when: !mouseArea.drag.active
}
]
transitions: [
Transition {
from: "dragging"
to: "finished_dragging"
ScriptAction {
script: console.log("finished dragging script");
}
}
]
}
ps -我知道这样的"变通方法"不符合赏金参数,但当我在这个问题上寻求帮助时,我很沮丧地只找到你的问题(没有解决方案)。希望在这条路上遇到的其他人会发现这很有用。不幸的是,我也不知道QML的Drag.dragType
发生了什么。