Qt--拖放操作

2023-10-27

Qt–拖放操作

1 使用拖放打开文件

将桌面上的.txt文件拖入程序打开。
新建Widget项目,项目名称为mydragdrop,类名和积累保持MainWindow和QMainWindow不变。建立完项目后,往界面上拖入一个Text Edit部件。然后在mainwindow.h文件中添加函数声明:

protected:
    void dragEnterEvent(QDragEnterEvent *event); // 拖动进入事件
    void dropEvent(QDropEvent *event);           // 放下事件

然后再mainwindow.cpp文件中添加头文件

#include <QDragEnterEvent>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QMimeData>

最后对二个事件处理函数定义

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

void MainWindow::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();
        if(!fileName.isEmpty()){                        // 如果文件路径不为空
            QFile file(fileName);     // 建立QFile对象并且以只读方式打开该文件
            if(!file.open(QIODevice::ReadOnly)) return;
            QTextStream in(&file);                      // 建立文本流对象
            ui->textEdit->setText(in.readAll());  // 将文件中所有内容读入编辑器
        }
    }
}

当鼠标拖拽一个数据进入主窗口时,就会触发dragEnterEvent()事件处理函数,从而获取其中的MIME 数据;然后查看它是否包含URL路径,因为拖入的文本文件实际上就是拖入了它的路径,这就是event→mimeData()→hasUrls()实现的功能。

如果有这样的数据,就接收它,否则忽略该事件。QMimeData类中提供了几个函数来处理常见的MIME数据,如表所列。

当松开鼠标左键,将数据放入主窗口时就会触发dropEvent()事件处理函数,这里获取了MIME数据中的URL列表。

因为拖入的只有一个文件,所以获取了列表中的第一个条目,并使用toLocalFile()函数将它转换为本地文件路径。

然后使用QFileQTextStream将文件中的数据读入编辑器中。

最后,进入 mainwindow.cpp文件,在构造函数中添加一行代码:

setAcceptDrops(true);

这样主窗口就可以接收放下事件了。这时先运行程序,然后从桌面上将一个文本文件拖入程序主窗口界面(不是里面的Text Edit部件中),可以看到文本编辑器中显示了文本文件中的内容。

在这里插入图片描述

请添加图片描述

Qt中QList<T>的用法

这里用到了Qt中QList<T>的用法
QList以列表形态存储并管理值,并能进行基于快速索引的访问,也可以进行快速的数据删除操作。

QList使用运算符将项目添加到列表

QList<QString> list;
list<<"one"<<"two"<<“three”;
//list:["one","two","three"]

QList通过比较运算符来获得返回值

if(list[0]=="boy")
	list[0]="bossa";

QList实现指针数组后,通过快速运算获取存储到QList的值。并且使用函数at()可以很容易的获得存储到列表的位置。

for( int i=0; i< list.size(); ++i)
{
		if(list.at(i)=="J")
				cout <<"J  at  position " << i  <<endl;
}


2 自定义拖放操作

下面再来看一个在窗口中拖动图片的例子,实现的功能就是在窗口中有一个图片,可以随意拖动它。这里需要使用到自定义的MIME类型。

新建Qt Widgets应用,项目名称改为 imagedrag-drop,类名和基类保持Main Window 和QMainWindow不变。完成后,在 mainwindow.h文件中对几个事件处理函数进行声明:

protected:
    void mousePressEvent(QMouseEvent *event);      // 鼠标按下事件
    void dragEnterEvent(QDragEnterEvent *event);   // 拖动进入事件
    void dragMoveEvent(QDragMoveEvent *event);     // 拖动事件
    void dropEvent(QDropEvent *event);             // 放下事件

然后再mainwindow.cpp中添加头文件:

#include <QLabel>
#include <QMouseEvent>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QPainter>
#include <QMimeData>
#include <QDrag>

在构造函数中添加如下代码:

 setAcceptDrops(true);                      // 设置窗口部件可以接收拖入
    QLabel *label = new QLabel(this);          // 创建标签
    QPixmap pix("../imagedragdrop/logo.png");
    label->setPixmap(pix);                     // 添加图片
    label->resize(pix.size());                 // 设置标签大小为图片的大小
    label->move(100,100);
    label->setAttribute(Qt::WA_DeleteOnClose); // 当窗口关闭时销毁图片

