Qt学习之路(54): 自定义拖放数据对象

QT拖放事件之七:子类化QMimeData,实现对多个自定义类型进行数据 【代码】QT拖放事件七:子类化QMimeData,实现对多个自定义类型进行数据。 阅读详情
前面的例子都是使用的系统提供的拖放对象 QMimeData 进行拖放数据的存储,比如使用 QMimeData::setText() 创建文本,使用 QMimeData::urls() 创建 URL 对象。但是,如果你希望使用一些自定义的对象作为拖放数据,比如自定义类等等,单纯使用 QMimeData 可能就没有那么容易了。为了实现这种操作,我们可以从下面三种实现方式中选择一个:
  1. 将自定义数据作为 QByteArray 对象,使用 QMimeData::setData() 函数作为二进制数据存储到 QMimeData 中,然后使用 QMimeData::Data() 读取;
  2. 继承 QMimeData,重写其中的 formats() 和 retrieveData() 函数操作自定义数据;
  3. 如果拖放操作仅仅发生在同一个应用程序,可以直接继承 QMimeData,然后使用任意合适的数据结构进行存储。
第一种方法不需要继承任何类,但是有一些局限:即是拖放不会发生,我们也必须将自定义的数据对象转换成 QByteArray 对象;如果你希望支持很多种拖放的数据,那么每种类型的数据都必须使用一个 QMimeData 类,这可能会导致类爆炸;如果数据很大的话,这种方式可能会降低系统的可维护性。然而,后两种实现方式就不会有这些问题,或者说是能够减小这种问题,并且能够让我们有完全控制权。
我们先来看一个应用,使用 QTableWidget 来进行拖放操作,拖放的类型包括 plain/text,plain/html 和 plain/csv。如果使用第一种实现方法,我们的代码将会如下所示:
 
  1. void MyTableWidget::mouseMoveEvent(QMouseEvent *event)
  2. {
  3. if (event->buttons() & Qt::LeftButton) {
  4. int distance = (event->pos() - startPos).manhattanLength();
  5. if (distance >= QApplication::startDragDistance())
  6. performDrag();
  7. }
  8. QTableWidget::mouseMoveEvent(event);
  9. }
  10. void MyTableWidget::performDrag()
  11. {
  12. QString plainText = selectionAsPlainText();
  13. if (plainText.isEmpty())
  14. return;
  15. QMimeData *mimeData = new QMimeData;
  16. mimeData->setText(plainText);
  17. mimeData->setHtml(toHtml(plainText));
  18. mimeData->setData("text/csv", toCsv(plainText).toUtf8());
  19. QDrag *drag = new QDrag(this);
  20. drag->setMimeData(mimeData);
  21. if (drag->exec(Qt::CopyAction | Qt::MoveAction) == Qt::MoveAction)
  22. deleteSelection();
  23. }
对于这段代码,我们应该已经很容易的理解:在 performDrag() 函数中,我们调用 QMimeData 的 setText() 和 setHTML() 函数存储 plain/text 和 plain/html 数据,使用 setData() 将 text/csv 类型的数据作为二进制 QByteArray 类型存储。
 
  1. QString MyTableWidget::toCsv(const QString &plainText)
  2. {
  3. QString result = plainText;
  4. result.replace("\\", "\\\\");
  5. result.replace("\"", "\\\"");
  6. result.replace("\t", "\", \"");
  7. result.replace("\n", "\"\n\"");
  8. result.prepend("\"");
  9. result.append("\"");
  10. return result;
  11. }
  12. QString MyTableWidget::toHtml(const QString &plainText)
  13. {
  14. QString result = Qt::escape(plainText);
  15. result.replace("\t", "<td>");
  16. result.replace("\n", "\n<tr><td>");
  17. result.prepend("<table>\n<tr><td>");
  18. result.append("\n</table>");
  19. return result;
  20. }
