Qt之QAbstractItemView视图项拖拽(二)

一、需求说明

上一篇文章Qt之QAbstractItemView视图项拖拽(一)讲述了实现QAbstractItemView视图项拖拽的一种方式,是基于QDrag实现的,这个类是qt自己封装好了的,所以可定制性也就没有了那么强,最明显的是,这个类在执行exec方法后,mouse系列的回调接口就被阻塞了,随之而来的问题就是拖拽时item项没有了hover特性,为了解决这个问题,我们就不能使用QDrag类来实现拖拽了,这也是这篇文章我要讲述的内容。

二、效果展示

如图1是demo的效果展示,比较丑,如果加上优秀的qss,那必然能让人眼前一亮

图1 ListWidget拖拽

三、实现思路

  1. 继承QListWidget类,重写其鼠标多拽时几个虚方法,分别是mousePressEvent(鼠标按下),mouseMoveEvent(鼠标移动),mouseReleaseEvent(鼠标弹起)等,当然还包括一些辅助的回调方法enterEvent和leaveEvent。
  2. 鼠标按下时,记录鼠标按下位置和鼠标点击项
  3. 鼠标移动时移动插入项标示和item项快照位置,并修改鼠标形状
  4. 最后鼠标释放时,判断如果需要更新拖拽项位置,那么把原有项删除,并构造新的项插入到目标位置

上边的几个步骤描述都是在mouse系列的回到接口中发生的,再也没有QDrag的事儿啦。当然这个mouse方法中需要做一些鼠标状态维护等。

四、代码说明

1、重要的类和上一篇文章中的一样,忘记的小伙伴可以到上一篇文章查看,或者猛戳Qt之QAbstractItemView视图项拖拽(一)
    2、下面就直接上代码
    a、记录鼠标按下时信息

 1 void DragList::mousePressEvent(QMouseEvent * event)
 2 {
 3     if (event->button() == Qt::LeftButton)
 4     {
 5         m_LeftPress = true;
 6         startPos = event->pos();
 7         dragItem = itemAt(event->pos());
 8     }
 9
10     QListWidget::mousePressEvent(event);
11 }

b、鼠标移动时维护鼠标状态、快照位置和插入表示位置

 1 void DragList::mouseMoveEvent(QMouseEvent * event)
 2 {
 3     QListWidgetItem * item = itemAt(event->pos());
 4     if (dragItem == nullptr)
 5     {
 6         dragItem = itemAt(event->pos());
 7     }
 8
 9     if (m_ShotPicture == nullptr)
10     {
11         InitShotLabel();
12     }
13     if (m_ShotLine == nullptr)
14     {
15         InitShotLine();
16     }
17
18     QRect rect = visualItemRect(dragItem);
19     if (ListItem * hoverWidget = ItemWidget(item))
20     {
21         QRect hoverRect = visualItemRect(item);
22         QPoint pos = hoverWidget->mapFromParent(event->pos());
23         if (hoverRect.size().height() / 2 < pos.y())
24         {
25             m_ShotLine->move(mapToGlobal(QPoint(2, hoverRect.y() + hoverRect.height() + 1)));
26         }
27         else
28         {
29             m_ShotLine->move(mapToGlobal(QPoint(2, hoverRect.y() + 1)));
30         }
31
32         m_ShotLine->setVisible(hoverRect.contains(event->pos()));
33     }
34
35     if (ListItem * newWidget = ItemWidget(dragItem))
36     {
37         m_ShotPicture->move(mapToGlobal(event->pos() - newWidget->mapFromParent(startPos)));
38         if (rect.contains(event->pos()) || event->pos().isNull())
39         {
40             setCursor(Qt::ForbiddenCursor);
41         }
42         else
43         {
44             setCursor(Qt::ArrowCursor);
45         }
46         if (m_ShotPicture->isHidden())
47         {
48             m_ShotPicture->show();
49         }
50     }
51
52
53 //    QListWidget::mouseMoveEvent(event);
54 }