这里必须先设置部件使其可以接收拖放操作,窗口部件默认是不可以接收拖放操作的。
然后创建了一个标签﹐并且为其添加了一张图片,这里将图片放到了项目源码目录下。

下面是添加那几个事件处理函数的定义:

void MainWindow::mousePressEvent(QMouseEvent *event)   //鼠标按下事件
{
    // 第一步:获取图片
    // 将鼠标指针所在位置的部件强制转换为QLabel类型
    QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
    if(!child->inherits("QLabel")) return; // 如果部件不是QLabel则直接返回
    QPixmap pixmap = *child->pixmap();     // 获取QLabel中的图片

    // 第二步:自定义MIME类型
    QByteArray itemData;                                     // 创建字节数组
    QDataStream dataStream(&itemData, QIODevice::WriteOnly); // 创建数据流
    // 将图片信息,位置信息输入到字节数组中
    dataStream << pixmap << QPoint(event->pos() - child->pos());

    // 第三步:将数据放入QMimeData中
    QMimeData *mimeData = new QMimeData;  // 创建QMimeData用来存放要移动的数据
    // 将字节数组放入QMimeData中,这里的MIME类型是我们自己定义的
    mimeData->setData("myimage/png", itemData);

    // 第四步:将QMimeData数据放入QDrag中
    QDrag *drag = new QDrag(this);      // 创建QDrag,它用来移动数据
    drag->setMimeData(mimeData);
    drag->setPixmap(pixmap);//在移动过程中显示图片,若不设置则默认显示一个小矩形
    drag->setHotSpot(event->pos() - child->pos()); // 拖动时鼠标指针的位置不变

    // 第五步:给原图片添加阴影
    QPixmap tempPixmap = pixmap; // 使原图片添加阴影
    QPainter painter;            // 创建QPainter,用来绘制QPixmap
    painter.begin(&tempPixmap);
    // 在图片的外接矩形中添加一层透明的淡黑色形成阴影效果
    painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
    painter.end();
    child->setPixmap(tempPixmap); // 在移动图片过程中,让原图片添加一层黑色阴影

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

鼠标按下时会触发鼠标按下事件,进而执行其处理函数,这里进行了一系列操作,就像程序的注释所描述的那样,大体上可以分为6步。

第1步:先获取鼠标指针所在处的部件的指针,将它强制转换为QLabel类型的指针,然后使用inherits()函数判断它是否是QLabel类型,如果不是则直接返回,不再进行下面的操作。

第2步:因为不仅要在拖动的数据中包含图片数据,还要包含它的位置信息﹐所以需要使用自定义的MIME类型。这里使用了QByteArray字节数组来存放图片数据和位置数据。然后使用QDataStream类将数据写入数组中,。其中,位置信息是当前鼠标指针的坐标减去图片左上角的坐标而得到的差值。

第3步:创建了QMimeData类对象指针,使用了自定义的MIME类型“myimage/png”,将字节数组放入QMimeData中。

第4步:为了移动数据,必须创建QDrag类对象,然后为其添加QMimeData数据。这里为了在移动过程中一直显示图片,需要使用setPixmap()函数为其设置图片。然后使用setHotSpot()函数指定了鼠标在图片上单击的位置,这里是相对于图片左上角的位置,如果不设定这个,那么在拖动图片过程中,指针会位于图片的左上角。

第5步:在移动图片过程中我们希望原来的图片有所改变来表明它正在被操作,所以为其添加了一层阴影。

第6步:执行拖动操作,这需要使用QDrag类的exec()函数,它不会影响主事件循环,所以这时界面不会被冻结。这个函数可以设定所支持的放下动作和默认的放下动作,比如这里设置了支持复制动作Qt : :CopyAction和移动动作Qt :: MoveAction,并设置默认的动作是复制。这就是说我们拖动图片,可以是移动它,也可以是进行复制,而默认的是复制操作,比如使用acceptProposedAction()函数时就是使用默认的操作。当图片被放下后,exec()函数就会返回操作类型,这个返回值由下面要讲到的dropE-vent()函数中的设置决定。这里判断到底进行了什么操作,如果是移动操作,那么就删除原来的图片;如果是复制操作,就恢复原来的图片。
请添加图片描述

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)   // 拖动事件
{
     if (event->mimeData()->hasFormat("myimage/png")) {
             event->setDropAction(Qt::MoveAction);
             event->accept();
     } else {
         event->ignore();
     }
}

