一、效果展示
客戶端程序拖拽是一個很常見的需求,對於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 }