链接
拖放操作链接: https://blog.csdn.net/MrHHHHHH/article/details/134547370
使用拖放打开文件
- 新建一个app项目,在MainWindow里,重新实现
virtual void dragEnterEvent(QDragEnterEvent *event) override;
,virtual void dragEnterEvent(QDragEnterEvent *event) override;
// 拖动进入事件
virtual void dragEnterEvent(QDragEnterEvent *event) override;
// 放下事件
virtual void dragEnterEvent(QDragEnterEvent *event) override;
- 实现,需要在.cpp里添加以下头文件
#include <QDragEnterEvent>
#include <QMimeData>
#include <QDropEvent>
#include <QFile>
#include <QTextStream>
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
// 数据中是否包含URL
if(event->mimeData()->hasUrls())
{
// 接收动作
event->acceptProposedAction();
}else {
// 忽略
event->ignore();
}
}
void MainWindow::dropEvent(QDropEvent *event)
{
// 获取MIME数据
const QMimeData* pMD = event->mimeData();
if(pMD->hasUrls())
{
// 获取URL列表
QList<QUrl> listUrls = pMD->urls();
QString fileNmae = listUrls.at(0).toLocalFile();
if(!fileNmae.isEmpty())
{
// 读取数据
QFile file(fileNmae);
if(file.open(QIODevice::ReadOnly)){
QTextStream in(&file);
ui->textEdit->append(in.readAll());
}
}
}
}
- 当鼠标拖拽一个数据进入主窗口时,会触发
dragEnterEvent
事件处理函数,从而获取其中的MIME
数据 - 然然后查看是否包含URL,因为拖拽的文本实际是拖拽其路径,
event->mimeData()->hasUrls()
实现的功能 - 如果有数据,就接收,不然就忽略
- 放入主窗口,进入
dropEvent
函数,获取URL列表,转换成本地文件路径 - 最后进行读写操作
那如果想实现控件拖拽,需要添加以下代码
setAcceptDrops(true);
这样主窗口就可以接收放下事件了。
效果如下:
拖拽
自定义拖放操作
实现在一个窗口中,有一张图片,可以随意拖动它,根据自定义的MIME类型进行实现。
- 在MainWindow.h添加以下事件
protected:
// 鼠标点击事件
virtual void mousePressEvent(QMouseEvent *event) override;
// 拖动进入事件
virtual void dragEnterEvent(QDragEnterEvent *event) override;
// 移动
virtual void dragMoveEvent(QDragMoveEvent *event) override;
// 放下事件
virtual void dropEvent(QDropEvent *event) override;
- 在构造中,构建一个QLabel控件,用于显示图片。
在MainWindow.cpp中,包含以下头文件
#include <QDragEnterEvent>
#include <QMimeData>
#include <QDropEvent>
#include <QFile>
#include <QTextStream>
#include <QMouseEvent>
#include <QDragMoveEvent>
#include <QPainter>
#include <QLabel>
#include <QByteArray>
#include <QDrag>
#include <QPixmap>
#include <QPainter>
#include <QDebug>
setAcceptDrops(true);
QLabel* pLabel = new QLabel(this);
QPixmap pixmap(":/drop.png");
pLabel->setPixmap(pixmap);
pLabel->resize(pixmap.size());
pLabel->move(width()/2-pLabel->width()/2, height()/2-pLabel->height()/2);
pLabel->setAttribute(Qt::WA_DeleteOnClose);
上述代码作用:
-
调用 setAcceptDrops(true) 启用控件的拖拽功能,即允许其他控件将数据拖拽到该控件上。
-
创建了一个 QLabel 控件,并将其添加到当前控件中。
-
从资源文件中加载了一张名为 drop.png 的图片,并将其设置为 QLabel 控件的背景。
-
调整了 QLabel 控件的大小和位置,使其居中显示在当前控件中心。
-
使用 setAttribute(Qt::WA_DeleteOnClose) 方法,在 QLabel 控件关闭时自动释放其内存空间,避免内存泄漏。
- 实现
mousePressEvent
事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{
QLabel* pLabel = static_cast<QLabel*>(childAt(event->pos()));
if(!pLabel->inherits("QLabel"))
return;
QPixmap pixmap = *pLabel->pixmap();
QByteArray ba;
QDataStream dataStream(&ba, QIODevice::WriteOnly);
dataStream << pixmap << QPoint(event->pos() - pLabel->pos());
QMimeData* md = new QMimeData;
md->setData("myimage/png", ba);
QDrag* pDrag = new QDrag(this);
pDrag->setMimeData(md);
pDrag->setPixmap(pixmap);
pDrag->setHotSpot(event->pos()-pLabel->pos());
QPixmap pTmp = pixmap;
QPainter p;
p.begin(&pTmp);
p.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
p.end();
pLabel->setPixmap(pTmp);
if(pDrag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction) == Qt::MoveAction)
{
pLabel->close();
}else{
pLabel->show();
pLabel->setPixmap(pixmap);
}
}
上述代码作用:
- 使用
childAt()
方法获取当前鼠标点击位置下的子控件,赋值给pLabel
变量。 - 判断该子控件是否是
QLabel
类型的控件,如果不是则直接返回。 - 获取
pLabel
控件中显示的图片,并将其转换为字节数组ba
。 - 创建一个
QMimeData
对象md
,将转换后的图片数据设置为该对象的 MIME 类型为myimage/png
的数据。 - 创建一个
QDrag
对象pDrag
,将md
对象设置为该拖拽操作的数据来源,并将pixmap
设置为拖拽时的图标,event->pos()-pLabel->pos()
为设置拖拽热点,即拖拽图标相对于鼠标点击位置的偏移量。 - 创建一个临时
QPixmap
对象pTmp
,并使用QPainter
对象对该对象进行填充,即将图像进行半透明化处理。 - 将
pTmp
对象设置为pLabel
控件的背景,启动拖拽操作,通过exec()
方法返回用户操作的拖拽行为。 - 如果用户选择了移动操作,则关闭
pLabel
控件;否则显示原来的图片。
- 实现
dragEnterEvent
、dragMoveEvent
- 如果不实现
dragEnterEvent
事件,无法拖拽
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
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();
}
}
上述代码作用:
dragEnterEvent
函数在拖拽对象进入窗口时被触发,dragMoveEvent
函数在拖拽对象在窗口内移动时被触发。- 判断拖拽对象的 MIME 类型是否为
myimage/png
,如果是则将拖拽操作设置为移动操作,并接受拖拽事件,否则忽略该事件。 - 在接受拖拽事件后,可以通过
event->setDropAction()
函数来设置拖拽操作的行为类型,如Qt::CopyAction
表示复制操作,Qt::MoveAction
表示移动操作,Qt::LinkAction
表示链接/打开操作。 - 在接受拖拽事件后,可以通过
event->accept()
函数来标记该事件被接受,从而向拖拽操作源发出一个dragLeaveEvent
事件,表明该窗口能够接受该拖拽操作;而通过event->ignore()
函数则表示该事件被忽略,拖拽操作源将继续寻找其他能够接受该拖拽操作的窗口。
- 实现
dropEvent
事件
void MainWindow::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasFormat("myimage/png"))
{
QByteArray ba = event->mimeData()->data("myimage/png");
QDataStream dataStream(&ba, QIODevice::ReadOnly);
QPixmap pixmap;
QPoint offset;
dataStream >> pixmap >> offset;
QLabel* pLabel = new QLabel(this);
pLabel->setPixmap(pixmap);
pLabel->resize(pixmap.size());
pLabel->move(event->pos()-offset);
pLabel->show();
pLabel->setAttribute(Qt::WA_DeleteOnClose);
event->setDropAction(Qt::MoveAction);
event->accept();
}else {
event->ignore();
}
}
上述代码作用:
dropEvent
函数在拖拽对象放下时被触发。- 判断放下的拖拽对象的 MIME 类型是否为
myimage/png
,若是则接受拖拽操作,并使用QDataStream
从 MIME 数据中读取数据,包括被拖拽的图片和其在放下位置的偏移量。 - 在接受拖拽事件后,通过
pLabel
创建一个新的QLabel
并展示被拖拽的图片。 - 通过设置
Qt::WA_DeleteOnClose
属性,保证在该QLabel
被关闭时,它的内存将会被自动释放。 - 在接受拖拽事件后,可以通过
event->setDropAction()
函数来设置拖拽操作的行为类型,如Qt::CopyAction
表示复制操作,Qt::MoveAction
表示移动操作。 - 在接受拖拽事件后,可以通过
event->accept()
函数来标记该事件被接受,从而通知拖拽的源对象该操作已被成功处理;而通过event->ignore()
函数则表示该事件被忽略,源对象将知道该操作无法被处理。
- 效果如下
拖拽事件
结论
记录是存在的一种方式
。