【Qt】Qt中的拖放操作实现——拖放文件以及自定义拖放操作

2023-11-17


文章参考《Qt Creator快速入门(第三版)》。


Qt的拖放操作

拖放操作分为拖动Drag和放下Drop,Qt提供了强大的拖放机制,可在帮助文档中通过Drag and Drop关键字查看。

在Qt中,数据拖动时会被存储为MIME类型(Multipurpose Internet Mail Extensions)。Qt提供QMimeData类表示MIME类型的数据,并使用QDrag类完成数据的转移,整个拖放操作是在几个鼠标事件和拖放事件中完成的。

拖放事件:

  • dragEnterEvent() 拖动进入事件;
  • dropEvent()放下事件;

使用拖放打开文件

当鼠标拖拽一个数据进入主窗口时, 会触发dragEnterEvent()事件,可以使用event->mimeData()获取其中的MIME数据;然后使用QMimeData::hasUrls()可以查看是否包含URL路径,如果是拖入文件实际就是拖入了它的路径。如果包含URL就接收event->acceptProposedAction(),否则就忽略该事件event->ignore()

acceptProposedAction()表示将放置操作设置位建议的操作。

当松开鼠标左键,将数据放到主窗口中就会触发dropEvent()事件,使用event->mimeData()获取MIME数据,判断数据中是否有URL,如果有的话就获取URL列表。获取到URL后就可以使用QFile文件操作读取文件并显示到textEdit中。

注意需要在构造函数中添加一行语句:setAcceptDrops(true);表示当前部件接收放下事件。

具体实现步骤:

首先在头文件中添加拖放事件的声明。

    void dragEnterEvent(QDragEnterEvent *event) override;
    void dropEvent(QDropEvent *event) override;

在.cpp文件中实现这两个函数。

void Widget::dragEnterEvent(QDragEnterEvent *event)
{
    // 拖动进入事件
    if(event->mimeData()->hasUrls())  // 数据中是否包含URL
    {
        event->acceptProposedAction();  // 如果数据中包含URL,就接收动作
    }
    else
    {
        event->ignore();  // 如果数据中不包含URL,就忽略该事件
    }
}

void Widget::dropEvent(QDropEvent *event)
{
    // 放下事件
    const QMimeData *mimeData = event->mimeData();  // 获取MIME数据
    if(mimeData->hasUrls())  // 如果数据中包含URL
    {
        QList<QUrl> urlList = mimeData->urls();  // 获取URL列表
        // 将其中的第一个URL表示为本地文件路径
        QString fileName = urlList.at(0).toLocalFile();  // toLocalFile()转换未本地文件路径
        if(!fileName.isEmpty())
        {
            // 文件路径不为空
            QFile file(fileName);
            if(!file.open(QIODevice::ReadOnly))
                return;
            QTextStream in(&file);
            ui->textEdit->setText(in.readAll());  // 将文件中的所有内容读入到控件中
        }
    }
}

QMimeData类提供了几个函数处理常见的MIME数据,如下:

