Qt----拖拽
最近比较忙,今天此才有时间来继续学习下Qt。Qt的拖拽可以按字面意思分为拖和拽两部分。一般来说我们常见的拖拽分别由两个程序合作完成。例如我们经常把桌面的文件拖拽进其他目录:

这个拖拽在Qt中由两方合作完成,一个是桌面窗口另一个是目录窗口,桌面发起“拖”动作,目录窗口接受“放”动作。如果你细心观察还可以发现,在不同的情况下拖拽还可以产生不同的结果:

拖拽方可以发起多个拖拽类型(复制、链接、移动等),接收方可以选择接受其中某个类型或者直接拒绝。除此之外,拖拽支持多种数据格式,并且还可以在同一个应用程序中进行(托和拽操作均由同一个exe发起)。我们通过一个示例程序来学习,这个程序包含以下功能:
- 内部发起拖拽。
- 切换可接受的拖拽动作:移动、拷贝、链接。
- 支持多种拖拽数据:image、html、text、color等。
- 拖拽区域高亮。
1. 内部拖拽
我们在主窗口内部放置了3个Label,分别可以用来演示3种不同数据类型的拖拽效果。如果鼠标左键在这几个标签区域内按下并且移动距离超过5个像素,我们就发起拖拽动作,可能的拖拽类型为:Copy、Move、Link。通过QDrag类我们就能发起一个拖拽动作,这个类还提供了setPixmap()和setHotSpot()函数类供我们自定义拖拽时的图像和位置,这里我们就不设置了。
调用QDrag::exec()就能进入拖拽的事件处理循环了,注意在Linux和Mac上,这个exec并不会阻塞全局的消息循环;在Windows上,它是阻塞的:
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() & Qt::LeftButton) {
m_dragStartPos = event->pos();
if (m_imageLabel->geometry().contains(event->pos()))
m_dragLabel = m_imageLabel;
else if (m_colorLabel->geometry().contains(event->pos()))
m_dragLabel = m_colorLabel;
else if (m_htmlLabel->geometry().contains(event->pos()))
m_dragLabel = m_htmlLabel;
else
m_dragStartPos = QPoint();
}
QMainWindow::mousePressEvent(event);
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
QDrag drag(this);
if (m_dragStartPos.isNull())
goto end;
if ((event->pos() - m_dragStartPos).manhattanLength() < 5)
goto end;
...
drag.exec(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction);
end:
QMainWindow::mouseMoveEvent(event);
}
2. 可接受拖拽类型切换
这个功能我们通过菜单来实现,因为同一时间只接受一种类型,因此这几个菜单要求必须互斥。互斥菜单这个概念我们在代码里选择使用QActionGroup,虽然自己实现切换也不麻烦,但是这样更快更方便。每个子菜单触发时会切换可接受拖拽类型,Qt提供了3种基本类型:Move、Copy、Link。拖拽显示时,Copy类型是一个+号,Move类型是一个→,Link类型是一个粗体的斜箭头:
void MainWindow::createMenus()
{
auto menu = this->menuBar()->addMenu(tr("Acceptable Drags"));
auto copyAction = menu->addAction("Only Copy",
this, SLOT(onlyAcceptCopyDrag()),
QKeySequence(Qt::CTRL + Qt::Key_C));
copyAction->setCheckable(true);
copyAction->setChecked(true);
m_actionGroup.addAction(copyAction);
auto moveAction = menu->addAction("Only Move",
this, SLOT(onlyAcceptMoveDrag()),
QKeySequence(Qt::CTRL + Qt::Key_M));
moveAction->setCheckable(true);
moveAction->setChecked(false);
m_actionGroup.addAction(moveAction);
auto linkAction = menu->addAction("Only Link",
this, SLOT(onlyAcceptLinkDrag()),
QKeySequence(Qt::CTRL + Qt::Key_L));
linkAction->setCheckable(true);
linkAction->setChecked(false);
m_actionGroup.addAction(linkAction);
}
3. 多种拖拽数据类型
我们在发起拖拽的时候设置传递的数据及类型,通过QDrag::setMimeData()函数来设置传入的数据及类型。这个函数接受一个QMimeData类型的指针,这个类用MIME来区分数据类型。对于常见的类型它提供了方便的函数setHtml()、setColorData()等,我们只需要传入数据就可以了:html和texx类型的数据以字符串表示,Image和Color类型数据以QVariant表示;对于自定义类型,我们需要调用setData()函数,同时传入MIME类型和对应的数据(因为使用简单,代码中没有演示)。数据获取则通过对应的html()、imageData()、data()等函数:
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
...
QMimeData* mimeData = new QMimeData();
if (m_dragLabel == m_htmlLabel)
mimeData->setHtml("<html>This is a html page</html>");
if (m_dragLabel == m_colorLabel)
mimeData->setColorData(QVariant(QColor(Qt::cyan)));
if (m_dragLabel == m_imageLabel)
mimeData->setImageData(QVariant(QPixmap(":/img/image.jpg")));
drag.setMimeData(mimeData);
...
}
其实个人觉得QMimeData不是很好用,没有获取当前类型的功能,只能约定好或者一个一个去尝试。
4. 拖拽区域高亮
- 当拖拽进入窗口之中时,会触发
dragEnterEvent()事件,我们在这里高亮窗口背景; - 当我们接受拖拽事件(通过
QDragEnterEvent::accept()或者QDropEvent::acceptProposedAction())后,窗口会收到dragMoveEvent()事件。QDragMoveEvent事件包含一个answerRect()函数,返回相对于窗口的当前拖拽范围,我们通过判断来选择是否绘制中心的高亮区域。有趣的是这个范围大小始终是1x1,它被当成点来处理。 - 当拖拽离开窗口时,会触发
dragLeaveEvent()事件,我们进行重绘。
下面是该部分代码:
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
event->setDropAction(m_acceptableDropAction);
event->accept();
m_currentBkColor = m_dragEnteredColor;
QWidget::dragEnterEvent(event);
}
void MainWindow::dragLeaveEvent(QDragLeaveEvent *event)
{
m_currentBkColor = m_dragLeavedColor;
repaint();
QWidget::dragLeaveEvent(event);
}
void MainWindow::dragMoveEvent(QDragMoveEvent *event)
{
if (m_acceptableRect.contains(event->answerRect()))
m_currentDragableAreaColor = m_highlightColor;
else
m_currentDragableAreaColor = m_unhighlightColor;
repaint();
}
5. 运行结果

