欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > QT:Widget拖拽操作

QT:Widget拖拽操作

2024/12/21 23:41:48 来源:https://blog.csdn.net/qq_43441284/article/details/144447033  浏览:    关键词:QT:Widget拖拽操作

基本概念

在 Qt 中,拖拽操作(Drag and Drop)提供了一种直观的用户交互方式,用于在应用程序内部或者不同应用程序之间移动或复制数据。它涉及两个主要的动作:拖动(Drag)和放置(Drop)。
拖动是指用户在一个部件(Widget)上按下鼠标,移动鼠标来 “抓起” 数据的过程;放置是指用户将 “抓起” 的数据移动到另一个部件上并松开鼠标,将数据 “放下” 的过程。

相关类和函数

QDrag 类:用于处理拖动操作。它封装了要拖动的数据以及相关的元数据,如数据格式、拖动的鼠标光标等信息。
QMimeData 类:用于存储拖动操作中的数据。它支持多种数据格式,如文本、图像、URL 等。例如,如果你想拖动一个文本字符串,你可以将这个字符串存储在 QMimeData 中。它通过调用 setText(对于文本数据)等方法来设置数据内容。
QDragEnterEvent、QDragMoveEvent、QDropEvent 事件类:这些事件类用于在拖动操作的不同阶段传递信息。
当被拖动的对象进入一个部件的边界时,会触发 QDragEnterEvent。部件可以通过重新实现 dragEnterEvent 函数来决定是否接受这个拖动操作。例如,一个只接受文本数据拖动的部件可以在这个函数中检查 QMimeData 的数据格式是否为文本。
当被拖动的对象在部件内部移动时,会触发 QDragMoveEvent。同样,部件可以通过重新实现 dragMoveEvent 函数来处理这个事件,如更新显示的反馈信息(比如改变鼠标光标形状等)。
当被拖动的对象在部件上被释放时,会触发 QDropEvent。部件通过重新实现 dropEvent 函数来处理放下的数据,如将数据插入到一个文本编辑器部件中。

新建项目

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

往界面上拖入一个Text Edit部件

在这里插入图片描述
然后在mainwindow.h文件中添加函数声明

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

mainwindow.cpp文件中添加头文件

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

对两个事件处理函数进行定义

//拖动进入事件
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{//数据中是否包含URLif(event->mimeData()->hasUrls()){//进行接收动作event->acceptProposedAction();}else{event->ignore();//忽略该事件}}//放下事件
void MainWindow::dropEvent(QDropEvent *event)
{const QMimeData *mimedata = event->mimeData();//获取MIME数据if(mimedata->hasUrls()){QList<QUrl> urlList = mimedata->urls();//获取urlQString fileName = urlList.at(0).toLocalFile();//将第一个URL表示为本地文件路径if(!fileName.isEmpty())//如果路径不为空{QFile file(fileName);//建立Qfile 并且以只读的方式打开文件if(!file.open(QIODevice::ReadOnly)){return;}QTextStream in(&file);//创建文本流对象ui->textEdit->setText(in.readAll());//将文件所有内容读入编辑器}}}

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

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);setAcceptDrops(true);
}

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

新建项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在mainwindow.h文件中对几个事件处理函数进行声明:

protected:void mousePressEvent(QMouseEvent *event) override;void dragEnterEvent(QDragEnterEvent *event) override;void dragMoveEvent(QDragMoveEvent *event) override;void dropEvent(QDropEvent *event) override;

到mainwindow.cpp文件中添加头文件:

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

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

