一、需求说明

最近在搞视图项的拖拽,也上网查了一些资料,好多的文档都是一样的,只是被不通的网站所收录了(也有可能是被爬过去的,不明所以),不过也有一些文档写的不错,不过就是太简易,都是点睛之笔,总之功能还是勉强可以实现,加之比较零散,刚好我自己也因为这个需求写了一个demo,因此我就把自己写这个demo的过程分析给大家,希望能帮到有这个需求的小伙伴。

二、效果展示

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

图1 ListWidget拖拽

三、实现思路

  1. 继承QListWidget类,重写其鼠标多拽时几个虚方法,分别是:dragEnterEvent(鼠标拖拽进入),dragLeaveEvent(鼠标拖拽时离开),dragMoveEvent(拖拽时移动),dropEvent(鼠标释放),(mousePressEvent)鼠标按下,mouseMoveEvent(鼠标移动)等。
  2. 鼠标按下时,记录鼠标按下位置和鼠标点击项
  3. 鼠标移动时构造一个QDrag对象,并且执行其exec方法,这个方法执行后,直到dropEvent触发后,mouseMoveEvent方法才会被再次触发,否则鼠标移动消息一直派发给dragMouseEvent。exec方法的之后,后续的鼠标事件都会在drag打头的方法中回调。
  4. 拖拽期间,鼠标移动,并回调在dragMoveEvent方法中,可以在这个方法中修改鼠标状态。维护一些变量,比如效果图上跟随鼠标一起移动的一张图片和绿色的指示插入位置的一条线。
  5. 最后鼠标释放时,判断如果需要更新拖拽项位置,那么把原有项删除,并构造新的项插入到目标位置。

四、代码说明

1、首先来看几个关键的类
    MimeData:存储拖拽时数据
    ListItem:item项定制,展示自定义结构
    DragList:视图窗口
2、下面就直接上代码,步骤对应第三小节的思路

a、记录鼠标按下时信息

 void DragList::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
startPos = event->pos();
dragItem = itemAt(event->pos());
}
QListWidget::mousePressEvent(event);
}

b、鼠标移动时启动QDrag,鼠标移动事件此后进入drag相关函数,直到dropEvent函数被调用

 void DragList::mouseMoveEvent(QMouseEvent * event)
{
QListWidgetItem * item = itemAt(event->pos());
if (dragItem == nullptr)
{
return;
} m_Drag = new QDrag(this); ListItem * itemWidget = nullptr;
if (itemWidget = ItemWidget(dragItem))
{
MimeData * mimeData = new MimeData(itemWidget->GetData());
m_Drag->setMimeData(mimeData);
} m_Drag->setDragCursor(style()->standardPixmap(QStyle::SP_TitleBarMinButton), Qt::LinkAction);
m_Drag->setDragCursor(style()->standardPixmap(QStyle::SP_TitleBarMaxButton), Qt::MoveAction); m_Drag->setHotSpot(QPoint(, -m_Drag->pixmap().height() * ));
Qt::DropAction dropAction = m_Drag->exec(Qt::MoveAction | Qt::LinkAction, Qt::LinkAction);
if (dropAction == Qt::MoveAction)
{
if (itemWidget)
{
itemWidget->deleteLater();
}
delete dragItem;//删除原有的item,在dropEvent(QDropEvent *event)函数中插入item
} QListWidget::mouseMoveEvent(event);
}

