当前位置: 首页 > news >正文

Qt学习之路(52): 拖放技术之一

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://devbean.blog.51cto.com/448512/280052
拖放 Drag and Drop,有时又被称为 DnD,是现代软件开发中必不可少的一项技术。它提供了一种能够在应用程序内部甚至是应用程序之间进行信息交换的机制,并且,操作系统与应用程序之间进行剪贴板的内容交换,也可以被认为是 DnD 的一部分。
DnD 其实是由两部分组成的:Drag 和 Drop。Drag 是将被拖放对象“拖动”,Drop 是将被拖放对象“放下”,前者一般是一个按下鼠标的过程,而后者则是一个松开鼠标的过程,这两者之间鼠标一直是被按下的。当然,这只是一种通常的情况,其他情况还是要看应用程序的具体实现。对于 Qt 而言,widget既可以作为 drag 对象,也可以作为 drop 对象,或者二者都是。
下面的一个例子来自 C++ GUI Programming with Qt 4, 2nd Edition。在这个例子中,我们创建一个程序,可以将系统中的文本文件拖放过来,然后在窗口中读取内容。
mainwindow.h

1. #ifndef MAINWINDOW_H
2. #define MAINWINDOW_H
3.
4. #include <QtGui>
5.
6. class MainWindow : public QMainWindow
7. {
8. Q_OBJECT
9.
10. public:
11. MainWindow(QWidget *parent = 0);
12. ~MainWindow();
13.
14. protected:
15. void dragEnterEvent(QDragEnterEvent *event);
16. void dropEvent(QDropEvent *event);
17.
18. private:
19. bool readFile(const QString &fileName);
20. QTextEdit *textEdit;
21. };
22.
23. #endif // MAINWINDOW_H

mainwindow.cpp

1. #include "mainwindow.h"
2.
3. MainWindow::MainWindow(QWidget *parent)
4. : QMainWindow(parent)
5. {
6. textEdit = new QTextEdit;
7. setCentralWidget(textEdit);
8.
9. textEdit->setAcceptDrops(false);
10. setAcceptDrops(true);
11.
12. setWindowTitle(tr("Text Editor"));
13. }
14.
15. MainWindow::~MainWindow()
16. {
17. }
18.
19. void MainWindow::dragEnterEvent(QDragEnterEvent *event)
20. {
21. if (event->mimeData()->hasFormat("text/uri-list")) {
22. event->acceptProposedAction();
23. }
24. }
25.
26. void MainWindow::dropEvent(QDropEvent *event)
27. {
28. QList<QUrl> urls = event->mimeData()->urls();
29. if (urls.isEmpty()) {
30. return;
31. }
32.
33. QString fileName = urls.first().toLocalFile();
34. if (fileName.isEmpty()) {
35. return;
36. }
37.
38. if (readFile(fileName)) {
39. setWindowTitle(tr("%1 - %2").arg(fileName, tr("Drag File")));
40. }
41. }
42.
43. bool MainWindow::readFile(const QString &fileName)
44. {
45. bool r = false;
46. QFile file(fileName);
47. QTextStream in(&file);
48. QString content;
49. if(file.open(QIODevice::ReadOnly)) {
50. in >> content;
51. r = true;
52. }
53. textEdit->setText(content);
54. return r;
55. }

main.cpp

1. #include <QtGui/QApplication>
2. #include "mainwindow.h"
3.
4. int main(int argc, char *argv[])
5. {
6. QApplication a(argc, argv);
7. MainWindow w;
8. w.show();
9. return a.exec();
10. }