toCsv() 和 toHtml() 函数将数据取出并转换成我们需要的 csv 和 html类型的数据。例如,下面的数据
Red   Green   Blue
Cyan  Yellow  Magenta
转换成 csv 格式为:
"Red", "Green", "Blue"
"Cyan", "Yellow", "Magenta"
转换成 html 格式为:
<table>
< tr><td>Red<td>Green<td>Blue
< tr><td>Cyan<td>Yellow<td>Magenta
< /table>
在放置的函数中我们像以前一样使用:
 
  1. void MyTableWidget::dropEvent(QDropEvent *event)
  2. {
  3. if (event->mimeData()->hasFormat("text/csv")) {
  4. QByteArray csvData = event->mimeData()->data("text/csv");
  5. QString csvText = QString::fromUtf8(csvData);
  6. // ...
  7. event->acceptProposedAction();
  8. } else if (event->mimeData()->hasFormat("text/plain")) {
  9. QString plainText = event->mimeData()->text();
  10. // ...
  11. event->acceptProposedAction();
  12. }
  13. }
虽然我们接受三种数据类型,但是在这个函数中我们只接受两种类型。至于 html 类型,我们希望如果用户将 QTableWidget 的数据拖到一个 HTML 编辑器,那么它就会自动转换成 html 代码,但是我们不计划支持将外部的 html 代码拖放到 QTableWidget 上。为了让这段代码能够工作,我们需要在构造函数中设置 setAcceptDrops(true) 和 setSelectionMode(ContiguousSelection)。
好了,上面就是我们所说的第一种方式的实现。这里并没有给出完整的实现代码,大家可以根据需要自己实现一下试试。下面我们将按照第二种方法重新实现这个需求。
 
  1. class TableMimeData : public QMimeData
  2. {
  3. Q_OBJECT
  4. public:
  5. TableMimeData(const QTableWidget *tableWidget,
  6. const QTableWidgetSelectionRange &range);
  7. const QTableWidget *tableWidget() const { return myTableWidget; }
  8. QTableWidgetSelectionRange range() const { return myRange; }
  9. QStringList formats() const;
  10. protected:
  11. QVariant retrieveData(const QString &format,
  12. QVariant::Type preferredType) const;
  13. private:
  14. static QString toHtml(const QString &plainText);
  15. static QString toCsv(const QString &plainText);
  16. QString text(int row, int column) const;
  17. QString rangeAsPlainText() const;
  18. const QTableWidget *myTableWidget;
  19. QTableWidgetSelectionRange myRange;
  20. QStringList myFormats;
  21. };
为了避免存储具体的数据,我们存储 table 和选择区域的坐标的指针。
 
  1. TableMimeData::TableMimeData(const QTableWidget *tableWidget,
  2. const QTableWidgetSelectionRange &range)
  3. {
  4. myTableWidget = tableWidget;
  5. myRange = range;
  6. myFormats << "text/csv" << "text/html" << "text/plain";
  7. }
  8. QStringList TableMimeData::formats() const
  9. {
  10. return myFormats;
  11. }
构造函数中,我们对私有变量进行初始化。formats() 函数返回的是被 MIME 数据对象支持的数据类型列表。这个列表是没有先后顺序的,但是最佳实践是将“最适合”的类型放在第一位。对于支持多种类型的应用程序而言,有时候会直接选用第一个符合的类型存储。
 
  1. QVariant TableMimeData::retrieveData(const QString &format,
  2. QVariant::Type preferredType) const
  3. {
  4. if (format == "text/plain") {
  5. return rangeAsPlainText();
  6. } else if (format == "text/csv") {
  7. return toCsv(rangeAsPlainText());
  8. } else if (format == "text/html") {
  9. return toHtml(rangeAsPlainText());
  10. } else {
  11. return QMimeData::retrieveData(format, preferredType);
  12. }
  13. }