代码详见链接。
Qt----拖拽的更多相关文章
- qt 拖拽 修改大小(二)
最近项目需要实现windows下橡皮筋的效果,所以对此做了一些了解,特此记录. 首先windows系统是支持橡皮筋效果的,需要使用win32方 法:SystemParametersInfo(SPI_S ...
- Qt拖拽界面 (*.ui) 缩放问题及解决办法
问题 使用Qt Designer 设计的界面,在缩放的时候不能随着主窗口一起缩放. 解决办法 之前遇到这个问题的时候,都是直接重写resizeEvent接口来实现的,在自动生成的Ui_Widget或U ...
- Qt拖拽界面 (*.ui) 缩放问题及解决办法(在最顶层放一个Layout)
问题 使用Qt Designer 设计的界面,在缩放的时候不能随着主窗口一起缩放. 解决办法 之前遇到这个问题的时候,都是直接重写resizeEvent接口来实现的,在自动生成的Ui_Widget或U ...
- qt 拖拽 修改大小
写次篇文章之前,qt窗口的放大缩小和拖拽我都是通过setGeometry方法实现的,但是作为windows程序,windows支持橡 皮筋式(拖拽时有一个虚框)拖拽和拉伸.通过setGeometry方 ...
- qt 拖拽 修改大小(使用了nativeEvent和winEvent)
http://www.cnblogs.com/swarmbees/p/5621543.html http://blog.sina.com.cn/s/blog_9e59cf590102w3r6.html
- atitit.D&D drag&drop拖拽文件到界面功能 html5 web 跟个java swing c#.net c++ 的总结
atitit.D&D drag&drop拖拽文件到界面功能 html5 web 跟个java swing c#.net c++ 的总结 1. DND的操作流程 1 2. Html5 注 ...
- Qt窗口添加鼠标移动拖拽事件
1. .h文件中添加 private: QPoint dragPosition; 2. 在cpp文件中重写鼠标点击和拖拽函数 void ShapeWidget::mousePressEvent( ...
- Qt之QAbstractItemView视图项拖拽(二)
一.需求说明 上一篇文章Qt之QAbstractItemView视图项拖拽(一)讲述了实现QAbstractItemView视图项拖拽的一种方式,是基于QDrag实现的,这个类是qt自己封装好了的,所 ...
- Qt之QAbstractItemView视图项拖拽(一)
一.需求说明 最近在搞视图项的拖拽,也上网查了一些资料,好多的文档都是一样的,只是被不通的网站所收录了(也有可能是被爬过去的,不明所以),不过也有一些文档写的不错,不过就是太简易,都是点睛之笔,总之功 ...
- QT笔记之自定义窗口拖拽移动
1.QT自定义标题栏,拖拽标题栏移动窗口(只能拖拽标题,其他位置无法拖拽) 方法一: 转载:http://blog.sina.com.cn/s/blog_4ba5b45e0102e83h.html . ...
随机推荐
- ssm搭建报错
在搭建ssm框架时候踩得坑:1.对于拦截器url-parttern的设置:第一次设置的是/** 本以为这个是表示拦截所有,没想到这是错误的写法,正确的写法是/ 启动项目不会报错,但是会出现404 ...
- 【疑问】用python写登录验证遇到的问题
最近开始断断续续学习python,今天加入博客园,作为新人,和各位老师们讨教了,以后多多照顾!为了大家能看清楚所以就截图了,文末尾附源码,说不定会有那位老师给我指教一番.############### ...
- MySQL自定义函数用法详解-复合结构自定义变量/流程控制
自定义函数 (user-defined function UDF)就是用一个象ABS() 或 CONCAT()这样的固有(内建)函数一样作用的新函数去扩展MySQL. 所以UDF是对MySQL功能的一 ...
- 简述Apache的ab测试主要有那些关键指标
一.ab的原理 ab是apachebench命令的缩写. ab的原理:ab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问.它的测试目标是基于URL的,因此,它既可以用来测试ap ...
- java字串加密
字串加密 1.设计思想: (1)加密方法,字符串的每一个字符都代表这个字符往后的第三位,最后三个字符代表,开始的三个字符. (2)解密方法,字符串的每一个字符都代表这个字符往前的第三位,开始三个字符代 ...
- SimpleDateFormat时间格式化存在线程安全问题
想必大家对SimpleDateFormat并不陌生.SimpleDateFormat 是 Java 中一个非常常用的类,该类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调 ...
- Linux系列教程(八)——Linux常用命令之压缩和解压缩命令
前面一篇博客我们讲解了Linux帮助和用户管理命令,对于帮助命令,man 命令能获得命令和配置文件的帮助信息,help命令能获得shell内置命令的帮助信息.我们可以通过which来区分什么是shel ...
- 07-从零玩转JavaWeb-对象内存分析
上篇看了关于数组的内存分析,接下来看一下对象的内存分析 假定有如下类: 第一步会把Person的字节码放到方法区 执行main方法,把main方法的栈帧放到栈当中 Person zly = ...
- 独热编码OneHotEncoder简介
在分类和聚类运算中我们经常计算两个个体之间的距离,对于连续的数字(Numric)这一点不成问题,但是对于名词性(Norminal)的类别,计算距离很难.即使将类别与数字对应,例如{'A','B','C ...
- 楼梯T-SQL:超越基础6级:使用CASE表达式和IIF函数
从他的楼梯到T-SQL DML,Gregory Larsen涵盖了更多的高级方面的T-SQL语言,如子查询. 有时您需要编写一个可以根据另一个表达式的评估返回不同的TSQL表达式的单个TSQL语句. ...