![]() |
![]() |
很重要--转载声明
- 本站文章无特别说明,皆为原创,版权全部,转载时请用连接的方式,给出原文出处。同时写上原做者:朝十晚八 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数据的,我使用的是其中第二个方法。