c、鼠标释放时处理拖拽结果

 1 void DragList::mouseReleaseEvent(QMouseEvent * event)
 2 {
 3     if (event->button() == Qt::LeftButton)
 4     {
 5         m_LeftPress = false;
 6         if (m_ShotPicture)
 7         {
 8             m_ShotPicture->close();
 9             m_ShotPicture->deleteLater();
10             m_ShotPicture = nullptr;
11         }
12         if (m_ShotLine)
13         {
14             m_ShotLine->close();
15             m_ShotLine->deleteLater();
16             m_ShotLine = nullptr;
17         }
18         MouseRelease(event);
19     }
20
21     setCursor(Qt::ArrowCursor);
22
23     QListWidget::mouseReleaseEvent(event);
24 }

d、初始化跟随鼠标移动的快照,并把当前拖拽的窗口截图设置给快照

 1 void DragList::InitShotLabel()
 2 {
 3     m_ShotPicture = new QLabel;
 4     m_ShotPicture->setWindowOpacity(0.95);
 5     m_ShotPicture->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
 6     m_ShotPicture->setAttribute(Qt::WA_TransparentForMouseEvents, true);
 7
 8     if (ListItem * oldWidget = ItemWidget(dragItem))
 9     {
10         m_ShotPicture->setPixmap(oldWidget->grab());
11         m_ShotPicture->resize(visualItemRect(dragItem).size());
12     }
13     m_ShotPicture->show();
14 }

e、初始化鼠标插入位置标示

 1 void DragList::InitShotLine()
 2 {
 3     m_ShotLine = new QLabel;
 4     m_ShotLine->setObjectName(QStringLiteral("ShotLine"));
 5     m_ShotLine->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
 6     m_ShotLine->setAttribute(Qt::WA_TransparentForMouseEvents, true);
 7     m_ShotLine->setStyleSheet("QLabel#ShotLine{background:green;}");//用图片代替
 8
 9     if (ListItem * oldWidget = ItemWidget(dragItem))
10     {
11     //    m_ShotLine->setPixmap(oldWidget->grab());
12         m_ShotLine->resize(visualItemRect(dragItem).size().width(), 2);
13     }
14     m_ShotLine->show();
15 }

f、鼠标弹起具体处理函数

 1 void DragList::MouseRelease(QMouseEvent * event)
 2 {
 3     QListWidgetItem * item = itemAt(event->pos());
 4     if (item == nullptr || item == dragItem)
 5     {
 6         return;
 7     }
 8
 9     int insertPos = row(item);
10     if (ListItem * oldWidget = ItemWidget(item))
11     {
12         QPoint pos = oldWidget->mapFromParent(event->pos());
13         if (oldWidget->size().height() / 2 < pos.y())
14         {
15             insertPos += 1;
16         }
17     }
18
19     if (dragItem)
20     {
21         if (ListItem * oldWidget = ItemWidget(dragItem))
22         {
23             QListWidgetItem * newItem = new QListWidgetItem;
24             ListItem * itemWidget = new ListItem;
25             itemWidget->SetData(oldWidget->GetData());
26
27             insertItem(insertPos, newItem);
28             setItemWidget(newItem, itemWidget);
29
30             setCurrentItem(newItem);
31
32             oldWidget->deleteLater();
33         }
34
35         dragItem = takeItem(row(dragItem));
36         if (dragItem)
37         {
38             delete dragItem;
39             dragItem = nullptr;
40         }
41     }
42 }

五、下载链接 

    Qt之QAbstractItemView视图项拖拽2

六、相关文章

  自定义拖放数据:这篇文章是讲述怎么自定义QMimeData数据的,我使用的是其中第二个方法。

  Qt之QAbstractItemView视图项拖拽(一)

  Qt之QAbstractItemView选择无焦点

时间: 2024-11-08 22:25:10

Qt之QAbstractItemView视图项拖拽(二)的相关文章

win32 sdk树形控件的项拖拽实现

