qt中的拖拽及其使用技巧
关于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思维导图
参考资料:
- http://doc.qt.io/qt-5.5/dnd.html
- http://blog.csdn.net/pcsuite/article/details/6147191
qt中的拖拽及其使用技巧的更多相关文章
- [Qt]Qt中TreeWidget拖拽事件
文章在简书里啦 http://www.jianshu.com/p/45b740060aca
- Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值
Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值,去属性表中设置这时候会提示你去属性表中更改返回类型. 其实存储过程返回的也是一张表,只不过有时候存储过程有点复杂或者写法不规范的话不能 ...
- iOS开发拓展篇—xib中关于拖拽手势的潜在错误
iOS开发拓展篇—xib中关于拖拽手势的潜在错误 一.错误说明 自定义一个用来封装工具条的类 搭建xib,并添加一个拖拽的手势. 主控制器的代码:加载工具条 封装工具条以及手势拖拽的监听事件 此时运行 ...
- iOS - xib中关于拖拽手势的潜在错误
iOS开发拓展篇—xib中关于拖拽手势的潜在错误 一.错误说明 自定义一个用来封装工具条的类 搭建xib,并添加一个拖拽的手势. 主控制器的代码:加载工具条 封装工具条以及手势拖拽的监听事件 此时运行 ...
- QT之——QTableWidget拖拽单元格并替换内容(进阶)
所需待重写函数: [virtual] bool QObject::eventFilter(QObject *watched, QEvent *event); /* * Filters events i ...
- H5中的拖拽事件
最近浏览了张鑫旭大神的基于HTML5 drag/drop模块拖动插入排序删除完整实例,感觉受益匪浅.于是将最做的demo记录下来. 首先浏览一下事件,这些事件比较好记,只要记住用在谁的身上就好了,无非 ...
- Android中GridView拖拽的效果【android进化三十六】
最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的 ...
- Android中GridView拖拽的效果
最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的那么 ...
- 浅谈DevExpress<四>:TreeList中的拖拽功能
本篇要实现的目标,简单来说就是把一个treelist的节点用鼠标拖到另外的节点(自身或其他的listview)上,如下图: 1
随机推荐
- UVA - 11475 Extend to Palindrome (后缀数组)
Your task is, given an integer N, to make a palidrome (word that reads the same when you reverse it) ...
- 【Repo】repo sync:error.GitError: cannot initialize work tree
1.Error Fetching projects: 100% (725/725), done. Checking out files: 100% (4605/4605), done.out file ...
- Python 实现栈与队列
#基于Python2.7 #基于顺序表实现 #发现用Python写题时,没有像写C++时方便的STL可用,不过查阅资料之后发现用class实现也很简洁,不过效率应该不是很高 Python实现栈并使用: ...
- DEVOPS技术实践_13:使用Jenkins持续传送设计-CD基础
1. 分支策略 持续集成中使用的分支策略包括以下三个: The master branch The integration branch The feature branch 而CD只在Integra ...
- DecoratorPattern(装饰器模式)-----Java/.Net
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装
- Linux 文件系统 -- inode 笔记
什么是 inode inode 的定义:Unix 文件系统中的一种数据结构,用来存储文件的元信息数据 文件在硬盘中的存储是以"块"(block)为单位的,常见的块大小是 4k ...
- 基于 Blazui 的 Markdown 编辑器 Blazui.Markdown 尝鲜
想做一个文档平台用来存放和展示 Blazui 的文档,然后基于 Markdown 写文档,但缺一个好用的 Blazor Markdown 编辑器,所以就顺便写一个了,功能上基本抄的 https://p ...
- Codeforces Round #519 by Botan Investments(前五题题解)
开个新号打打codeforces(以前那号玩废了),结果就遇到了这么难一套.touristD题用了map,被卡掉了(其实是对cf的评测机过分自信),G题没过, 700多行代码,码力惊人.关键是这次to ...
- 【转】8 个效果惊人的 WebGL/JavaScript 演示
英文原文:9 IMPRESSIVE WEBGL JAVASCRIPT EFFECT SHOWCASE,翻译:iteye WebGL 是一种 3D 绘图标准,这种绘图技术标准允许把 JavaScript ...
- 【转】JavaScript 3D图表
文章系本人原创,转载请保持完整性并注明出自<四火的唠叨> 在说3D图表以前,首先要明确两个概念,一个是数据的维度,一个是呈现数据载体的维度.对于数据的维度,一维的数据呈现,但是呈现的载体是 ...