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类在定制一下右键菜单,我使用的具体方式 ...
随机推荐
- android 透明度颜色值
100% — FF99% — FC98% — FA97% — F796% — F595% — F294% — F093% — ED92% — EB91% — E890% — E689% — E388% ...
- asp.net 多个文件同时下载
1.首先读取文件夹下的文件,可能同时存在多个文件 2.选中文件,然后点击下载,同时可以选择多个文件. 思路:通过生产压缩包的形式进行下载,然后再清楚压缩包,这样用户可以一次性全部下载下来. 一.获取目 ...
- std::bind和std::function
std::bind 用于绑定一个函数,返回另外一种调用方式的函数对象 ,可以改变参数顺序 和个数,特别是在多线程的程序中,经常用它将函数进行包装,然后打包发送给工作线程,让工作线程去执行我们的任务. ...
- web项目中加入struts2、spring的支持,并整合两者
Web项目中加入struts2 的支持 在lib下加入strut2的jar包 2. 在web.xml中添加配置 <filter> <filter-name>struts2< ...
- 将树苺派升级到Raspbian 8 (Jessie)
我的树苺派2B跑的是Raspbian 7 (Wheezy),有不少软件都让我觉察出老旧来.想着Debian官方已经发布Debian 8 (Jessie)大半年了(8.0发布于2015/04/25),树 ...
- CGI、FastCGI 知识总结
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- 点击短信中的url打开某个应用
实现功能: 短信内容中含有url(例如,http://youngo.com/app/),点击后打开apk 遗留问题: 点击url后,会出现选择框,让用户选择是用浏览器打开还是用该apk打开----没有 ...
- IBM HTTP Server Performance Tuning
IBM HTTP Server Performance Tuninghttp://publib.boulder.ibm.com/httpserv/ihsdiag/ihs_performance.htm ...
- Android数据缓存
1.http://blog.csdn.net/lnb333666/article/details/8460159 2.https://github.com/Trinea/android-common ...
- 即将放出ITSEC第一期所有培训视频
课程大概被分为三个章节 客户端安全培训 安全工具培训 服务端安全培训 部分PPT 详细课程表 FireBug代码调试工具使用:工具介绍 FireBu ...

