一、效果展示
客户端程序拖拽是一个很常见的需求,对于QWidget程序来说,需要重写如图1这么几个方法,通过重写这几个方法的逻辑,我们就可以控制鼠标拖拽的逻辑,糟糕的是QDrag执行exec后是一个阻塞主事件循环的操作,这个时候除了拖拽界面外,其他界面不能响应鼠标事件。作者之前就有过这么一个需要主界面响应的需求,当时我是重写了如图2所示的接口,来模拟程序拖拽。
图1 QWidget拖拽接口
图2 QWidget鼠标事件
如图3所示是示例拖拽展示,界面上有3个大的EditText,相互之间可以进行拖拽,将文本移动到新的EditText。
图3 示例拖拽
二、源码分析
这个示例代码只有2个qml文件,一个是自定义的组件DragAndDropTextItem,另一个是主界面布局。
1、自定义组件DragAndDropTextItem
自定义组件DragAndDropTextItem根节点是Rectangle,支持鼠标事件,MouseArea捕获整个根节点的是标事件,并设置拖拽对象为draggable组件。DraopArea区域有许多槽函数,这些槽函数会自动被调用,比如onEntered,当鼠标进行的时候被调用,onExited当鼠标离开时被调用,具体代码如下
1 import QtQuick 2.2 2 3 Rectangle { 4 id: item 5 property string display//导出属性 6 color: "#EEE"//自定义矩形背景色 7 Text { 8 anchors.fill: parent 9 text: item.display//文本显示绑定导出属性(文本字符串) 10 wrapMode: Text.WordWrap//文本按字折行 11 } 12 DropArea {//拖拽区域 13 anchors.fill: parent 14 keys: ["text/plain"]//该字段对应draggable中mimeData 15 onEntered: { 16 item.color = "#FCC" 17 } 18 onExited: { 19 item.color = "#EEE"//鼠标拖拽退出时恢复常规背景色 20 } 21 onDropped: {//鼠标拖拽完成 释放时触发 22 item.color = "#EEE" 23 if (drop.hasText) {//拖拽含有文本字符串 24 if (drop.proposedAction == Qt.MoveAction || drop.proposedAction == Qt.CopyAction) { 25 item.display = drop.text//重置当前显示文本 26 drop.acceptProposedAction()//接受目标动作,停止事件传递 27 } 28 } 29 } 30 } 31 //鼠标事件区域,覆盖整个矩形 32 MouseArea { 33 id: mouseArea 34 anchors.fill: parent 35 drag.target: draggable//拖拽目标指定 36 } 37 Item { 38 id: draggable// 39 anchors.fill: parent 40 Drag.active: mouseArea.drag.active 41 Drag.hotSpot.x: 10//热点位置 42 Drag.hotSpot.y: 10 43 Drag.mimeData: { "text/plain": item.display }//设置拖拽时内部数据 44 Drag.dragType: Drag.Automatic//拖拽类型 45 Drag.onDragStarted: {//拖拽开始 46 } 47 Drag.onDragFinished: {//拖拽结束 拖拽操作状态为接受 48 if (dropAction == Qt.MoveAction) {//如果是移动操作,将显示置空 49 item.display = ""//清空被拖拽文本框 50 } 51 } 52 } // Item 53 }
2、主界面布局
主界面使用了列布局器ColumnLayout,第一行是一个Text文本,显示该应用程序的基本描述信息,接下来3行是3个自定义控件DragAndDropTextItem,代码如下
1 import QtQuick 2.2 2 import QtQuick.Layouts 1.0 3 4 Item { 5 id: root//作用域内 唯一标示 6 width: 320 7 height: 480 8 9 ColumnLayout {//列布局器,类似于GridLayout 但是只有一列 10 11 anchors.fill: parent 12 anchors.margins: 8 13 14 Text {//第一行显示一串文本 15 Layout.fillWidth: true 16 text: "Drag text into, out of, and between the boxes below." 17 wrapMode: Text.WordWrap 18 } 19 20 //支持拖拽自定义控件 21 DragAndDropTextItem { 22 Layout.fillWidth: true 23 height: 142 24 display: "Sample Text" 25 } 26 27 //支持拖拽自定义控件 28 DragAndDropTextItem { 29 Layout.fillWidth: true 30 height: 142 31 display: "Option/ctrl drag to copy instead of move text." 32 } 33 34 //支持拖拽自定义控件 35 DragAndDropTextItem { 36 Layout.fillWidth: true 37 height: 142 38 display: "Drag out into other applications." 39 } 40 } 41 }