这里的代码并不是很复杂。在MainWindow中,一个QTextEdit作为窗口中间的widget。这个类中有两个protected的函数:dragEnterEvent() 和 dropEvent(),这两个函数都是继承自 QWidget,看它们的名字就知道这是两个事件,而不仅仅是signal。
在构造函数中,我们创建了 QTextEdit 的对象。默认情况下,QTextEdit 可以接受从其他的应用程序拖放过来的文本类型的信息。如果用户把一个文件拖到这里面,那么就会把文件名插入到文本的当前位置。但是我们希望让 MainWindow 读取文件内容,而不仅仅是插入文件名,所以我们在MainWindow中对 drop 事件进行了处理,因此要把QTextEdit的setAcceptDrops()函数置为false,并且把MainWindow的 setAcceptDrops()置为true,以便让MainWindow对 drop 事件进行处理。
当用户将对象拖动到组件上面时,dragEnterEvent()函数会被回调。如果我们在事件处理代码中调用 acceptProposeAction() 函数,我们就可以向用户暗示,你可以将拖动的对象放在这个组件上。默认情况下,组件是不会接受拖放的。如果我们调用了这样的函数,那么Qt会自动地以光标来提示用户是否可以将对象放在组件上。在这里,我们希望告诉用户,窗口可以接受拖放。因此,我们首先检查拖放的MIME类型。MIME类型为 text/uri-list 通常用来描述一个 URI 的列表。这些 URI 可以是文件名,可以是 URL或者其他的资源描述符。MIME类型由 Internet Assigned Numbers Authority (IANA) 定义,Qt 的拖放事件使用MIME类型来判断拖放对象的类型。关于 MIME类型的详细信息,请参考 http://www.iana.org/assignments/media-types/.
当用户将对象释放到组件上面时,dropEvent() 函数会被回调。我们使用 QMimeData::urls()来或者 QUrl 的一个list。通常,这种拖动应该只用一个文件,但是也不排除多个文件一起拖动。因此我们需要检查这个list是否为空,如果不为空,则取出第一个。如果不成立,则立即返回。最后我们调用 readFile() 函数读取文件内容。关于读取操作我们会在以后的章节中详细说明,这里不再赘述。
好了,至此我们的小程序就解释完毕了,运行一下看看效果吧!
对于拖动和脱离,Qt 也提供了类似的函数:dragMoveEvent() 和 dragLeaveEvent(),不过对于大部分应用而言,这两个函数的使用率要小得多。

本文出自 “豆子空间” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/280052

相关文章:

  • C# 图片识别(支持21种语言)【转】
  • Qt学习之路(tip): Qt容器和算法拾遗
  • 使用 vimdiff 來呈現 Git diff 差異
  • android 开发Eclipse 快捷键
  • Qt学习之路(51): QByteArray和QVariant
  • 我该如何奋斗?
  • Qt学习之路(50): QString
  • 原创:C语言贪吃蛇代码
  • Qt学习之路(49): 通用算法
  • 【转】解决:SecureCRT在Linux下vim显示utf-8编码的文件乱码
  • Qt学习之路(47): 自定义Model之三
  • 用vc++做滚动条控件
  • Qt学习之路(48): 自定义委托
  • 9520个大气笔刷!902个无缝叠加图案!!770个质感纹理!!!
  • Qt学习之路(46): 自定义model之二
  • 2017 前端面试准备 - 收藏集 - 掘金
  • Git初体验
  • Linux Process Manage
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • Object.assign方法不能实现深复制
  • Python_OOP
  • session共享问题解决方案
  • Vue2.0 实现互斥
  • vue-router 实现分析
  • vue数据传递--我有特殊的实现技巧
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 最近的计划
  • 【干货分享】dos命令大全
  • kubernetes资源对象--ingress
  • #if 1...#endif
  • #include<初见C语言之指针(5)>
  • #NOIP 2014# day.1 T2 联合权值
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (Matlab)使用竞争神经网络实现数据聚类
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (四) Graphivz 颜色选择
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转) Face-Resources
  • (转)甲方乙方——赵民谈找工作
  • .bat批处理(六):替换字符串中匹配的子串
  • .form文件_一篇文章学会文件上传
  • .net 4.0发布后不能正常显示图片问题
  • .NET DataGridView数据绑定说明
  • .net 按比例显示图片的缩略图
  • .Net 代码性能 - (1)
  • .NET 读取 JSON格式的数据
  • .Net7 环境安装配置
  • .net的socket示例
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • [ 常用工具篇 ] AntSword 蚁剑安装及使用详解
  • [acm算法学习] 后缀数组SA
  • [AI]文心一言出圈的同时,NLP处理下的ChatGPT-4.5最新资讯