Qt之QAbstractItemView视图项拖拽(二)
一、需求说明
上一篇文章Qt之QAbstractItemView视图项拖拽(一)讲述了实现QAbstractItemView视图项拖拽的一种方式,是基于QDrag实现的,这个类是qt自己封装好了的,所以可定制性也就没有了那么强,最明显的是,这个类在执行exec方法后,mouse系列的回调接口就被阻塞了,随之而来的问题就是拖拽时item项没有了hover特性,为了解决这个问题,我们就不能使用QDrag类来实现拖拽了,这也是这篇文章我要讲述的内容。
二、效果展示
如图1是demo的效果展示,比较丑,如果加上优秀的qss,那必然能让人眼前一亮

图1 ListWidget拖拽
三、实现思路
- 继承QListWidget类,重写其鼠标多拽时几个虚方法,分别是mousePressEvent(鼠标按下),mouseMoveEvent(鼠标移动),mouseReleaseEvent(鼠标弹起)等,当然还包括一些辅助的回调方法enterEvent和leaveEvent。
- 鼠标按下时,记录鼠标按下位置和鼠标点击项
- 鼠标移动时移动插入项标示和item项快照位置,并修改鼠标形状
- 最后鼠标释放时,判断如果需要更新拖拽项位置,那么把原有项删除,并构造新的项插入到目标位置
上边的几个步骤描述都是在mouse系列的回到接口中发生的,再也没有QDrag的事儿啦。当然这个mouse方法中需要做一些鼠标状态维护等。
四、代码说明
1、重要的类和上一篇文章中的一样,忘记的小伙伴可以到上一篇文章查看,或者猛戳Qt之QAbstractItemView视图项拖拽(一)
2、下面就直接上代码
a、记录鼠标按下时信息
void DragList::mousePressEvent(QMouseEvent * event)
{
if (event->button() == Qt::LeftButton)
{
m_LeftPress = true;
startPos = event->pos();
dragItem = itemAt(event->pos());
} QListWidget::mousePressEvent(event);
}
b、鼠标移动时维护鼠标状态、快照位置和插入表示位置
void DragList::mouseMoveEvent(QMouseEvent * event)
{
QListWidgetItem * item = itemAt(event->pos());
if (dragItem == nullptr)
{
dragItem = itemAt(event->pos());
} if (m_ShotPicture == nullptr)
{
InitShotLabel();
}
if (m_ShotLine == nullptr)
{
InitShotLine();
} QRect rect = visualItemRect(dragItem);
if (ListItem * hoverWidget = ItemWidget(item))
{
QRect hoverRect = visualItemRect(item);
QPoint pos = hoverWidget->mapFromParent(event->pos());
if (hoverRect.size().height() / < pos.y())
{
m_ShotLine->move(mapToGlobal(QPoint(, hoverRect.y() + hoverRect.height() + )));
}
else
{
m_ShotLine->move(mapToGlobal(QPoint(, hoverRect.y() + )));
} m_ShotLine->setVisible(hoverRect.contains(event->pos()));
} if (ListItem * newWidget = ItemWidget(dragItem))
{
m_ShotPicture->move(mapToGlobal(event->pos() - newWidget->mapFromParent(startPos)));
if (rect.contains(event->pos()) || event->pos().isNull())
{
setCursor(Qt::ForbiddenCursor);
}
else
{
setCursor(Qt::ArrowCursor);
}
if (m_ShotPicture->isHidden())
{
m_ShotPicture->show();
}
} // QListWidget::mouseMoveEvent(event);
}
c、鼠标释放时处理拖拽结果
void DragList::mouseReleaseEvent(QMouseEvent * event)
{
if (event->button() == Qt::LeftButton)
{
m_LeftPress = false;
if (m_ShotPicture)
{
m_ShotPicture->close();
m_ShotPicture->deleteLater();
m_ShotPicture = nullptr;
}
if (m_ShotLine)
{
m_ShotLine->close();
m_ShotLine->deleteLater();
m_ShotLine = nullptr;
}
MouseRelease(event);
} setCursor(Qt::ArrowCursor); QListWidget::mouseReleaseEvent(event);
}
d、初始化跟随鼠标移动的快照,并把当前拖拽的窗口截图设置给快照
void DragList::InitShotLabel()
{
m_ShotPicture = new QLabel;
m_ShotPicture->setWindowOpacity(0.95);
m_ShotPicture->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
m_ShotPicture->setAttribute(Qt::WA_TransparentForMouseEvents, true); if (ListItem * oldWidget = ItemWidget(dragItem))
{
m_ShotPicture->setPixmap(oldWidget->grab());
m_ShotPicture->resize(visualItemRect(dragItem).size());
}
m_ShotPicture->show();
}
e、初始化鼠标插入位置标示
void DragList::InitShotLine()
{
m_ShotLine = new QLabel;
m_ShotLine->setObjectName(QStringLiteral("ShotLine"));
m_ShotLine->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
m_ShotLine->setAttribute(Qt::WA_TransparentForMouseEvents, true);
m_ShotLine->setStyleSheet("QLabel#ShotLine{background:green;}");//用图片代替 if (ListItem * oldWidget = ItemWidget(dragItem))
{
// m_ShotLine->setPixmap(oldWidget->grab());
m_ShotLine->resize(visualItemRect(dragItem).size().width(), );
}
m_ShotLine->show();
}
f、鼠标弹起具体处理函数
void DragList::MouseRelease(QMouseEvent * event)
{
QListWidgetItem * item = itemAt(event->pos());
if (item == nullptr || item == dragItem)
{
return;
} int insertPos = row(item);
if (ListItem * oldWidget = ItemWidget(item))
{
QPoint pos = oldWidget->mapFromParent(event->pos());
if (oldWidget->size().height() / < pos.y())
{
insertPos += ;
}
} if (dragItem)
{
if (ListItem * oldWidget = ItemWidget(dragItem))
{
QListWidgetItem * newItem = new QListWidgetItem;
ListItem * itemWidget = new ListItem;
itemWidget->SetData(oldWidget->GetData()); insertItem(insertPos, newItem);
setItemWidget(newItem, itemWidget); setCurrentItem(newItem); oldWidget->deleteLater();
} dragItem = takeItem(row(dragItem));
if (dragItem)
{
delete dragItem;
dragItem = nullptr;
}
}
}
五、下载链接
六、相关文章
自定义拖放数据:这篇文章是讲述怎么自定义QMimeData数据的,我使用的是其中第二个方法。
![]() |
![]() |
很重要--转载声明
- 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
- 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。
Qt之QAbstractItemView视图项拖拽(二)的更多相关文章
- Qt之QAbstractItemView视图项拖拽(一)
一.需求说明 最近在搞视图项的拖拽,也上网查了一些资料,好多的文档都是一样的,只是被不通的网站所收录了(也有可能是被爬过去的,不明所以),不过也有一些文档写的不错,不过就是太简易,都是点睛之笔,总之功 ...
- Qt图形视图体系结构示例解析(视图、拖拽、动画)
本博的示例来自与QT Example:C:\Qt\Qt5.9.3\Examples\Qt-5.9.3\widgets\graphicsview\dragdroprobot 将通过分析示例完成主要功能: ...
- QT笔记之自定义窗口拖拽移动
1.QT自定义标题栏,拖拽标题栏移动窗口(只能拖拽标题,其他位置无法拖拽) 方法一: 转载:http://blog.sina.com.cn/s/blog_4ba5b45e0102e83h.html . ...
- Qt实现不同Treewidget之间拖拽
拖拽是编程中经常要用到的,我这里主要是实习了Treewidget之间直接拖拽Item,按下Ctrl键的话是copy,不按Ctrl则是Move.以下是实现代码 class TreeItemMimeDat ...
- Qt窗口添加鼠标移动拖拽事件
1. .h文件中添加 private: QPoint dragPosition; 2. 在cpp文件中重写鼠标点击和拖拽函数 void ShapeWidget::mousePressEvent( ...
- ztree插件的使用及列表项拖拽的实现(jQuery)+异步加载节点数据
为了实现如图所示的树状结构图,并使列表项可拖动到盒子里,研究了ztree这个插件的使用,并仔细研究了列表项的拖动事件.完成了预期需求,对jQuery的运用得到了提高.这个插件的功能非常强大,除了基本的 ...
- win32 sdk树形控件的项拖拽实现
本课中,我们将学习如何使用树型视图控件.另外还要学习如何在树型视图中完成拖-拉动作,以及如何使用图象列表. 理论: 树型视图是一种特别的窗口,我们可以使用它一目了然地表示某种层次关系.譬如象在资源管理 ...
- qt 拖拽 修改大小(二)
最近项目需要实现windows下橡皮筋的效果,所以对此做了一些了解,特此记录. 首先windows系统是支持橡皮筋效果的,需要使用win32方 法:SystemParametersInfo(SPI_S ...
- Qt之QAbstractItemView右键菜单
一.功能概述 说起右键菜单,之前Qt之自定义QLineEdit右键菜单这篇文章中我已经讲述过3种右键菜单的实现方式,今儿也是在啰嗦一下,针对QListWidget类在定制一下右键菜单,我使用的具体方式 ...
随机推荐
- 防止ViewPager中的Fragment被销毁的方法,更加流畅
在使用ViewPager与Fragment的时候,ViewPager会自动缓存1页内的数据,如下图: 当我们当前处在页面2的时候,页面1和页面3的View实际上已经创建好了,所以在我们拖动的时候是可以 ...
- 为什么你还在用嵌入式的方式来使用mod_wsgi?
可能你还不知道你的python 网站是否跑在embedded mod of mod_wsgi,不管你知不知道请看下去,因为大部分人都是在这个工作模式下运行的.嵌入式顾名思义就是运行在apache的子 ...
- mybatis oracle java.sql.SQLException: 流已被关闭问题
/** * 按照页码取值(从current_page页开始,每页page_size条) * @param key * @param params * @param current_page * @pa ...
- 使用 Python SimpleHTTPServer 快速共享文件
近期,想着从一个服务器 向另一个服务器传输文件,但是对其知之甚少,就从别人那里知道一种方法,使用 Python SimpleHTTPServer 快速共享文件. 直接运行:python -m Simp ...
- android开发常见编程错误总结
1.设置TextView的文本颜色 1 2 3 TextView tv; ... tv.setTextColor(R.color.white); 其实这样设置的颜色是 R.color.white的资源 ...
- 【Linux】——ctags
ctags的功能:扫描指定的源文件,找出其中所包含的语法元素,并将找到的相关内容记录下来. ctags 可以在官网上下载源代码,然后编译安装.最后在 ~/.vimrc 文件中写入以下配置: " ...
- PHP中ob系列函数整理
ob,输出缓冲区,是output buffering的简称,而不是output cache.ob用对了,是能对速度有一定的帮助,但是盲目的加上ob函数,只会增加CPU额外的负担. 下面我说说ob的基本 ...
- 优先队列求解Huffman编码 c++
优先队列小析 优先队列的模板: template <class T, class Container = vector<T>,class Compare = less< ...
- 通过PowerShell获取域名whois信息
Whois 简单来说,就是一个用来查询域名是否已经被注册,以及注册域名的详细信息的数据库(如域名所有人.域名注册商.域名注册日期和过期日期等).通过域名Whois服务器查询,可以查询域名归属者联系方式 ...
- Spring进阶教程之在ApplicationContext初始化完成后重定义Bean
前言 很久没有写博客了,也是两个原因:一是自己觉得一直在班门弄斧,其实自己没什么技术可言:二是很多朋友的问题实际上可以自行解决,我经常觉得不该我来过问,或者是有时候我认为技术还得靠自己钻研,我一两句话 ...