本课中,我们将学习如何使用树型视图控件.另外还要学习如何在树型视图中完成拖-拉动作,以及如何使用图象列表. 理论: 树型视图是一种特别的窗口,我们可以使用它一目了然地表示某种层次关系.譬如象在资源管理器中左边窗口中的就是树型视图.您可以调用CreateWindowEx来创建树型视图,传递一个类名""SysTreeView32"",或者您也可以把它放到一个对话框中去.不要忘了在您的代码中加入InitCommonControls函数. 树型视图有几种特有的风格.下面是几

QT笔记之自定义窗口拖拽移动

1.QT自定义标题栏,拖拽标题栏移动窗口(只能拖拽标题,其他位置无法拖拽) 方法一: 转载:http://blog.sina.com.cn/s/blog_4ba5b45e0102e83h.html .h文件中 1 //自己重新实现拖动操作 2 protected: 3 4 void mouseMoveEvent ( QMouseEvent * event ); 5 6 void mousePressEvent ( QMouseEvent * event ); 7 8 void mouseRele

Qt实现不同Treewidget之间拖拽

拖拽是编程中经常要用到的,我这里主要是实习了Treewidget之间直接拖拽Item,按下Ctrl键的话是copy,不按Ctrl则是Move.以下是实现代码 [cpp] view plain copy class TreeItemMimeData:public QMimeData { Q_OBJECT public: TreeItemMimeData():QMimeData() { m_pDragItem = NULL; } ~TreeItemMimeData() { } void SetDra

Qt窗口添加鼠标移动拖拽事件

1. .h文件中添加 private:    QPoint dragPosition; 2. 在cpp文件中重写鼠标点击和拖拽函数 void ShapeWidget::mousePressEvent(QMouseEvent * event){    if (event->button() == Qt::LeftButton) //点击左边鼠标    {         dragPosition = event->globalPos() - frameGeometry().topLeft(); 

Vue的v-for中列表项拖拽排序详细方法

首先:HTML中,关键点是监听拖拽的三个阶段,即:dragstart/dragover/dragend,注意:要拖拽元素必须加上draggable="true" <ul @dragstart="onDragStart" @dragover="onDragOver" @dragend="onDragEnd" ref="taskListUl"> <li v-for="(subTask

js基础拖拽二

var oDiv= document.getElementById("div"); oDiv.onmousedown= function(e){ var _this = this; var e= e || window.event; var diffX= e.clientX - _this.offsetLeft; var diffY= e.clientY - _this.offsetTop; if(_this.setCapture) _this.setCapture(); docume

Qt之QAbstractItemView右键菜单

一.功能概述 说起右键菜单,之前Qt之自定义QLineEdit右键菜单这篇文章中我已经讲述过3种右键菜单的实现方式,今儿也是在啰嗦一下,针对QListWidget类在定制一下右键菜单,我使用的具体方式呢,是直接重写了contextMenuEvent方法,在这个方法中弹出右键菜单. 二.效果展示 如图1是针对QListWidget定制的右键菜单,美观程度一般,但是功能基本实现 图1 QListWidget右键菜单 三.代码讲解 右键菜单在相关文章小节中我已经给出了一些文章,关于右键菜单的弹出逻辑我

WPF中元素拖拽的两个实例

原文:WPF中元素拖拽的两个实例 今天结合之前做过的一些拖拽的例子来对这个方面进行一些总结,这里主要用两个例子来说明在WPF中如何使用拖拽进行操作,元素拖拽是一个常见的操作,第一个拖拽的例子是将ListBox中的子元素拖拽到ListView的某一个节点,从而将该子元素作为当前节点的子节点.第二个例子就是将ListView的某一项拖拽到另外一项上从而使两个子项位置互换,这两个例子的原理类似,实现细节上有所差别,下面就具体分析一下这些细节. DEMO1 一 示例截图 图一 示例一截图 二 重点原理分

dev TreeList拖拽

一.说明 使用dev控件,TreeList1向TreeList2拖拽 二.属性 //允许拖拽            treeList1.AllowDrop = true;            treeList2.AllowDrop = true;            //允许多行选择            treeList1.OptionsSelection.MultiSelect = true; 三.代码 #region tree拖拽操作 TreeListHitInfo downHitIn