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

这篇具有很好参考价值的文章主要介绍了【Qt】Qt中的拖放操作实现——拖放文件以及自定义拖放操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


文章参考《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】Qt中的拖放操作实现——拖放文件以及自定义拖放操作

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

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

完整代码可下载:https://download.csdn.net/download/sinat_41752325/87378359。文章来源地址https://www.toymoban.com/news/detail-417922.html

到了这里,关于【Qt】Qt中的拖放操作实现——拖放文件以及自定义拖放操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 实验6-cp –r系统命令的实现--源路径(目录)中的所有文件和子目录,以及子目录中的所有内容,全部拷贝到目标路径(目录)中--操作系统实验

    掌握Linux目录操作方法,包括打开目录、关闭目录、读取目录文件 掌握Linux文件属性获取方法,包括三个获取Linux文件属性的函数、文件属性解析相关的宏 掌握POSIX与ANSI C文件I/O操作方法,包括打开文件、关闭文件、创建文件、读写文件、定位文件 利用POSIX API(文件操作也可

    2024年02月08日
    浏览(54)
  • Ubuntu22.04 在 VMware 17 无法实现拖放复制操作解决办法

    环境: 主机:Windows10 虚拟机软件:VMware Workstation Pro 17.0 虚拟机系统:Ubuntu Desktop 22.04 LTS 软件:open-vm-tools (open-vm-tools-desktop) 2023.07.04更新(请看完下面另外的内容再来看这个): 在最近的使用中发现一个问题,因为屏幕分辨率和显示器大小的问题,需要将系统缩放设置成1

    2024年03月24日
    浏览(58)
  • WPF怎么实现文件拖放功能winform怎么实现拖拽功能

    WPF怎么实现文件拖放功能winform怎么实现文件拖拽功能,在管理员模式下wpf winform怎么实现文件的拖拽功能 WPF实现文件拖放功能,正常情况并没有什么问题,但是如果你的程序使用管理员身份启动,你就会发现文件拖放功能就会失效。同样winform使用管理员身份启动,你就会发

    2024年02月10日
    浏览(43)
  • QT实现连接MySQL数据库以及查询等操作

    功能包含数据库的增删改查和界面的显示,因为没有用.ui文件所以控件的位置都是手动设置的,写的有点费劲 首先打开Navicat,新建一个名字为bak_db的数据库,然后新建查询导入下面的sql语句: 然后刷新显示表已经创建好了,接下来就开始进行操作了: 文件结构 源码在我的

    2024年02月04日
    浏览(66)
  • 安装了VMware Tools,但无法实现文件的拖拽和复制粘贴---解决方案

    安装了VMware Tools,但无法实现文件的拖拽和复制粘贴---解决方案 - octal_zhihao - 博客园 (cnblogs.com) 环境:Windows11,VMware16Pro,Ubuntu20.04 我给虚拟机装好Ubuntu系统后,它默认是安装好vmtools的 而且这些选项默认是勾选的,但是我无法实现宿主机和虚拟机之间文件的拖拽和复制粘贴

    2024年02月05日
    浏览(84)
  • Qt 实现压缩文件、文件夹和解压缩操作zip

    通过Qt自带的库来实现,使用多线程方式,通过信号和槽来触发压缩与解压缩,并将压缩和解压缩结果回传过来。 使用的类: 1、在.pro文件中添加模块gui-private 若未cmake工程,需要在CMakeList.txt中添加 待验证: 1、中文路径,文件名含有中文 2、隐藏文件夹,.dir和…dir,例如:

    2024年02月14日
    浏览(45)
  • PyQt6 使用Qt Designer实现简单的界面,以及ui文件转py文件

    前言,主要通过参考并总结两篇文章中的部分内容,参考文章一 参考文章二 新增一个用户注册界面,包含用户名,密码,性别,手机号,点击注册按钮时,弹出一个对话框,提示恭喜 “{用户输入的用户名}” 注册成功。但是无奈还没找出获取最新输入用户名的值,就简单做

    2024年02月04日
    浏览(50)
  • Openssl数据安全传输平台016:在QT中的数据库操作+在项目中的设计与实现

    在Qt中进行数据库操作需要使用的类: QSqlDataBase 属于的模块: sql 使用这个类可以创建出一个连接数据库服务器的实例 单例

    2024年02月06日
    浏览(51)
  • Qt C++拖放事件探索之旅:多方法深入解析

    拖放事件(Drag and Drop Events)是指在图形用户界面(Graphical User Interface,简称GUI)中,用户通过鼠标或触摸屏拖动一个对象,并将其放置到另一个位置或对象上的过程。在Qt C++中,拖放事件涉及到一系列类和方法,用于处理此类交互。 拖放事件的核心组成部分包括以下几个概

    2024年02月01日
    浏览(48)
  • ElasticSearch进阶:多种查询操作,各种ES查询以及在Java中的实现

    目录 前言 1 词条查询 1.1 等值查询-term 1.2 多值查询-terms 1.3 范围查询-range 1.4 前缀查询-prefix 1.5 通配符查询-wildcard 2 复合查询 2.1 布尔查询 2.2 Filter查询 3 聚合查询 3.1 最值、平均值、求和 3.2 去重查询 3.3 分组聚合 3.3.1 单条件分组 3.3.2 多条件分组 3.4 过滤聚合 ElasticSearch 第一篇

    2024年02月02日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包