函数 retrieveData() 将给出的 MIME 类型作为 QVariant 返回。参数 format 的值通常是 formats() 函数返回值之一,但是我们并不能假定一定是这个值之一,因为并不是所有的应用程序都会通过 formats() 函数检查 MIME 类型。一些返回函数,比如 text(), html(), urls(), imageData(), colorData() 和 data() 实际上都是在 QMimeData 的 retrieveData() 函数中实现的。第二个参数 preferredType 给出我们应该在 QVariant 中存储哪种类型的数据。在这里,我们简单的将其忽略了,并且在 else 语句中,我们假定 QMimeData 会自动将其转换成所需要的类型。
 
  1. void MyTableWidget::dropEvent(QDropEvent *event)
  2. {
  3. const TableMimeData *tableData =
  4. qobject_cast<const TableMimeData *>(event->mimeData());
  5. if (tableData) {
  6. const QTableWidget *otherTable = tableData->tableWidget();
  7. QTableWidgetSelectionRange otherRange = tableData->range();
  8. // ...
  9. event->acceptProposedAction();
  10. } else if (event->mimeData()->hasFormat("text/csv")) {
  11. QByteArray csvData = event->mimeData()->data("text/csv");
  12. QString csvText = QString::fromUtf8(csvData);
  13. // ...
  14. event->acceptProposedAction();
  15. } else if (event->mimeData()->hasFormat("text/plain")) {
  16. QString plainText = event->mimeData()->text();
  17. // ...
  18. event->acceptProposedAction();
  19. }
  20. QTableWidget::mouseMoveEvent(event);
  21. }
在放置的函数中,我们需要按照我们自己定义的数据类型进行选择。我们使用 qobject_cast 宏进行类型转换。如果成功,说明数据来自同一应用程序,因此我们直接设置 QTableWidget 相关 数据,如果转换失败,我们则使用一般的处理方式。

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

Qt/C++编写自定义控件54-时钟仪表盘 一、前言 这个控件没有太多的应用场景,主要就是练手,论美观的话比不上之前发过的一个图片时钟控件,所以此控件也是作为一个基础的绘制demo出现在Qt源码中,我们可以在Qt的安装目录下找到一个时钟控件的绘制,甚至还有qml版本,本控件无非就是一个仪表边框加上时钟分钟刻度再加上时分秒指针,打完收工,我是在此基础上增加了可以设置各种颜色,然后鼠标右键可设置四种效果 普通效果/弹簧效果/连续效果/隐藏效果,... 阅读详情

相关推荐

从入门到实战:rkhunter(Rootkit猎手)在Linux服务器安全运维中的部署与自动化监控

本文详细介绍了rkhunter(Rootkit猎手)在Linux服务器安全运维中的部署与自动化监控方法。从Rootkit的危害性入手,讲解了rkhunter的安装、配置及实战应用,包括如何建立基准、优化定时任务方案以及智能告警处理。通过多级过滤脚本和系统级联动,帮助运维人员高效识别和应对Rootkit威胁,提升服务器安全性。

weixin_28715953的博客 241

QT5学习2-信号槽

版权声明该文章原创于Qter开源社区(www.qter.org),作者devbean,博客www.devbean.net,转载请注明出处! 信号槽是 Qt 框架引以为豪的机制之一。熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力。 所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没...

zhizhuan3361的博客 326

集成电路设计笔记(七)UVLO设计

