关于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. 2019前端学习路线心得-黑马程序员pink老师

    在规划之前先给大家分享几点心得哈: 1. 学习,特别是在线学习,是非常辛苦的事情,为了少走弯路, 所以一定要系统学习,多借鉴与前辈们总结出来的经验. 2. 不要相信任何说 一周掌握 css, 一周学完 ...

  2. C++Review6_优先队列priority_queue

    普通队列是一个先进先出的数据结构,元素在队尾添加,在队头删除. 优先队列的出队逻辑相比于普通队列发生了改变,具有最高优先级的元素先出队. 在C++中只要包含了#include<queue> ...

  3. JMeter JMS测试计划

    在本节中,我们将学习如何编写一个简单的测试计划来测试Java Messaging Service(JMS). 出于测试目的,我们使用Apache ActiveMQ.有各种JMS服务器,如:glassf ...

  4. Docker zookeeper 集群 for Docker desktop (win)

    docker desktop win10 环境下的 zookeeper 容器创建并运及可能出现的问题: https://github.com/poazy/boazy-learn/blob/master ...

  5. Laravel5.5 邮件发送报错:stream_socket_client()

    具体报错如下: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:1409 ...

  6. Spring||IQ

    Here's the question about spring 1.Spring概述 Spring 是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应 ...

  7. centos批量创建用户并发送邮件,(修订版)

    # cat user_create.sh echo -n "创建用户输入C,删除用户输入D!" read name function monitor() { if [ " ...

  8. Python中三大框架各自的应用场景(DJango,flask,Tornado)

    django:主要是用来搞快速开发的,他的亮点就是快速开发,节约成本,正常的并发量不过10000,如果要实现高并发的话,就要对django进行二次开发,比如把整个笨重的框架给拆掉,自己写socket实 ...

  9. 【题解】P1712 [NOI2016]区间(贪心+线段树)

    [题解]P1712 [NOI2016]区间(贪心+线段树) 一个observe是,对于一个合法的方案,将其线段长度按照从大到小排序后,他极差的来源是第一个和最后一个.或者说,读入的线段按照长度分类后, ...

  10. JAVA字节码文件之结构

    开发工具:IEDA.JDK1.8.WinHex 一.字节码文件结构 源代码 package com.jalja.java.bytecode; /** * @Auther: XL * @Date: 20 ...