![]() |
![]() |
很重要--轉載聲明
- 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
- 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。
最近在搞視圖項的拖拽,也上網查了一些資料,好多的文檔都是同樣的,只是被不通的網站所收錄了(也有多是被爬過去的,不明因此),不過也有一些文檔寫的不錯,不過就是太簡易,都是點睛之筆,總之功能仍是勉強能夠實現,加之比較零散,恰好我本身也由於這個需求寫了一個demo,所以我就把本身寫這個demo的過程分析給你們,但願能幫到有這個需求的小夥伴。html
如圖1是demo的效果展現,比較醜,若是加上優秀的qss,那必然能讓人眼前一亮。函數
圖1 ListWidget拖拽post
一、首先來看幾個關鍵的類
MimeData:存儲拖拽時數據
ListItem:item項定製,展現自定義結構
DragList:視圖窗口
二、下面就直接上代碼,步驟對應第三小節的思路網站
a、記錄鼠標按下時信息this
1 void DragList::mousePressEvent(QMouseEvent *event) 2 { 3 if (event->button() == Qt::LeftButton) 4 { 5 startPos = event->pos(); 6 dragItem = itemAt(event->pos()); 7 } 8 QListWidget::mousePressEvent(event); 9 }
b、鼠標移動時啓動QDrag,鼠標移動事件此後進入drag相關函數,直到dropEvent函數被調用url
1 void DragList::mouseMoveEvent(QMouseEvent * event) 2 { 3 QListWidgetItem * item = itemAt(event->pos()); 4 if (dragItem == nullptr) 5 { 6 return; 7 } 8 9 m_Drag = new QDrag(this); 10 11 ListItem * itemWidget = nullptr; 12 if (itemWidget = ItemWidget(dragItem)) 13 { 14 MimeData * mimeData = new MimeData(itemWidget->GetData()); 15 m_Drag->setMimeData(mimeData); 16 } 17 18 m_Drag->setDragCursor(style()->standardPixmap(QStyle::SP_TitleBarMinButton), Qt::LinkAction); 19 m_Drag->setDragCursor(style()->standardPixmap(QStyle::SP_TitleBarMaxButton), Qt::MoveAction); 20 21 m_Drag->setHotSpot(QPoint(0, -m_Drag->pixmap().height() * 2)); 22 Qt::DropAction dropAction = m_Drag->exec(Qt::MoveAction | Qt::LinkAction, Qt::LinkAction); 23 if (dropAction == Qt::MoveAction) 24 { 25 if (itemWidget) 26 { 27 itemWidget->deleteLater(); 28 } 29 delete dragItem;//刪除原有的item,在dropEvent(QDropEvent *event)函數中插入item 30 } 31 32 QListWidget::mouseMoveEvent(event); 33 }
c、鼠標拖拽時移動spa
1 void DragList::dragMoveEvent(QDragMoveEvent * event) 2 { 3 DragList * source = (DragList *)((void *)(event->source())); 4 if (source && source == this) 5 { 6 QListWidgetItem * item = itemAt(event->pos()); 7 if (dragItem != nullptr && item != nullptr && m_Drag != nullptr) 8 { 9 if ((dragItem == item) != m_IsSelf) 10 { 11 m_IsSelf = dragItem == item; 12 13 if (m_IsSelf) 14 { 15 event->setDropAction(Qt::LinkAction); 16 } 17 else 18 { 19 event->setDropAction(Qt::MoveAction); 20 } 21 } 22 } 23 24 if (m_ShotPicture == nullptr) 25 { 26 InitShotLabel(); 27 } 28 29 if (ListItem * newWidget = ItemWidget(dragItem)) 30 { 31 m_ShotPicture->move(mapToGlobal(event->pos() - newWidget->mapFromParent(startPos))); 32 } 33 34 event->accept(); 35 } 36 }
d、鼠標釋放時處理拖拽結果.net
1 void DragList::dropEvent(QDropEvent * event) 2 { 3 if (m_ShotPicture) 4 { 5 m_ShotPicture->close(); 6 m_ShotPicture->deleteLater(); 7 m_ShotPicture = nullptr; 8 } 9 DragList * source = (DragList *)((void *)(event->source())); 10 if (source && source == this) 11 { 12 endPos = event->pos();//獲得鼠標移動到的座標 13 QListWidgetItem * itemRow = itemAt(endPos); //經過endPos獲取鼠標位置所在的行 14 if (itemRow == dragItem) 15 { 16 event->setDropAction(Qt::LinkAction); 17 } 18 else 19 { 20 int insertPos = row(itemRow); 21 if (ListItem * oldWidget = ItemWidget(itemRow)) 22 { 23 QPoint pos = oldWidget->mapFromParent(endPos); 24 if (oldWidget->size().height() / 2 < pos.y()) 25 { 26 insertPos += 1; 27 } 28 } 29 30 if (const MimeData * mimeData = dynamic_cast<const MimeData *>(event->mimeData())) 31 { 32 QListWidgetItem * newItem = new QListWidgetItem; 33 ListItem * itemWidget = new ListItem; 34 ItemData data = mimeData->GetData(); 35 itemWidget->SetData(data); 36 37 insertItem(insertPos, newItem); 38 setItemWidget(newItem, itemWidget); 39 } 40 event->setDropAction(Qt::MoveAction); 41 } 42 43 m_IsSelf = false; 44 event->accept(); 45 } 46 }
e、初始化跟隨鼠標移動的label,並把當前拖拽的窗口截圖設置給label3d
1 void DragList::InitShotLabel() 2 { 3 m_ShotPicture = new QLabel; 4 m_ShotPicture->setWindowOpacity(0.5); 5 m_ShotPicture->setWindowFlags(Qt::Popup); 6 m_ShotPicture->setAttribute(Qt::WA_TransparentForMouseEvents, true); 7 8 SetWindowLong((HWND)m_ShotPicture->winId(), GWL_EXSTYLE, GetWindowLong((HWND)m_ShotPicture->winId(), GWL_EXSTYLE) | 9 WS_EX_TRANSPARENT//忽略一切消息(WM_PAINT除外) 10 | WS_EX_LAYERED); 11 12 if (ListItem * oldWidget = ItemWidget(dragItem)) 13 { 14 m_ShotPicture->resize(oldWidget->size()); 15 m_ShotPicture->setPixmap(oldWidget->grab()); 16 } 17 m_ShotPicture->show(); 18 }
自定義拖放數據:這篇文章是講述怎麼自定義QMimeData數據的,我使用的是其中第二個方法。