【Qt开发流程】之拖放操作2:使用

链接

拖放操作链接: 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);

上述代码作用:

  1. 调用 setAcceptDrops(true) 启用控件的拖拽功能,即允许其他控件将数据拖拽到该控件上。

  2. 创建了一个 QLabel 控件,并将其添加到当前控件中。

  3. 从资源文件中加载了一张名为 drop.png 的图片,并将其设置为 QLabel 控件的背景。

  4. 调整了 QLabel 控件的大小和位置,使其居中显示在当前控件中心。

  5. 使用 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);
    }
}

上述代码作用:

  1. 使用 childAt() 方法获取当前鼠标点击位置下的子控件,赋值给 pLabel 变量。
  2. 判断该子控件是否是 QLabel 类型的控件,如果不是则直接返回。
  3. 获取 pLabel 控件中显示的图片,并将其转换为字节数组 ba
  4. 创建一个 QMimeData 对象 md,将转换后的图片数据设置为该对象的 MIME 类型为 myimage/png 的数据。
  5. 创建一个 QDrag 对象 pDrag,将 md 对象设置为该拖拽操作的数据来源,并将 pixmap 设置为拖拽时的图标,event->pos()-pLabel->pos() 为设置拖拽热点,即拖拽图标相对于鼠标点击位置的偏移量。
  6. 创建一个临时 QPixmap 对象 pTmp,并使用 QPainter 对象对该对象进行填充,即将图像进行半透明化处理。
  7. pTmp 对象设置为 pLabel 控件的背景,启动拖拽操作,通过 exec() 方法返回用户操作的拖拽行为。
  8. 如果用户选择了移动操作,则关闭 pLabel 控件;否则显示原来的图片。
  • 实现dragEnterEventdragMoveEvent
  • 如果不实现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();
    }
}

上述代码作用:

  1. dragEnterEvent 函数在拖拽对象进入窗口时被触发,dragMoveEvent 函数在拖拽对象在窗口内移动时被触发。
  2. 判断拖拽对象的 MIME 类型是否为 myimage/png,如果是则将拖拽操作设置为移动操作,并接受拖拽事件,否则忽略该事件。
  3. 在接受拖拽事件后,可以通过 event->setDropAction() 函数来设置拖拽操作的行为类型,如 Qt::CopyAction 表示复制操作,Qt::MoveAction 表示移动操作,Qt::LinkAction 表示链接/打开操作。
  4. 在接受拖拽事件后,可以通过 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();
    }
}

上述代码作用:

  1. dropEvent 函数在拖拽对象放下时被触发。
  2. 判断放下的拖拽对象的 MIME 类型是否为 myimage/png,若是则接受拖拽操作,并使用 QDataStream 从 MIME 数据中读取数据,包括被拖拽的图片和其在放下位置的偏移量。
  3. 在接受拖拽事件后,通过 pLabel 创建一个新的 QLabel 并展示被拖拽的图片。
  4. 通过设置 Qt::WA_DeleteOnClose 属性,保证在该 QLabel 被关闭时,它的内存将会被自动释放。
  5. 在接受拖拽事件后,可以通过 event->setDropAction() 函数来设置拖拽操作的行为类型,如 Qt::CopyAction 表示复制操作,Qt::MoveAction 表示移动操作。
  6. 在接受拖拽事件后,可以通过 event->accept() 函数来标记该事件被接受,从而通知拖拽的源对象该操作已被成功处理;而通过 event->ignore() 函数则表示该事件被忽略,源对象将知道该操作无法被处理。
  • 效果如下

拖拽事件

结论

记录是存在的一种方式

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FreeLikeTheWind.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值