c、鼠标拖拽时移动

 void DragList::dragMoveEvent(QDragMoveEvent * event)
{
DragList * source = (DragList *)((void *)(event->source()));
if (source && source == this)
{
QListWidgetItem * item = itemAt(event->pos());
if (dragItem != nullptr && item != nullptr && m_Drag != nullptr)
{
if ((dragItem == item) != m_IsSelf)
{
m_IsSelf = dragItem == item; if (m_IsSelf)
{
event->setDropAction(Qt::LinkAction);
}
else
{
event->setDropAction(Qt::MoveAction);
}
}
} if (m_ShotPicture == nullptr)
{
InitShotLabel();
} if (ListItem * newWidget = ItemWidget(dragItem))
{
m_ShotPicture->move(mapToGlobal(event->pos() - newWidget->mapFromParent(startPos)));
} event->accept();
}
}

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

 void DragList::dropEvent(QDropEvent * event)
{
if (m_ShotPicture)
{
m_ShotPicture->close();
m_ShotPicture->deleteLater();
m_ShotPicture = nullptr;
}
DragList * source = (DragList *)((void *)(event->source()));
if (source && source == this)
{
endPos = event->pos();//得到鼠标移动到的坐标
QListWidgetItem * itemRow = itemAt(endPos); //通过endPos获取鼠标位置所在的行
if (itemRow == dragItem)
{
event->setDropAction(Qt::LinkAction);
}
else
{
int insertPos = row(itemRow);
if (ListItem * oldWidget = ItemWidget(itemRow))
{
QPoint pos = oldWidget->mapFromParent(endPos);
if (oldWidget->size().height() / < pos.y())
{
insertPos += ;
}
} if (const MimeData * mimeData = dynamic_cast<const MimeData *>(event->mimeData()))
{
QListWidgetItem * newItem = new QListWidgetItem;
ListItem * itemWidget = new ListItem;
ItemData data = mimeData->GetData();
itemWidget->SetData(data); insertItem(insertPos, newItem);
setItemWidget(newItem, itemWidget);
}
event->setDropAction(Qt::MoveAction);
} m_IsSelf = false;
event->accept();
}
}

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

 void DragList::InitShotLabel()
{
m_ShotPicture = new QLabel;
m_ShotPicture->setWindowOpacity(0.5);
m_ShotPicture->setWindowFlags(Qt::Popup);
m_ShotPicture->setAttribute(Qt::WA_TransparentForMouseEvents, true); SetWindowLong((HWND)m_ShotPicture->winId(), GWL_EXSTYLE, GetWindowLong((HWND)m_ShotPicture->winId(), GWL_EXSTYLE) |
WS_EX_TRANSPARENT//忽略一切消息(WM_PAINT除外)
| WS_EX_LAYERED); if (ListItem * oldWidget = ItemWidget(dragItem))
{
m_ShotPicture->resize(oldWidget->size());
m_ShotPicture->setPixmap(oldWidget->grab());
}
m_ShotPicture->show();
}

五、下载链接

  Qt之QAbstractItemView视图项拖拽

六、相关文章

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

  Qt之QAbstractItemView选择无焦点

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

 

很重要--转载声明

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

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

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

    一.需求说明 上一篇文章Qt之QAbstractItemView视图项拖拽(一)讲述了实现QAbstractItemView视图项拖拽的一种方式,是基于QDrag实现的,这个类是qt自己封装好了的,所 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. Qt之QAbstractItemView右键菜单

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

随机推荐

  1. 流媒体选择Nginx是福还是祸?

    CDN,视频云,已经“僧多粥少” 视频直播的持续升温,无意间也让带宽生意的争夺变得异常残酷.一时间,各种云计算.CDN.视频云提供商都在视频尤其是直播上投入重兵,揭竿而起的新生起义军们也正马不停蹄的赶 ...

  2. fidder 抓 https包配置方法(ios & android & pc浏览器)

    1. fidder抓https包的基本配置,可参见以下博文 http://blog.csdn.net/idlear/article/details/50999490 2. 遇到问题:抓包看只有Tunn ...

  3. C++矩阵运算库推荐

    最近在几个地方都看到有人问C++下用什么矩阵运算库比较好,顺便做了个调查,做一些相关的推荐吧.主要针对稠密矩阵,有时间会再写一个稀疏矩阵的推荐. Armadillo:C++下的Matlab替代品 地址 ...

  4. Codeforces Round #384 (Div. 2)D - Chloe and pleasant prizes 树形dp

    D - Chloe and pleasant prizes 链接 http://codeforces.com/contest/743/problem/D 题面 Generous sponsors of ...

  5. web优化规范

    转载自:http://www.tuicool.com/articles/UZR3Az

  6. TypeError: Cannot read property 'root' of null

    解决办法: brew upgrade watchman

  7. 读Java 804 - Quick refresher

    Upcast永远是成功的,但Downcast不是,记得做instanceof判断 仅抛不同异常,而返回值相同的重载是不可以的 static import只会import静态类 static metho ...

  8. 【Cocos2d-Js基础教学(6)网络层(弱联网)的封装及使用】

    谈到联网,在游戏中也是非常核心的模块,在官方Js-test中我们可以找到联网部分 的NetworkTest文件下有两个类 SocketIOTest.js(Socket 类) WebSocketTest ...

  9. C# 文件操作方法

    方法一: FileStream textFile = File.Open(@"F:\程序\新手测试\linqApplication1\linqApplication1\IO.txt" ...

  10. 初探Stage3D(一) 3D渲染基础原理

    关于本文 本文主要想介绍一下3D渲染的基本流程,及怎样把一个三角形(0,1,0),(1,0,1),(0,0,1)最终渲染到屏幕上来.文章的目的是对3D渲染流程做一个简单的介绍,其中不涉及任何语言的AP ...