在这二个事件处理函数中,先判断拖动的数据中是否有自定义的MIME类型的数据,如果有,则执行移动动作 Qt::MoveAction

void MainWindow::dropEvent(QDropEvent *event) // 放下事件
{
    if (event->mimeData()->hasFormat("myimage/png")) {
         QByteArray itemData = event->mimeData()->data("myimage/png");
         QDataStream dataStream(&itemData, QIODevice::ReadOnly);
         QPixmap pixmap;
         QPoint offset;
         // 使用数据流将字节数组中的数据读入到QPixmap和QPoint变量中
         dataStream >> pixmap >> offset;
         // 新建标签,为其添加图片,并根据图片大小设置标签的大小
         QLabel *newLabel = new QLabel(this);
         newLabel->setPixmap(pixmap);
         newLabel->resize(pixmap.size());
   // 让图片移动到放下的位置,不设置的话,图片会默认显示在(0,0)点即窗口左上角
         newLabel->move(event->pos() - offset);
         newLabel->show();
         newLabel->setAttribute(Qt::WA_DeleteOnClose);
         event->setDropAction(Qt::MoveAction);
         event->accept();
     } else {
         event->ignore();
     }
}

在放下事件中,使用字节数组获取了拖放的数据﹐然后将其中的图片数据和位置数据读取到两个变量中,并使用它们来设置新建的标签。

请添加图片描述

上面的例子是对图片进行移动,如果要像对图片进行复制,则只需将dragEnterEvent,dropEvent,dragMoveEvent这3个函数中的event->setDropAction()函数中的参数改为Qt::CopyAction即可
在这里插入图片描述
请添加图片描述

对于拖放操作的其他应用,比如根据移动的距离来判断是否开始一个拖放操作,还有剪贴板QClioboard类,都可以通过在Drag and Drop关键字查看

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

Qt--拖放操作 的相关文章

