关于qt中的拖放操作,首先可以看这篇官方文档:http://doc.qt.io/qt-5.5/dnd.html

一、QDrag

首先是创建QDrag,可以在mousePressEvent或者mouseMoveEvent中创建。

void DragDropWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
QDrag *drag = new QDrag(this);
QMimeData *data = new QMimeData;
drag->setMimeData(data);
drag->exec(Qt::MoveAction);
}
}

或者

void DragDropWidget::mousePressEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
{
startPos = event->pos();
}
} void DragDropWidget::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
{
if ((event->pos() - startPos).manhattanLength() < QApplication::startDragDistance())
{
QDrag *drag = new QDrag(this);
QMimeData *data = new QMimeData;
drag->setMimeData(data);
drag->exec(Qt::LinkAction);
}
}
}

QDrag在exec前,一定要设置QMimeData,否则会弹出警告“QDrag: No mimedata set before starting the drag”。并且不会开始拖拽操作。

QMimeData在拖拽中非常有用,可以用来保存拖拽操作附带的信息,比如字符串、文件或者图片,同时也可以用来验证其所保存的信息格式,并以此来判断是否可接收。未来再补充QMimeData的用法。

另外要注意,在windows下,QDrag::exec()是个同步操作,要在exec()返回后,才会继续执行下面的代码。

二、drag相关事件

首先,当需要一个控件接收drag和drop,就要先调用控件的方法:setAcceptDrops(true)。

qt中一共有三个drag相关事件,dragEnterEvent、dragMoveEvent、dragLeaveEvent。这三个事件触发条件类似鼠标移入,鼠标移动,鼠标移出。当鼠标拖拽进入控件触发dragEnterEvent,在控件内拖拽移动触发dragMoveEvent,鼠标拖拽离开控件触发dragLeaveEvent。

dragEnterEvent事件有一个参数,参数类型是QDragEnterEvent,继承自QDragMoveEvent。

dragMoveEvent事件有一个参数,参数类型是QDragMoveEvent。

dragLeaveEvent事件有一个参数,参数类型是QDragLeaveEvent,继承自QEvent,无特别用法。

当鼠标拖拽进入控件时,会触发dragEnterEvent,如果不做处理,后续将不会接收到dragMoveEvent事件和dragLeaveEvent事件。在dragEnterEvent事件中,如果调用了QDragMoveEvent::accept()函数,后续将可以收到dragMoveEvent事件和dragLeaveEvent事件。而如果调用QDragMoveEvent::ignore()函数,效果相当于不处理,不会接收后续事件。

void DragDropWidget::dragEnterEvent(QDragEnterEvent *event)
{
if (event->source() == this)
event->ignore();
else
event->accept();
}

发起drag的控件自身也是可以接受到来自自身的drag的相关事件的,这个要注意,处理不好容易出bug。

三、dropEvent

当drag为accept状态,然后释放鼠标,就会产生dropEvent。我们可以在这个事件里处理本次拖拽附带的Mime信息。

四、使用技巧

在我的一个项目中,需要通过拖拽操作连接两个控件,然后在两个控件之间画连接线。这里有两种控件,画布控件CanvasWidget,和节点控件NodeWidget。NodeWidget在CanvasWidget上,连接线也是在CanvasWidget上绘制。我们可以在NodeWidget的dropEvent事件里给CanvasWidget发送连接信号,告诉CanvasWidget两个NodeWidget已经相连了。

void NodeWidget::dropEvent(QDropEvent *event)
{
auto src = event->source();
event->setDropAction(Qt::LinkAction);
event->accept();
emit linked(src, this);
}

然后我又想在拖拽的过程中就看到一条动态的连接线,这时候就要用到CanvasWidget的drag相关事件。在CanvasWidget的dragMoveEvent事件中这样处理:

void CanvasWidget::dragMoveEvent(QDragMoveEvent *event)
{
m_lineDraging.end = event->pos();
update();
}

m_lineDraging就是用来绘制的动态连接线。设置完连接线的端点,然后再update()一下,就可以显示了。当然这只是一个简单方案,还没有验证过在绘制量较大时,在move事件中update会不会很卡。

下面是效果图

Qt Drag and Drop思维导图

 

参考资料:

  1. http://doc.qt.io/qt-5.5/dnd.html
  2. http://blog.csdn.net/pcsuite/article/details/6147191

