当前位置: 首页 > news >正文

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选择无焦点

转载于:https://www.cnblogs.com/swarmbees/p/6055280.html

相关文章:

  • mysql中使用 where 1=1和 0=1 的作用
  • 括号
  • ssh远程登录讲解
  • Linux系统备份与恢复
  • libcurl
  • Eureka的故事,专注能让你看到别人看不到的事情
  • 锤子科技官方首页的特效
  • 知识获取、管理与知识体系的完善
  • Web Storage相关
  • CSS的垂直居中和水平居中总结
  • Android 复制文本内容到系统剪贴板的最简单实践
  • 9种用户体验设计的状态是必须知道的(二)
  • 用ASCII码显示string.xml中的特殊字符
  • 11.2.0.3 hosts里边的scanip信息删除与否对数据库是否重启探索
  • SpringBoot揭秘:快速构建微服务体系
  • JavaScript-如何实现克隆(clone)函数
  • 【面试系列】之二:关于js原型
  • CentOS7简单部署NFS
  • CSS 提示工具(Tooltip)
  • CSS魔法堂:Absolute Positioning就这个样
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • Java 最常见的 200+ 面试题:面试必备
  • Objective-C 中关联引用的概念
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • pdf文件如何在线转换为jpg图片
  • php中curl和soap方式请求服务超时问题
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 开源SQL-on-Hadoop系统一览
  • 入门级的git使用指北
  • 算法之不定期更新(一)(2018-04-12)
  • 微信小程序填坑清单
  • 用Canvas画一棵二叉树
  • 由插件封装引出的一丢丢思考
  • 主流的CSS水平和垂直居中技术大全
  • - 转 Ext2.0 form使用实例
  • Android开发者必备:推荐一款助力开发的开源APP
  • ​ssh免密码登录设置及问题总结
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • #includecmath
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (06)金属布线——为半导体注入生命的连接
  • (1)(1.9) MSP (version 4.2)
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (七)c52学习之旅-中断
  • (三十五)大数据实战——Superset可视化平台搭建
  • (未解决)macOS matplotlib 中文是方框
  • (新)网络工程师考点串讲与真题详解
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转载)Linux 多线程条件变量同步
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • .bashrc在哪里,alias妙用
  • .net程序集学习心得
  • @test注解_Spring 自定义注解你了解过吗?
  • []C/C++读取串口接收到的数据程序