// MainWindow类的构造函数定义
// 这个构造函数用于创建MainWindow类的对象实例,并完成一系列与窗口初始化相关的操作
// 参数parent是一个指向QWidget类型的指针,用于指定MainWindow的父部件(parent widget)
// 在Qt中,设置父部件可以构建部件的对象树结构,方便内存管理等操作,若parent为nullptr,则该MainWindow对象为顶层窗口
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)  // 调用基类(QMainWindow)的构造函数,并传递parent参数,以初始化基类相关的属性和行为, ui(new Ui::MainWindow)  // 创建一个Ui::MainWindow类的实例指针ui,通过UI设计文件生成的Ui类通常用于方便地访问界面中的各个部件(由UI设计工具自动生成代码相关联)
{ui->setupUi(this);  // 调用由UI设计文件生成的setupUi函数,用于初始化界面上的各个部件,按照在UI设计工具中设计好的布局和属性进行设置setAcceptDrops(true);  // 设置当前MainWindow窗口能够接受拖放操作,这样窗口就可以作为拖放操作的目标部件,后续可以在相应的拖放事件处理函数中处理拖放进来的数据QLabel *label = new QLabel(this);  // 创建一个新的QLabel部件对象,它将作为当前MainWindow窗口(this表示当前MainWindow对象)的子部件,用于显示图像等内容QPixmap pix("../../logo.png");  // 创建一个QPixmap对象pix,尝试从相对路径"../logo.png"加载图像文件,如果文件存在且格式正确,pix将包含对应的图像数据,注意这里相对路径是相对于可执行文件所在目录而言的,若路径不对可能导致图像加载失败label->setPixmap(pix);  // 将刚刚加载好的图像数据(通过QPixmap对象pix表示)设置到QLabel部件label上,使得label能够显示该图像label->resize(pix.size());  // 根据图像的尺寸(由pix.size()获取)来调整QLabel部件label的大小,使其大小刚好适配要显示的图像大小,保证图像完整显示且不会出现拉伸等异常情况label->move(100, 100);  // 将QLabel部件label在其父部件(也就是当前MainWindow窗口)中的位置移动到坐标(100, 100)处,这里的坐标是相对于父部件左上角为原点的坐标系统,单位是像素,这样可以指定图像在窗口内显示的位置label->setAttribute(Qt::WA_DeleteOnClose, true);  // 为QLabel部件label设置属性,当它所属的窗口(这里就是MainWindow窗口)关闭时,自动删除这个QLabel部件,有助于内存的合理清理,避免内存泄漏等问题
}

必须先设置部件使其可以接受拖放操作,窗口部件默认是不可以接受拖放操作的,必须先设置部件使其可以接受拖放操作,窗口部件默认是不可以接受拖放操作的,注意图片路径的选择

鼠标按下事件void MainWindow::mousePressEvent(QMouseEvent *event)