qt中的拖拽及其使用技巧的更多相关文章

  1. [Qt]Qt中TreeWidget拖拽事件

    文章在简书里啦 http://www.jianshu.com/p/45b740060aca

  2. Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值

    Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值,去属性表中设置这时候会提示你去属性表中更改返回类型. 其实存储过程返回的也是一张表,只不过有时候存储过程有点复杂或者写法不规范的话不能 ...

  3. iOS开发拓展篇—xib中关于拖拽手势的潜在错误

    iOS开发拓展篇—xib中关于拖拽手势的潜在错误 一.错误说明 自定义一个用来封装工具条的类 搭建xib,并添加一个拖拽的手势. 主控制器的代码:加载工具条 封装工具条以及手势拖拽的监听事件 此时运行 ...

  4. iOS - xib中关于拖拽手势的潜在错误

    iOS开发拓展篇—xib中关于拖拽手势的潜在错误 一.错误说明 自定义一个用来封装工具条的类 搭建xib,并添加一个拖拽的手势. 主控制器的代码:加载工具条 封装工具条以及手势拖拽的监听事件 此时运行 ...

  5. QT之——QTableWidget拖拽单元格并替换内容(进阶)

    所需待重写函数: [virtual] bool QObject::eventFilter(QObject *watched, QEvent *event); /* * Filters events i ...

  6. H5中的拖拽事件

    最近浏览了张鑫旭大神的基于HTML5 drag/drop模块拖动插入排序删除完整实例,感觉受益匪浅.于是将最做的demo记录下来. 首先浏览一下事件,这些事件比较好记,只要记住用在谁的身上就好了,无非 ...

  7. Android中GridView拖拽的效果【android进化三十六】

      最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的 ...

  8. Android中GridView拖拽的效果

    最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的那么 ...

  9. 浅谈DevExpress<四>:TreeList中的拖拽功能

    本篇要实现的目标,简单来说就是把一个treelist的节点用鼠标拖到另外的节点(自身或其他的listview)上,如下图: 1 

随机推荐

  1. mysql修改数据库密码

    方法1: 运行MySQL 5.7 Command Line Client,输入老的密码: use mysql: update user set authentication_string=passwo ...

  2. 【53.57%】【codeforces 610C】Harmony Analysis

    time limit per test3 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  3. [POJ2528]Mayor's posters(离散化+线段树)

    Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 70365   Accepted: 20306 ...

  4. Channel 9视频整理【3】

    Will 保哥 微软mvp https://channel9.msdn.com/Niners/Will_Huang 繁体中文视频 Visual Studio 2017 新功能探索 https://ch ...

  5. 安卓APP动态调试(IDA实用攻略)

    转自:http://drops.wooyun.org/mobile/5942 0x00 前言 随着智能手机的普及,移动APP已经贯穿到人们生活的各个领域.越来越多的人甚至已经对这些APP应用产生了依赖 ...

  6. element-ui table 的翻页记忆选中

    公司中台项目刚开始开发,用了vue+element,需要许多前置调研,table的翻译记忆选中就是其中之一. template: <el-table :ref="tableRef&qu ...

  7. C# event 事件

    事件第二篇:https://www.cnblogs.com/FavoriteMango/p/11731485.html 曾经面试碰到一道设计题: 现有一个人,一群鸟,人有一把手枪,当人开枪时,所有的鸟 ...

  8. 软RAID和硬RAID的区别

    要实现RAID可以分为硬件实现和软件实现两种.所谓硬RAID就是指通过硬件实现,同理软件实现就作为软RAID.   硬RAID 就是用专门的RAID控制器将硬盘和电脑连接起来,RAID控制器负责将所有 ...

  9. 多vps管理面板

           iis7远程桌面连接工具,又叫做iis7远程桌面管理软件,是一款绿色小巧,功能实用的远程桌面管理工具,其界面简洁,操作便捷,能够同时远程操作多台服务器,并且多台服务器间可以自由切换,适用 ...

  10. jib-maven-plugin构建镜像

    序言 在本次期末设计当中,应为需要做部署脚本,我们采用的是dockerfile+docker-compose的部署方式,这种方式对vue项目是没有问题的,因为vue下载依赖与打包是分离开来的,即使修改 ...