随机推荐

  • PTA L3 题目合集(暂不更新)

    L3 001 凑零钱 30 分 01背包问题记录路径 include
  • 第三周 任务2.1 C#猜数字

    程序头部注释开始 程序的版权和版本声明部分 Copyright c 2011 烟台大学计算机学院学生 All rights reserved 文件名称 C 猜数字 作 者 薛广晨 完成日期 2011 年 09 月 11 日 版 本号 x1
  • 一文理解GPT及向ChatGPT提问的技巧

    一 什么是ChatGPT 人工智能已成为当今科技领域的一大热门话题 随着深度学习的快速发展 OpenAI团队在其GPT Generative Pre trained Transformer 模型的基础上 推出了ChatGPT 这是一种革命性
  • 红芯丑闻揭秘者 Touko 专访

    专栏 九章算法 网址 www jiuzhang com 红芯事件 近日 一则 自主研发的国产浏览器内核 红芯宣布获2 5亿C轮融资 的讯息再次将 国产自主创新 这一话题推向高潮 希冀之声群起 然好景不长 网友Touko在将红芯浏览器的exe
  • 专业修图软件 Affinity Photo mac中文功能

    Affinity Photo for mac是应用在MacOS上的专业修图软件 支持多种文件格式 包括psD PDF SVG Eps TIFF JPEG等 Affinity Photo提供了许多高级图像编辑功能 如无限制的图层 非破坏性操作
  • (六)IDEA新建工程——从0开始大数据开发实战:电影推荐系统(scala版)

    打开IntelliJ IDEA 选择菜单 File gt New gt Project 打开一个新建项目对话框 如下图所示 本教程使用Maven对Scala程序进行编译打包 所以 请点击左侧的 Maven 右侧 Create from ar
  • 英特尔cpu发布时间表_英特尔CPU路线曝光,碾压AMD和Arm就在4年后?

    来源 内容由半导体行业观察 ID icbank 编译自 Adoredtv 谢谢 我们最近不仅收到了英特尔的内部客户端CPU路线图 我们还收到了内部服务器路线图 一直延伸到2024年的roadmap 在我开始分享这个路线图的细节之前 我必须澄
  • Qt Designer UI设计布局小结

    目录 前言 1 居中布局 2 左右布局 3 上下布局 4 复杂页面布局 总结 前言 本文总结了在开发Qt应用程序时使用 Designer 进行UI布局的一些心得体会 Qt Designer是Qt提供的一个可视化界面设计工具 旨在帮助开发人员
  • Matlab 改变图像尺寸

    问题 我们在进行图像相关的实验时 需要对读取后的图片进行处理 改变图片尺寸就是其中一种处理 方法 1 imresize 利用插值方法重塑图像大小 P imread picture jpg 读取处理的图像 new P imresize P m
  • 1.1.1 Qt信号槽之connect与disconnect介绍

    关于Qt信号槽中connect与disconnect介绍 首先我们要知道 如果想要使用Qt中的信号槽机制 那么必须继承QObject类 因为QObject类中包含了信号槽的一系列操作 今天我们来讲解的是信号与槽怎么建立连接以及断开连接 一
  • Python爬虫之findall和lxml

    Python爬虫之findall和lxml 提示 前言 Python爬虫之findall和lxml 提示 写完文章后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 Python爬虫之findall和lxml 前言 一 导入包 二
  • vivo 自研鲁班分布式 ID 服务实践

    作者 vivo IT 平台团队 An Peng 本文介绍了什么是分布式ID 分布式ID的业务场景以及9种分布式ID的实现方式 同时基于vivo内部IT的业务场景 介绍了自研鲁班分布式ID服务的实践 一 方案背景 1 1 分布式ID应用的场景
  • 任务调度框架 Quartz 用法指南(超详细)

    点击关注 Java基基 2022 07 31 11 55 发表于上海 点击上方 Java基基 选择 设为星标 做积极的人 而不是积极废人 每天 14 00 更新文章 每天掉亿点点头发 源码精品专栏 原创 Java 2021 超神之路 很肝
  • C语言打印菱形

    思路 简单明了的说一下 首先我们可以将菱形分成上半部分和下半部分 用3个for循环打印上半部分 再用3个for循环打印下半部分 至于for循环里面的判断条件为什么要这样写 你记住就行了 不要问为什么 你问的话 它逻辑就是通的 define
  • 北京大学肖臻老师《区块链技术与应用》公开课笔记1——课程简介篇

    北京大学肖臻老师 区块链技术与应用 公开课笔记 课程简介篇 对应肖老师视频 click here 全系列笔记请见 click here About Me 点击进入我的Personal Page 区块链的本质是什么 观点1 区块链是下一代价值
  • VMware Workstation及CentOS-7虚机安装

    创建新的虚机 选择安装软件 这里选的是桌面版 也可以根据实际情况进行选择 等待检查软件依赖关系 选择安装位置 自主配置分区 创建一个普通用户 安装完成后重启 点击完成配置 进入登陆界面 输入账号密码进入系统
  • STM32 复合设备编写

    目的 完成一个CDC MSC的复合USB设备 可以方便在CDC MSC 复合设备三者间切换 可移植性强 预备知识 cube中USB只有两个入口 main函数中的MX USB DEVICE Init函数 init function void
  • (十七)STM32——定时器

    目录 学习目标 内容 简介 定时器分类 定时器功能介绍 计时器模式 工作过程 内部时钟选择 寄存器 配置 代码 总结 学习目标 本节内容我们来介绍一下有关定时器的知识 其实这个定时器 和我们日常接触的定时器没有什么区别 都是到了一定的时间就
  • ajax简单异步图片上传,Ajax简单异步上传图片并回显

    前台代码 上传图片按钮 选择图片 隐藏的文件选择器 图片预览 去除图片预览未选择时默认时的边框 img src img not src opacity 0 JavaScript部分 function uploadPhoto photoFil
  • Qt--拖放操作

    Qt 拖放操作 1 使用拖放打开文件 将桌面上的 txt文件拖入程序打开 新建Widget项目 项目名称为mydragdrop 类名和积累保持MainWindow和QMainWindow不变 建立完项目后 往界面上拖入一个Text Edit