一、需求说明

上一篇文章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、记录鼠标按下时信息

 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;
}
}
}

五、下载链接 

    Qt之QAbstractItemView视图项拖拽2

六、相关文章

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

  Qt之QAbstractItemView视图项拖拽(一)

  Qt之QAbstractItemView选择无焦点

如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!! 

 

很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。

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

  1. Qt之QAbstractItemView视图项拖拽(一)

    一.需求说明 最近在搞视图项的拖拽,也上网查了一些资料,好多的文档都是一样的,只是被不通的网站所收录了(也有可能是被爬过去的,不明所以),不过也有一些文档写的不错,不过就是太简易,都是点睛之笔,总之功 ...

  2. Qt图形视图体系结构示例解析(视图、拖拽、动画)

    本博的示例来自与QT Example:C:\Qt\Qt5.9.3\Examples\Qt-5.9.3\widgets\graphicsview\dragdroprobot 将通过分析示例完成主要功能: ...

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

    1.QT自定义标题栏,拖拽标题栏移动窗口(只能拖拽标题,其他位置无法拖拽) 方法一: 转载:http://blog.sina.com.cn/s/blog_4ba5b45e0102e83h.html . ...

  4. Qt实现不同Treewidget之间拖拽

    拖拽是编程中经常要用到的,我这里主要是实习了Treewidget之间直接拖拽Item,按下Ctrl键的话是copy,不按Ctrl则是Move.以下是实现代码 class TreeItemMimeDat ...

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

    1. .h文件中添加 private:    QPoint dragPosition; 2. 在cpp文件中重写鼠标点击和拖拽函数 void ShapeWidget::mousePressEvent( ...

  6. ztree插件的使用及列表项拖拽的实现(jQuery)+异步加载节点数据

    为了实现如图所示的树状结构图,并使列表项可拖动到盒子里,研究了ztree这个插件的使用,并仔细研究了列表项的拖动事件.完成了预期需求,对jQuery的运用得到了提高.这个插件的功能非常强大,除了基本的 ...

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

    本课中,我们将学习如何使用树型视图控件.另外还要学习如何在树型视图中完成拖-拉动作,以及如何使用图象列表. 理论: 树型视图是一种特别的窗口,我们可以使用它一目了然地表示某种层次关系.譬如象在资源管理 ...

  8. qt 拖拽 修改大小(二)

    最近项目需要实现windows下橡皮筋的效果,所以对此做了一些了解,特此记录. 首先windows系统是支持橡皮筋效果的,需要使用win32方 法:SystemParametersInfo(SPI_S ...

  9. Qt之QAbstractItemView右键菜单

    一.功能概述 说起右键菜单,之前Qt之自定义QLineEdit右键菜单这篇文章中我已经讲述过3种右键菜单的实现方式,今儿也是在啰嗦一下,针对QListWidget类在定制一下右键菜单,我使用的具体方式 ...

随机推荐

  1. java文件同步性能测试

    2003同步速度

  2. Android文本输入框(EditText)切换密码的显示与隐藏

    package cc.c; import android.app.Activity; import android.os.Bundle; import android.text.Selection; ...

  3. 2014 Hangjs 见闻流水账第二天

    前言 第一天传送门: 2014 Hangjs 见闻流水账第一天 写作风格跟第一天还是一样的. Slide 每个slide我都会根据自己的理解重新命名一次,用于表达自己的第一看法,主观意见,不喜可吐槽, ...

  4. nginx做反向代理负载均衡 Java怎么获取后端服务器获取用户IP

    nginx做反向负载均衡,后端服务器获取真实客户端ip   首先,在前端nginx上需要做如下配置: location / proxy_set_hearder host                 ...

  5. WPF Window 服务安装

    一.安装服务 1.已管理员的身份启动CMD 2.输入 cd C:\Windows\Microsoft.NET\Framework\v4.0.30319 回车 3.输入 InstallUtil.exe ...

  6. 菜鸟教程之工具使用(十)——用BlazeMeter录制JMeter测试脚本

    工具: 1,JMeter 2,Chrome 3,BlazeMeter 4,SwitchyOmega(如果需要代理) 步骤: 以上工具准备好以后就可以录制JMeter的测试脚本了, 在Chrome中点击 ...

  7. Top 10 Universities for Artificial Intelligence

    1. Massachusetts Institute of Technology, Cambridge, MA Massachusetts Institute of Technology is a p ...

  8. How to get the Current Controller Name, Action, or ID in ASP.NET MVC

    public static class HtmlRequestHelper { public static string Id(this HtmlHelper htmlHelper) { var ro ...

  9. LNMP软件安装所在的目录详细

    LNMP相关软件安装目录Nginx 目录: /usr/local/nginx/MySQL 目录 : /usr/local/mysql/MySQL数据库所在目录:/usr/local/mysql/var ...

  10. CentOS下Red5安装

    Red5介绍 Red5是一个采用Java开发开源的Flash流媒体服务器.它支持:把音频(MP3)和视频(FLV)转换成播放流: 录制客户端播放流(只支持FLV):共享对象:现场直播流发布:远程调用. ...