1. 什么是UVLO 欠压锁定(Undervoltage-Lockout)简称UVLO,是电子设备中在电源电压低于正常工程准位时,切断电源的电路。在嵌入式系统中常会用UVLO监控电池电压,若电压低于一定值,会直接切断电源,保护嵌入式系统的电路。 许多电子设备中都有UVLO的功能,例如在镇流器中就有UVLO电路,若电压过低时直接切断电源。 UVLO就是低电压锁定; 低压关断. 欠压关断模式是当供电电压低于IC的开启门限电压时的一种保护模式。欠压关断模式可保证IC在供电电压不足时不致于被损坏。一个低电压锁定(

ccbirds 2万+

Qt 拖放 - QMimeData类(2)

在 Qt 中,QMimeData 类是一个数据容器类,用于存储多种格式的数据和 MIME 类型。主要用途是为了支持拖放和剪切复制等操作,以便应用程序之间或同一应用程序内传递数据。

STIV_的博客 732

Jenkins插件下载慢?3分钟搞定国内镜像加速(含华为/腾讯/清华源对比)

本文详细介绍了如何通过国内镜像源加速Jenkins插件下载,包括华为云、腾讯云和清华源等主流镜像站的性能对比及一键配置方案。通过实测数据展示华为云镜像站表现最佳,下载速度达19.4MB/s,并提供sed命令、管理界面配置和Docker定制三种高效加速方案,帮助开发者快速解决插件下载慢的问题。

sql99的博客 320

逐行逐句进一步了解SurroundOcc(一)

通过分析中的模型构建过程,理解了从配置文件到模型实例化的整个流程。构建过程的核心是通过build和等函数,逐步将配置文件解析并生成模型的各个模块对象,最终组合成一个完整的模型结构。这一过程涉及多个类和函数的调用,其中函数是生成对象的关键,它能够从配置字典中提取必要信息并生成对应的类实例。

lovely_yoshino的博客 8112

QMimeData

将与mimeType给出的MIME类型关联的数据设置为指定的数据。对于最常见的数据类型,可以调用更高级别的函数setText()、setHtml()、setUrls()、setImageData()、setColorData()。通用data()获取器和便捷函数(text(),html(),urls(),imageData()和colorData())调用此函数。对于最常见的数据类型,可以使用hasText()、hasHtml()、hasUrls()、hasImage()、hasColor()。

hw5230的博客 726

从零玩转显示屏:手把手教你用Arduino驱动SPI屏幕(附引脚定义图)

本文提供了一份详尽的Arduino驱动SPI屏幕的入门指南。从SPI接口的核心引脚定义(如DC、RESET)与RGB接口的区别讲起,手把手指导硬件连接与软件库配置,并最终通过一个天气显示器实战项目,帮助读者掌握驱动SPI屏幕、显示RGB色彩内容的核心技能。

weixin_29189987的博客 132

Qt实现鼠标拖放(drag/drop)

Qt拖放官方例程: Qt5.12.9\Examples\Qt-5.12.9\widgets\draganddrop Qt拖放豆子教程: Qt学习之路(52): 拖放技术之一 Qt学习之路(53): 拖放技术之二 Qt学习之路(54): 自定义拖放数据对象 Qt 学习之路 2(52):使用拖放 Qt 学习之路 2(53):自定义拖放数据 ...

$firecat利白的代码足迹$ 1737

PID调参避坑手册:用APM/PX4飞控让无人机稳如老狗

本文提供了一份针对APM/PX4飞控的PID调参实战指南。文章从理解PID控制原理出发,详细解析了级联控制结构,并给出了从内环到外环的五步调参流程与数据日志分析方法,帮助无人机爱好者避开常见误区,实现稳定飞行。

red88的博客 875

ADS负载牵引仿真避坑指南:从零开始搞定Loadpull模板设置

本文是一份针对ADS负载牵引仿真的深度避坑指南,详细解析了Loadpull模板从初始化配置到结果解读的全过程。文章重点阐述了如何根据设计目标灵活设置扫描圆、采样点等关键参数,以解决仿真不收敛、结果不完整等常见问题,并指导读者在功率与效率之间做出理性权衡,最终提取出用于匹配网络设计的最优负载阻抗。

weixin_29234423的博客 598

Learning Qt 5! (14):拖放

Qt 学习之路 2(52):使用拖放:使用系统提供的拖放对象QMimeData进行拖放数据的存储。 代码的例子来自 C++ GUI Programming with Qt4, 2nd Edition,有空应学习一下此书。 QMimeData的用法:比如使用QMimeData::setText()创建文本,使用QMimeData::urls()创建 URL 对象等。 Qt 学习之路 2(53):自定...

随便写写 326

EEMD算法原理及应用

本博客主要概括EEMD算法的背景、原理以及应用,利用EEEMD对信号进行分解,然后选择有用的IMF分量进行叠加以完成信号的重构,从而实现对信号降噪。本文配套的源代码见文中链接,可供大家免费下载。

总结论文中的算法并给出论文的复现代码 4万+

QT6(54)6.4 拖放事件与拖放操作:本节例题程序是支持对电脑中图片的拖放操作,并显示图片。

(189)(190)

zhangzhangkeji的博客 297

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Qt:54---自定义Qt Designer插件

一、创建Qt Designer Widget插件 Qt提供两种设计插件的API,可以用于扩展Qt的功能 高级API:用于设计插件以扩展Qt的功能,例如定制数据库驱动、图像格式、文本编码、定制样式等。Qt有大量采用了插件,单击Qt Creator的主菜单栏的“Help” ==>“About Plugins”菜单项,会显示Qt Creator里已经安装的各种插件 低级API:用于创建插件...

董哥的黑板报 2299

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

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

拖放 Drag and Drop,有时又被称为 DnD,是现代软件开发中必不可少的一项技术。它提供了一种能够在应用程序内部甚至是应用程序之间进行信息交换的机制,并且,操作系统与应用程序之间进行剪贴板的内容交换,也可以被认为是 DnD 的一部分。   DnD 其实是由两部分组成的:Drag 和 Drop。Drag 是将被拖放对象“拖动”,Drop 是将被拖放对象“放下”,前者一般是一个按下鼠标的过

wuqinxiang的专栏 1365

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Qt学习路线

找到一篇比较全面的Qt学习规划,留下来备用。 链接地址:http://www.qter.org/thread-629-1-1.html 第一篇 序 第二篇 Qt简介 第3篇Hello, world! 第4篇 信号槽 第5篇 自定义信号槽 第6篇 Qt模块简介 第7篇MainWindow 简介 第8篇 添加动作 第9篇 资源文件 第10篇 对象模型 第11篇 布局管理器 第12篇 菜单栏、工具栏和状...

qq_40754866的博客 3870

54黑马QT笔记之使用Qt5版本进行线程画图

54黑马QT笔记之使用Qt5版本进行线程画图 1 线程绘图例子 这里我们使用Qt5版本进行线程绘图,该例子不算难,步骤就是上一篇文章的步骤。这里只需要注意一下,当我们从子线程处理完数据后,通过信号传参将画好的数据image传出来,赋值给主线程的image(两者不一样),然后当主线程要在窗口绘图时,必须重写绘图事件。 2 代码 1)自定义类头文件: #ifndef MYTHREAD_H #define MYTHREAD_H #include <QObject> #include <QIma

weixin_44517656的博客 771

Qt学习之路系列教程目录

导语 《Qt 学习之路》是在网络上受到一定欢迎的 Qt 入门教程。只是这个系列便携与 2009 年,至今已经有三年多的时间。今天的 Qt 有了很大的变化,包括 Qt Quick 的加入、Qt 底层架构的改变,更重要的是 Qt 5 的发布。本系列文章将会是《Qt 学习之路》的一次升级和修订,着重关注于 Qt 5,同时会结合 Qt 4 进行讲解。希望这个系列也能够像前面一个版本那样,能够

MachineLP的专栏 3万+

QT自学过程记录(1):为什么学习QT,课程安排以及QT安装教程

自学视频来源B站,是传智播客黑马程序员的课程。B站网址:https://www.bilibili.com/video/av53077699; QT下载安装教程都可以参考这个文章:https://jingyan.baidu.com/article/d5c4b52baa73a5da560dc5f9.html; 我自己下载安装的软件包还有找的一些学习资料等,可以参考这个文章:https://blog...

FightingBoom的博客 1910
上一篇: Qt学习之路(53): 拖放技术之二
下一篇: Qt学习之路(55): 剪贴板操作
flowingFire2012
博客等级 码龄14年 6粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值