//鼠标按下事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{// 1、获取图片// 通过事件发生位置获取对应的子部件,并转换为QLabel类型,如果转换失败(即不是QLabel类型)则直接返回// 这里假设childAt函数根据给定的坐标返回对应的子部件,event->position().toPoint()用于获取事件发生的坐标点QLabel *child = static_cast<QLabel*>(childAt(event->position().toPoint()));if(!child->inherits("QLabel")){return;}// 获取该QLabel部件上显示的图片(QPixmap类型),后续的拖放操作等会基于这个图片进行处理QPixmap pixmap = child->pixmap();// 2、自定义MIME类型// 创建一个字节数组itemData,用于存储要通过拖放传递的数据QByteArray itemData;// 以只写模式创建一个数据流对象dataStream,将字节数组itemData与之关联,以便后续往里面写入数据QDataStream dataStream(&itemData,QIODevice::WriteOnly);// 将获取到的图片(pixmap)以及鼠标相对于子部件(child)的位置(通过计算事件位置与子部件位置的差值得到)// 写入到数据流中,这样在拖放接收端可以解析出这些信息来进行相应处理dataStream << pixmap << QPoint(event->pos() - child->pos());// 3、将数据放入QMimeData中// 创建一个QMimeData对象,QMimeData用于存储在拖放操作中要传递的数据以及相关的MIME类型信息QMimeData *mimeData = new QMimeData;// 设置自定义的MIME类型数据// 将之前准备好的包含图片和位置信息的字节数组itemData设置到该MIME类型对应的数据中mimeData->setData("../../gift.png",itemData);// 4、将QMimeData数据放入QDrag中// 创建一个QDrag对象,用于管理整个拖放操作,传入当前的父对象指针(this通常表示当前类的实例指针)QDrag *drag = new QDrag(this);// 将包含拖放数据的QMimeData对象设置到QDrag中,这样在拖放过程中接收方就能获取到相应的数据了drag->setMimeData(mimeData);// 设置拖放操作时显示的图片,这里直接使用之前获取的原始图片pixmap作为拖放时显示的图标,方便用户直观看到拖放的内容drag->setPixmap(pixmap);// 设置拖放操作的热点位置,这里(event->pos() - child->pos()),表示鼠标相对于子部件的位置作为热点位置,// 热点位置通常决定了在放下拖放内容时的精确对齐等相关操作drag->setHotSpot(event->pos() - child->pos());// 5、给原图添加阴影// 创建一个临时的图片对象tempPixmap,并初始化为与原始图片pixmap相同的内容,后续将在这个临时图片上进行绘制阴影的操作QPixmap tempPixmap = pixmap;// 创建一个QPainter对象,用于在图片上进行绘制操作,通过传入临时图片的指针来关联要绘制的目标QPainter painter;painter.begin(&tempPixmap);// 使用灰色(RGB值为127,127,127)填充整个图片区域,以此来模拟阴影效果,这里填充的是整个图片矩形范围,可能实际效果不一定符合期望的阴影样式,// 可以根据具体需求调整绘制阴影的逻辑,比如采用渐变等更合理的方式来绘制阴影painter.fillRect(pixmap.rect(),QColor(127,127,127));painter.end();// 将子部件(child)显示的图片替换为添加了阴影效果的临时图片,这样在拖放操作过程中,原始图片所在位置显示的是带有阴影效果的版本child->setPixmap(tempPixmap);// 6、执行拖放操作// 启动拖放操作,并指定支持的拖放动作(这里支持复制和移动两种动作),同时指定默认的拖放动作(这里是复制动作)// 拖放操作执行后会返回实际执行的动作类型,如果返回的是移动动作(Qt::MoveAction)if(drag->exec(Qt::CopyAction| Qt::MoveAction,Qt::CopyAction) == Qt::MoveAction){// 则关闭对应的子部件(可能意味着将该图片从原位置移除等操作,具体功能取决于整个程序的逻辑)child->close();}else{// 如果不是移动动作,而是其他动作(比如复制动作等),则重新显示子部件,并将其显示的图片恢复为原始的未添加阴影的图片,// 这样在拖放操作完成(比如取消拖放等情况)后,界面恢复到原始状态child->show();child->setPixmap(pixmap);}}// 以下是在 MainWindow 类中的函数定义,用于处理与拖放操作相关的不同事件// dragMoveEvent 函数,用于处理拖动过程中的事件
// 当在窗口内拖动一个对象时,此函数会被多次调用,以确定拖动操作在当前位置是否被允许等情况
void MainWindow::dragMoveEvent(QDragMoveEvent *event)
{// 检查拖放操作所携带的 MIME 数据中是否包含指定格式(这里格式为"../../gift.png",实际可能需要规范为合适的 MIME 类型标识)的数据if (event->mimeData()->hasFormat("../../gift.png")){// 设置此拖放操作的默认动作是移动(意味着如果最终在此处放下,将会执行移动相关的逻辑,例如源对象可能会被移除等)event->setDropAction(Qt::MoveAction);// 告知系统当前事件已被接受,即允许在此处继续进行拖放操作(后续可以根据这个接受状态进行相应的界面反馈等)event->accept();}else{// 如果不包含指定格式的数据,则忽略此次拖放操作,意味着拖放操作在此处不被允许进行下去event->ignore();}
}

dragEnterEvent 函数

// dragEnterEvent 函数,用于处理拖放对象刚进入窗口区域时触发的事件
// 主要用于对进入窗口的拖放操作进行初始的合法性判断等操作
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{// 同样检查拖放操作携带的 MIME 数据是否具有指定格式("../../gift.png")的数据if (event->mimeData()->hasFormat("../../gift.png")){// 设置拖放动作类型为移动动作,表明如果在此窗口放下拖放对象,预期执行移动相关逻辑event->setDropAction(Qt::MoveAction);// 接受此次拖放进入事件,意味着允许拖放对象进入当前窗口区域继续后续的拖放操作流程event->accept();}else{// 如果数据格式不符合要求,忽略此次拖放进入事件,拖放对象在进入窗口时就不被允许继续操作了event->ignore();}
}

dragMoveEvent 函数

