Qt之QAbstractItemView視圖項拖拽(一)

1、需求說明   

     最近在搞視圖項的拖拽,也上網查了一些資料,好多的文檔都是同樣的,只是被不通的網站所收錄了(也有多是被爬過去的,不明因此),不過也有一些文檔寫的不錯,不過就是太簡易,都是點睛之筆,總之功能仍是勉強能夠實現,加之比較零散,恰好我本身也由於這個需求寫了一個demo,所以我就把本身寫這個demo的過程分析給你們,但願能幫到有這個需求的小夥伴。html

2、效果展現   

    如圖1是demo的效果展現,比較醜,若是加上優秀的qss,那必然能讓人眼前一亮。函數

圖1 ListWidget拖拽post

3、實現思路

  1. 繼承QListWidget類,重寫其鼠標多拽時幾個虛方法,分別是:dragEnterEvent(鼠標拖拽進入),dragLeaveEvent(鼠標拖拽時離開),dragMoveEvent(拖拽時移動),dropEvent(鼠標釋放),(mousePressEvent)鼠標按下,mouseMoveEvent(鼠標移動)等。
  2. 鼠標按下時,記錄鼠標按下位置和鼠標點擊項    
  3. 鼠標移動時構造一個QDrag對象,而且執行其exec方法,這個方法執行後,直到dropEvent觸發後,mouseMoveEvent方法纔會被再次觸發,不然鼠標移動消息一直派發給dragMouseEvent。exec方法的以後,後續的鼠標事件都會在drag打頭的方法中回調。  
  4. 拖拽期間,鼠標移動,並回調在dragMoveEvent方法中,能夠在這個方法中修改鼠標狀態。維護一些變量,好比效果圖上跟隨鼠標一塊兒移動的一張圖片和綠色的指示插入位置的一條線。
  5. 最後鼠標釋放時,判斷若是須要更新拖拽項位置,那麼把原有項刪除,並構造新的項插入到目標位置。

4、代碼說明

一、首先來看幾個關鍵的類
    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 }

5、下載連接

  Qt之QAbstractItemView視圖項拖拽code

6、相關文章

    自定義拖放數據:這篇文章是講述怎麼自定義QMimeData數據的,我使用的是其中第二個方法。

  Qt之QAbstractItemView選擇無焦點
   

若是您以爲文章不錯,不妨給個 打賞,寫做不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。 

相關文章
相關標籤/搜索