测试函数 获取函数 设置函数 MIME类型
hasText() text() setText() text/plain
hasHtml() html() setHtml() text/plain
hasUrls() urls() setUrls() text/url-list
hasImage() imageData() setImageData() image/*
hasColor() colorData() setColorData() application/x-color

自定义拖放操作

如下实例实现随意移动窗口中的图片。

首先,重写几个事件处理函数。

    // 重写事件处理函数
    void mousePressEvent(QMouseEvent *event) override;  // 鼠标按下事件
    void dragEnterEvent(QDragEnterEvent *event) override;  // 拖动进入事件
    void dragMoveEvent(QDragMoveEvent *event) override;  // 拖动事件
    void dropEvent(QDropEvent *event) override;  // 放下事件

然后,在构造函数中编写如下代码。

    // 设置窗口部件可以接收拖入操作
    setAcceptDrops(true);
    // 标签添加图片
    QPixmap pix(":/logo");
    ui->label->setPixmap(pix);
    // 标签大小设置为图片大小
    ui->label->resize(pix.size());
    // 移动标签
    ui->label->move(100,100);
    // 设置当窗口关闭时销毁图片
    ui->label->setAttribute(Qt::WA_DeleteOnClose);

最后,实现上面的几个事件处理函数

Ⅰ、先实现鼠标按下事件,在鼠标按下事件处理函数中主要实现自定义的MIME类型数据,并执行拖动操作。处理过程大致分为6步:

  1. 获取鼠标指针所在处的部件的指针,并强制转换为QLabel,使用inherits()判断是否是QLabel标签,如果不是直接返回。
  2. 在拖动的数据中包含图片数据和它的位置信息,需要使用自定义的MIME类型,其中位置信息是当前鼠标指针的坐标减去图片左上角的坐标得到的差值。
  3. 创建QMimeData类对象指针,使用自定义的MIME类型,将要拖动的数据放入QMimeData对象中。
  4. 要移动数据,必须创建QDrag类对象,然后为QDrag对象添加QMimeData数据;使移动中一直显示图片,需要使用setPixmap()函数为QDrag设置,并且使用setHotSpot()指定鼠标在图片上单机的位置,如果不设置这个,在拖动图片过程中指针会位于图片的左上角。
  5. 在移动图片的过程中希望原来的图片有所改变可以看出来正在被操作,所以添加一层阴影。
  6. 执行拖动操作,需要使用QDrag::exec(),它不会影响主事件循环,这时的界面不会被冻结,exec()函数可以设定支持的放下动作和默认的放下动作,比如支持移动Qt::MoveAction,支持复制操作Qt::CopyAction。调用acceptProposedAction()函数时使用的默认的操作。exec()的返回值由dropEvent()中的设置决定。

示例代码如下:

void MainWindow::mousePressEvent(QMouseEvent *event)  // 鼠标按下事件
{
    // 1. 获取图片
    // 将鼠标指针所在位置的部件强制转换为QLabel类型
    QLabel *child = static_cast<QLabel*>(childAt(event->pos()));  // childAt()返回指定坐标处的可见子部件,如果指定位置没有可见的子部件,就返回nullptr
    if(child == Q_NULLPTR)
    {
        qDebug() << tr("位置(%1,%2)处没有子部件!").arg(event->pos().x()).arg(event->pos().y());
        return;
    }
    if(!child->inherits("QLabel"))  // 判断得到的这个部件是不是继承QLabel
    {
        qDebug() << tr("当前部件不是QLabel标签部件");
        return;
    }
    // 获取QLabel中的标签
    QPixmap pix = *child->pixmap();
    // 2. 自定义MIME类型
    QByteArray itemData;  // 创建字节数组
    QDataStream dataStream(&itemData,QIODevice::WriteOnly);  // 创建数据流
    // 将图片信息、位置信息输入到字节数组中
    dataStream <<  pix << QPoint(event->pos() - child->pos());
    // 3. 将数据放入到QMimeData中
    QMimeData *mimeData = new QMimeData;  // QMimeData对象用来存放要移动的数据
    // 将字节数组放入到QMimeData中,MIME类型是自己定义的
    mimeData->setData("myimage/png",itemData);
    // 4. 将QMimeData数据放入QDrag中
    QDrag *drag = new QDrag(this);  // 创建QDrag,用来移动数据
    drag->setMimeData(mimeData);
    // 设置在移动过程中显示图片
    drag->setPixmap(pix);
    //设置拖动时鼠标指针的位置不变
    drag->setHotSpot(event->pos() - child->pos());

    // 5. 给原始图片添加阴影
    QPixmap tmpPixmap = pix;
    QPainter painter;
    painter.begin(&tmpPixmap);
    // 在图片的外界觉醒中添加一层透明的淡黑形成阴影效果
    painter.fillRect(pix.rect(),QColor(127,127,127,127));
    painter.end();
    // 在移动图片过程中,让原图片添加一层黑色阴影
    child->setPixmap(tmpPixmap);

    // 6. 执行拖放操作
    // 设置拖放可以是移动和复制操作,默认是复制操作
    if(Qt::MoveAction == drag->exec(Qt::CopyAction | Qt::MoveAction,Qt::CopyAction))
    {
        child->close();  // 如果是移动操作,拖放完成后关闭原标签
    }
    else
    {
        child->show();  // 如果是复制操作,拖放完成后显示标签
        child->setPixmap(pix);  // 显示原标签,不再使用阴影
    }
}

Ⅱ、再处理拖动进入和拖动事件,在这两个事件处理函数中,先判断拖动的数据中是否有自定义的MIME类型的数据,如果有,就执行移动动作。示例代码:

void MainWindow::dragEnterEvent(QDragEnterEvent *event)  // 拖动进入事件
{
    // 判断是否有自定义的MIME数据,如果有,就进行移动操作
    if(event->mimeData()->hasFormat("myimage/png"))
    {
        event->setDropAction(Qt::MoveAction);  // 指定移动操作
        event->accept();
    }
    else
    {
        event->ignore();
    }
}

void MainWindow::dragMoveEvent(QDragMoveEvent *event)  // 拖动事件
{
    // 判断是否有自定义的MIME数据,如果有,就执行移动操作
    if(event->mimeData()->hasFormat("myimage/png"))
    {
        event->setDropAction(Qt::MoveAction);  // 指定移动操作
        event->accept();
    }
    else
    {
        event->ignore();
    }
}

Ⅲ、最后处理放下事件,使用字节数组获取拖放的数据,然后获取图片数据和位置信息,并使用这些数据设置新建的标签。示例代码:

void MainWindow::dropEvent(QDropEvent *event)  // 放下事件
{
    // 放下事件,判断是否有自定义的MIME类型的数据,如果有就获取这些数据并将图片显示出来
    if(event->mimeData()->hasFormat("myimage/png"))
    {
        QByteArray itemData = event->mimeData()->data("myimage/png");
        QDataStream out(&itemData,QIODevice::ReadOnly);
        QPixmap pix;
        QPoint ptOffset;
        // 将MIME数据读入到QPixmap和QPoint中
        out >> pix >> ptOffset;
        // 新建标签,添加图片,并根据图片大小设置标签大小
        QLabel *label = new QLabel(this);
        label->setPixmap(pix);
        label->resize(pix.size());
        // 让图片移动到放下的位置,如果不设置,图片会默认显示在窗口左上角
        label->move(event->pos() - ptOffset);
        label->show();
        label->setAttribute(Qt::WA_DeleteOnClose);
        event->setDropAction(Qt::MoveAction); // 设置移动过程中的操作,Qt::MoveAction是移动,如果需要复制操作,改成Qt::CopyAction
        event->accept();
    }
    else
    {
        event->ignore();
    }
}

运行程序显示结果:

在这里插入图片描述

将拖动进入、拖动、放下事件中的Qt::MoveAction改为Qt::CopyAction运行后显示结果:

在这里插入图片描述

完整代码可下载:https://download.csdn.net/download/sinat_41752325/87378359

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Qt】Qt中的拖放操作实现——拖放文件以及自定义拖放操作 的相关文章

  • QWidget::showMinimized() 不起作用

    在 Ubuntu 13 04 上 如果使用QWidget showMinimized 为了最小化窗口 我发现通过单击系统任务栏上的应用程序图标恢复它后 调用QWidget showMinimized 无法工作 connect minimum
  • 使用嵌入qt的mysql?

    我正在尝试使用嵌入 QT 的 mysql 我已经有一个与 mysqld 链接的 Qt mysql 插件 该插件可以很好地加载嵌入式数据库 但 QT 没有简单的方法来设置 dataDir 等嵌入式选项 我在这里看到 http doc qt i
  • 当从 html 文件读取 Unicode 内容时,为什么 Unicode 字体在 QTextBrowser 中无法正确显示?

    我正在读一本html文件 该文件基本上包含Unicode案文如下 b akko sati kru akkh ti khy abbahati b h b But the QText浏览器不解释Unicode字体 所以QText浏览器显示如下
  • 面向 Delphi 开发人员的 Qt

    有人知道为 Delphi C Builder VCL 开发人员解释 Qt 的书籍或教程吗 对于具有该背景的开发人员来说 学习 Qt 的最佳方法是什么 我对如何使用 Qt 完成我知道如何在 Delphi 中完成的事情特别感兴趣 例如 Qt 相
  • 选择合适的IDE

    您会推荐使用以下哪种 IDE 语言来在 Windows 下开发涉及识别手势并与操作系统交互的项目 我将使用 OpenCV 库来执行图像处理任务 之后 我将使用 win32 API 或 NET 框架与操作系统交互 具体取决于您建议的工具 性能
  • QChart 对大数据集无响应

    我的这段代码适用于高达 1000 的数据大小 现在我用 65536 个点对其进行了测试 series new QLineSeries QList
  • Qt 编译器标志顺序

    我的目标是消除某些类型的编译器警告 我发现可以通过在 pro 文件中添加编译器标志来做到这一点 QMAKE CXXFLAGS Wno unused variable Wno reorder 问题是它们被添加在 Qt 构建系统生成的标志之前
  • QObject多重继承

    我正在尝试在 C Qt 类中使用 mix 来提供一大堆具有通用接口的小部件 该接口是以这样的方式定义的 如果它被定义为其他小部件类的基类 那么小部件本身将具有这些信号 class SignalInterface public QObject
  • 将 C++ 代码(本机客户端)移植到浏览器(Web 应用程序)

    我有一个使用 Qt creator SDK 编写的 C 模块 我想将此代码移植到任何网页上运行 而不会对最终用户损害源代码 用户应该能够在任何浏览器 Chrome Firefox Safari Explorer 上看到此模块的输出 而无需安
  • PyQt 和 QSignalMapper/lambdas - 多个信号,单槽

    我在 PyQt 的菜单上有一个操作列表 每个操作对应我想要显示的每个不同的提要 所以我有一个 Y 将活动源设置为 Y Z 将其设置为 Z 等等 对于网络漫画阅读程序 我的菜单上都有 并且觉得自动化方法可能更好 而不是每次都打字 类似于将其添
  • QFileDialog 作为 TableView 的编辑器:如何获取结果?

    我正在使用一个QFileDialog作为某些专栏的编辑QTableView 这基本上有效 对一些焦点问题取模 请参阅here https stackoverflow com questions 22854242 qfiledialog as
  • 运行最新版本时没有“最新”消息?

    我正在尝试使用Sparkle https sparkle project org与 Qt Go 的绑定 https github com therecipe qt app 闪光 m import
  • 构建qt程序时未定义的符号:找不到qt_version_tag

    我正在学习Qt5 6 我正在使用 Ubuntu 14 4 当我链接我的程序时 出现以下错误 undefined reference to qt version tag 在 CMakeLists txt 中 link libraries Qt
  • PyQt:如何通过匿名代理使用网页

    这真让我抓狂 我想在 QWebPage 中显示一个 url 但我想通过匿名代理来实现 Code setting up the proxy proxy QNetworkProxy proxy setHostName 189 75 98 199
  • Qt - 意外的 GDB 退出

    我正在尝试开发一个应用程序 该应用程序创建图像并使用双线性插值填充颜色像素 然后显示它 到目前为止我的代码如下 include
  • 仅当从 Qt 连接时网页返回 HTTP 406 错误

    我有一个测试页面设置http mlecturedownload com test qt php http mlecturedownload com test qt php有以下代码
  • Qt QML MenuItem iconSource不显示

    我有一个非常简单的设置只是为了说明问题 import QtQuick Controls 1 4 import QtQuick Window 2 2 ApplicationWindow visible true width 640 heigh
  • 使用信号和槽更新指针

    我对 Qt 很陌生 请帮我解决这个问题 我正在使用线程在后台执行密集操作 同时我想更新 UI 所以我使用 SIGNALS 和 SLOTS 为了更新 UI 我发出一个信号并更新 UI 让我们考虑下面的示例代码 struct sample QS
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的

随机推荐

  • 【毕设教程】基于python实现网络爬虫

    文章目录 0 前言 1 简介 2 交互界面 3 爬虫部分 4 数据存储 5 最后 0 前言 Hi 大家好 这里是丹成学长的毕设系列文章 对毕设有任何疑问都可以问学长哦 这两年开始 各个学校对毕设的要求越来越高 难度也越来越大 毕业设计耗费时
  • Linux系统安装python3.8与卸载教程

    Linux系统安装python3 8与卸载教程 一 安装python解释器 1 获取系统版本信息 首先 查看Linux系统版本信息 root oldboy cat proc version Linux version 4 18 0 240
  • python三行代码生成自己专属二维码

    利用pip安装库MyQR库 pip install MyQR 代码 from MyQR import myqr myqr run words https blog csdn net qq 29023939 spm 1001 2014 300
  • el-table多选框点击表格选中和取消

    div div
  • 在 Python 中使用 OpenAI 的新 Whisper API 进行语音转文本

    您是否厌倦了手动转录数小时的录音 您想节省时间并提高工作效率吗 然后 您会很高兴听到 OpenAI 用于语音到文本转换的新 Whisper API 借助这项尖端的 AI 技术 您现在可以在 Python 程序中轻松地将音频文件转换为文本 让
  • 【Transformer】Self-Attention with Relative Position Representations及实现pytorch代码

    在Transformer中加入可训练的embedding编码 使得output representation可以表征inputs的时序 位置信息 这些embedding vectors在计算输入序列中的任意两个单词i j之间的key和val
  • 深入浅出主流的几款小程序跨端框架原理

    目前 小程序在用户规模及商业化方面都取得了极大的成功 微信 支付宝 百度 字节跳动等平台的小程序日活都超过了3亿 我们在开发小程序时仍然存在诸多痛点 小程序孱弱简陋的原生开发体验 注定会出现小程序增强型框架 来提升开发者开发体验 各家厂商小
  • 全链路Python环境迁移

    全链路Python环境迁移 在当前的Python环境中 安装一些库以后 如果换了一套Python环境 难道再来一次不停的pip install 当然不是 第一步 使用pip freeze 冻结 备份当前Python库的环境 pip free
  • linux环境配置以后生效,Linux中修改环境变量及生效方法

    Linux中修改环境变量及生效方法 在 etc profile文件中添加变量 对所有用户生效 永久的 用VI在文件 etc profile文件中增加变量 该变量将会对Linux下所有用户有效 并且是 永久的 要让刚才的修改马上生效 需要执行
  • 专门为码农朋友量身打造的笔记软件-Boostnote

    感谢参考原文 http bjbsair com 2020 04 01 tech info 18432 html 前言 很多人好奇程序猿是如何记笔记的 如果有了解过可能会知道 Markdown 都知道Markdown 是一个轻量级的标记语言
  • Unity插件DlibFaceLandmarkDetector的使用心得

    Unity小白日记 1 DlibFaceLandmarkDetector Unity官方插件 在插件商店里即可找到 但是对于我这种只是用来试用一下效果的小白来说还是有点小贵 更别说还是美刀 如果如果有感兴趣的童鞋可以在CSDN查找下载 学习
  • Python:variable in function(argument、function) name should be lowercase 处理方式

    用pyCharm时 常会出现警告信息 function name should be lowercase 函数名应该是小写 字母 argument name should be lowercase 参数名应该是小写字母 variable i
  • 检查电脑显卡配置是否支持CUDA

    计算机 管理 系统工具 设备管理器 显示适配器 https developer nvidia com cuda gpus
  • SpringMVC:从入门到精通,7篇系列篇带你全面掌握--五.JSR303和拦截器

    Welcome Huihui s Code World 接下来看看由辉辉所写的关于SpringMVC的相关操作吧 目录 Welcome Huihui s Code World 一 JSR303是什么 二 使用JSR303的优势 三 使用JS
  • 台式计算机 无线接收,台式电脑无线接收器插上连不上网怎么处理

    大家好 我是时间财富网智能客服时间君 上述问题将由我为大家进行解答 台式电脑无线接收器插上连不上网的处理方方法 1 首先 您将您的无线网接收器插入到您的台式机中 2 接下来 您看看有没有反应 是否可以接收到wifi 如果没有找到 那么它需要
  • jsp 生成静态页面

    file name 文件名及文件之后的参数 最好为a jsf fileId aaaa path 文件所在的路径 相对于根目录而言的 realName文件要保存的名字 realPath文件要保存的真实路径 默认与文件所在的目录相同 publi
  • 学生正版Altium Designer许可证到期怎么再申请

    学生如何使用正版Altium Designer软件 适用于老师 学生 校友等等 目录 一 前情提要 二 许可证延期步骤 2 1 重要前提 2 2 许可证申请 2 3 申请完成 一 前情提要 如果不知道怎么安装学生版AD 可点击以下链接学生如
  • Azure简单使用教程

    这段时间在做调研 我们小组负责了解微软的Azure的情况 按照官网教程 我搭建了一遍官网示例 汽车价格预测 过程如下 一 创建模型 1 获取数据 若要进行机器学习 首先需获取数据 可以使用机器学习工作室随附的多个示例数据集 也可以从多种源导
  • 什么是稀疏数组?

    文章目录 稀疏数组 一 定义 二 代码实现 1 二维数组转稀疏数组 2 稀疏数组转二维数组 3 完整代码 总结 稀疏数组 稀疏数组一般使用在一个二维数组存储着大量无效数据的场景中 举个例子 一个二维数组存储了100个数据 有效数据只有2个
  • 【Qt】Qt中的拖放操作实现——拖放文件以及自定义拖放操作

    文章目录 Qt的拖放操作 使用拖放打开文件 自定义拖放操作 文章参考 Qt Creator快速入门 第三版 Qt的拖放操作 拖放操作分为拖动Drag和放下Drop Qt提供了强大的拖放机制 可在帮助文档中通过Drag and Drop关键字