// dragMoveEvent 函数,用于处理拖动过程中的事件
// 当在窗口内拖动一个对象时,此函数会被多次调用,以确定拖动操作在当前位置是否被允许等情况
void MainWindow::dragMoveEvent(QDragMoveEvent *event)
{// 检查拖放操作所携带的 MIME 数据中是否包含指定格式(这里格式为"../../gift.png",实际可能需要规范为合适的 MIME 类型标识)的数据if (event->mimeData()->hasFormat("../../gift.png")){// 设置此拖放操作的默认动作是移动(意味着如果最终在此处放下,将会执行移动相关的逻辑,例如源对象可能会被移除等)event->setDropAction(Qt::MoveAction);// 告知系统当前事件已被接受,即允许在此处继续进行拖放操作(后续可以根据这个接受状态进行相应的界面反馈等)event->accept();}else{// 如果不包含指定格式的数据,则忽略此次拖放操作,意味着拖放操作在此处不被允许进行下去event->ignore();}
}

dragEnterEvent 函数


// dragEnterEvent 函数,用于处理拖放对象刚进入窗口区域时触发的事件
// 主要用于对进入窗口的拖放操作进行初始的合法性判断等操作
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{// 同样检查拖放操作携带的 MIME 数据是否具有指定格式("../../gift.png")的数据if (event->mimeData()->hasFormat("../../gift.png")){// 设置拖放动作类型为移动动作,表明如果在此窗口放下拖放对象,预期执行移动相关逻辑event->setDropAction(Qt::MoveAction);// 接受此次拖放进入事件,意味着允许拖放对象进入当前窗口区域继续后续的拖放操作流程event->accept();}else{// 如果数据格式不符合要求,忽略此次拖放进入事件,拖放对象在进入窗口时就不被允许继续操作了event->ignore();}
}// dropEvent 函数,用于处理拖放对象在窗口内被放下时触发的事件
// 在此函数中执行实际的放下拖放对象后的相关操作,比如根据拖放数据创建新的界面元素等
void MainWindow::dropEvent(QDropEvent *event)
{// 首先检查拖放数据是否具有指定格式("../../gift.png")的数据,只有符合要求的数据才进行后续处理if (event->mimeData()->hasFormat("../../gift.png")){// 获取拖放数据中对应指定格式("../../gift.png")的字节数组数据,这些数据在之前的拖放准备阶段被存储进去,包含了图片及相关位置信息等QByteArray itemData = event->mimeData()->data("../../gift.png");// 创建一个以只读模式打开的数据流对象,关联刚才获取的字节数组 itemData,以便后续从中读取数据QDataStream dataStream(&itemData, QIODevice::ReadOnly);// 用于存储从数据流中读取出来的图片对象,后续将用此图片来创建新的显示标签等QPixmap pixmap;// 用于存储从数据流中读取出来的位置偏移量信息,该偏移量表示在拖动操作时鼠标相对于原始图片的位置,在放置图片时会用到此偏移量来确定准确的放置位置QPoint offset;// 从数据流中依次读取图片对象和位置偏移量信息,按照之前在拖放准备阶段写入数据的顺序进行读取dataStream >> pixmap >> offset;// 创建一个新的 QLabel 标签对象,将其作为当前窗口(this 表示 MainWindow 实例,即当前窗口)的子部件,用于显示拖放过来的图片QLabel *newLabel = new QLabel(this);// 设置新标签显示的图片为刚才读取出来的 pixmap,这样就能在界面上显示出拖放过来的图片内容了newLabel->setPixmap(pixmap);// 将新标签的大小调整为与图片大小一致,确保图片能完整显示且布局合理(也可以根据实际需求添加额外的布局相关处理)newLabel->resize(pixmap.size());// 根据拖放操作放下时的鼠标位置(event->position().toPoint())以及之前读取的偏移量 offset,计算出图片最终应该放置的准确位置,然后移动新标签到该位置newLabel->move(event->position().toPoint() - offset);// 显示新创建的标签,使其在界面上可见,呈现出拖放图片后的最终效果newLabel->show();// 设置新标签在关闭时自动删除的属性,这样当标签关闭(比如用户手动关闭或者程序逻辑中关闭它)时,会自动释放其所占用的内存资源newLabel->setAttribute(Qt::WA_DeleteOnClose);// 设置此次拖放操作的实际执行动作是移动动作,与前面拖放过程中的相关设置对应,表示整个拖放操作按照移动逻辑完成了event->setDropAction(Qt::MoveAction);// 接受此次拖放放下事件,告知系统拖放操作已成功完成且相关处理都已执行完毕event->accept();}else{// 如果拖放数据格式不符合要求,忽略此次拖放放下事件,不做任何处理event->ignore();}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com