Qt之QDrag的使用(含源码+注释)

一、效果示例图

提示:主控件(CDragTest界面,UI中中包含CWidget界面);子控件(CWidget界面,在CDragTest界面添加)
提示:源码中拖拽数据设置的文本不同,是博主准备好示例素材之后添加的,但是在控件自己对应的拖拽事件中,发送的数据就是控件自己对应的数据。

1.同一窗口

在同一窗口中操作,主控件接收Drop,子控件不接收Drop,在窗口中的拖动事件主控件都会响应接收;
在这里插入图片描述
在同一窗口中操作,主控件不接收Drop,子控件接收Drop,在窗口中的拖动事件子控件只接收子控件所占位置的事件;
在这里插入图片描述
在同一窗口中操作,主控件不接收Drop,子控件也不接收Drop,在窗口中的拖动事件都不会接收;
在这里插入图片描述
在同一窗口中操作,主控件接收Drop,子控件也接收Drop,在窗口中的拖动事件主子控件都会响应,但是仅会响应自己包含的拖动区域;
在这里插入图片描述

2.不同窗口(效果和同意窗口一致)

在不同窗口中操作,所有控件都接收,在窗口中的拖动事件都会接收拖动事件;
在这里插入图片描述
在不同窗口中操作,所有控件都不接收,在窗口中的拖动事件都不接收拖动事件;
在这里插入图片描述
提示:不会使用Qt设计师设计界面的小伙伴点击这里

二、QDrag须知(个人理解)

  1. 拖拽事件在操作系统中非常常见,如选择文本后的拖动,选择文件后的拖动等;
  2. 要触发QDrag需要通过该对象的exec()函数主动触发,且该函数会阻塞当前线程(可查看源码中mousePressEvent源码);
  3. 要使拖动操作中包含数据需要创建QMimeData对象,并将数据(支持多种数据类型如URL、TEXT、IMAGE,详情可查看Qt源码)设置到该对象中,然后将该对象设置到QDrag中;
  4. 控件对象如果需要响应拖拽事件,需要调用setAcceptDrops()函数接收拖拽事件;
  5. 在dragEnterEvent需要主动调用accept()函数,否则dragMoveEvent、dragLeaveEvent两个事件都不会进入。

三、源码

CWidget.h

#ifndef CWIDGET_H
#define CWIDGET_H

#include <QWidget>

namespace Ui {
class CWidget;
}

class CWidget : public QWidget
{
    Q_OBJECT

public:
    explicit CWidget(QWidget *parent = nullptr);
    ~CWidget();

    // QWidget interface
protected:
    /**
     * @brief dragEnterEvent 拖拽进入事件
     * @param event 拖拽事件对象
     */
    void dragEnterEvent(QDragEnterEvent *event);

    /**
     * @brief dragMoveEvent 拖拽移动事件
     * @param event 拖拽事件对象
     */
    void dragMoveEvent(QDragMoveEvent *event);

    /**
     * @brief dragLeaveEvent 拖拽离开事件
     * @param event 拖拽事件对象
     */
    void dragLeaveEvent(QDragLeaveEvent *event);

    /**
     * @brief dropEvent 方向事件
     * @param event 放下事件对象
     */
    void dropEvent(QDropEvent *event);

    /**
     * @brief mousePressEvent 鼠标按下事件
     * @param event 鼠标事件对象
     */
    void mousePressEvent(QMouseEvent *event);

private slots:
    /**
     * @brief on_dragFlagBtn_clicked 按钮点击槽函数
     * @param checked 选中状态
     */
    void on_dragFlagBtn_clicked(bool checked);

private:
    Ui::CWidget *ui;
};

#endif // CWIDGET_H

CWidget.cpp

#include "CWidget.h"
#include "ui_CWidget.h"

#include <QDrag>
#include <QDebug>
#include <QMimeData>
#include <QDragMoveEvent>

CWidget::CWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::CWidget)
{
    ui->setupUi(this);
}

CWidget::~CWidget()
{
    delete ui;
}

void CWidget::dragEnterEvent(QDragEnterEvent *event)
{
    // 事件接收拖拽
    event->accept();
    // 函数名追加到文本编辑框中
    ui->textEdit->append(__func__);
}

void CWidget::dragMoveEvent(QDragMoveEvent *event)
{
    // 函数名追加到文本编辑框中
    ui->textEdit->append(__func__);
}

void CWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
    // 函数名追加到文本编辑框中
    ui->textEdit->append(__func__);
}

void CWidget::dropEvent(QDropEvent *event)
{
    // 获取QMimeData对象中的文本
    QString text = event->mimeData()->text();
    // 函数名追加到文本编辑框中
    ui->textEdit->append(text);
}

void CWidget::mousePressEvent(QMouseEvent *event)
{
    // 判断当前按钮是否为左键
    bool mouseBtn = Qt::LeftButton == event->button();

    // 如果是则进入
    if(mouseBtn)
    {
        // 创建QDrag对象
        QDrag *drag = new QDrag(this);
        // 创建拖拽对象包含的数据
        QMimeData *data = new QMimeData;
        // 设置数据文本
        data->setText("Child Wieget 拖拽操作");
        // 将数据设置到拖拽对象中
        drag->setMimeData(data);
        // 函数名追加到文本编辑框中
        ui->textEdit->append(QString("%1  拖拽操作开始").arg(__func__));
        // 执行拖拽对象
        drag->exec();
        ui->textEdit->append(QString("%1  拖拽操作结束").arg(__func__));
    }
}

void CWidget::on_dragFlagBtn_clicked(bool checked)
{
    // 通过按钮选中状态切换控件接收拖拽的状态
    this->setAcceptDrops(checked);
}


CWidget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>CWidget</class>
 <widget class="QWidget" name="CWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <property name="spacing">
    <number>6</number>
   </property>
   <property name="leftMargin">
    <number>0</number>
   </property>
   <property name="topMargin">
    <number>0</number>
   </property>
   <property name="rightMargin">
    <number>0</number>
   </property>
   <item>
    <widget class="QPushButton" name="dragFlagBtn">
     <property name="text">
      <string>Drag Flag</string>
     </property>
     <property name="checkable">
      <bool>true</bool>
     </property>
    </widget>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <property name="spacing">
      <number>0</number>
     </property>
     <item>
      <widget class="QTextEdit" name="textEdit"/>
     </item>
     <item>
      <spacer name="horizontalSpacer">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>40</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

CDragTest.h

#ifndef CDRAGTEST_H
#define CDRAGTEST_H

#include <QWidget>

namespace Ui {
class CDragTest;
}

class CDragTest : public QWidget
{
    Q_OBJECT

public:
    explicit CDragTest(QWidget *parent = nullptr);
    ~CDragTest();

    // QWidget interface
protected:
    /**
     * @brief dragEnterEvent 拖拽进入事件
     * @param event 拖拽事件对象
     */
    void dragEnterEvent(QDragEnterEvent *event);

    /**
     * @brief dragMoveEvent 拖拽移动事件
     * @param event 拖拽事件对象
     */
    void dragMoveEvent(QDragMoveEvent *event);

    /**
     * @brief dragLeaveEvent 拖拽离开事件
     * @param event 拖拽事件对象
     */
    void dragLeaveEvent(QDragLeaveEvent *event);

    /**
     * @brief dropEvent 方向事件
     * @param event 放下事件对象
     */
    void dropEvent(QDropEvent *event);

    /**
     * @brief mousePressEvent 鼠标按下事件
     * @param event 鼠标事件对象
     */
    void mousePressEvent(QMouseEvent *event);

private slots:
    /**
     * @brief on_dragFlagBtn_clicked 按钮点击槽函数
     * @param checked 选中状态
     */
    void on_dragFlagBtn_clicked(bool checked);

private:
    Ui::CDragTest *ui;

};

#endif // CDRAGTEST_H

CDragTest.cpp

#include "CDragTest.h"
#include "ui_CDragTest.h"

#include <QWidget>
#include <QDrag>
#include <QDebug>
#include <QMimeData>
#include <QDragMoveEvent>

CDragTest::CDragTest(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::CDragTest)
{
    ui->setupUi(this);
    // 初始化设置接收拖拽
    this->setAcceptDrops(true);
}

CDragTest::~CDragTest()
{
    delete ui;
}

void CDragTest::dragEnterEvent(QDragEnterEvent *event)
{
    // 事件接收拖拽
    event->accept();
    // 函数名追加到文本编辑框中
    ui->textEdit->append(__func__);
}

void CDragTest::dragMoveEvent(QDragMoveEvent *event)
{
    // 函数名追加到文本编辑框中
    ui->textEdit->append(__func__);
}

void CDragTest::dragLeaveEvent(QDragLeaveEvent *event)
{
    // 函数名追加到文本编辑框中
    ui->textEdit->append(__func__);
}

void CDragTest::dropEvent(QDropEvent *event)
{
    // 获取QMimeData对象中的文本
    QString text = event->mimeData()->text();
    // 函数名追加到文本编辑框中
    ui->textEdit->append(text);
}

void CDragTest::mousePressEvent(QMouseEvent *event)
{
    // 判断当前按钮是否为左键
    bool mouseBtn = Qt::LeftButton == event->button();

    // 如果是则进入
    if(mouseBtn)
    {
        // 创建QDrag对象
        QDrag *drag = new QDrag(this);
        // 创建拖拽对象包含的数据
        QMimeData *data = new QMimeData;
        // 设置数据文本
        data->setText("Main Widget 拖拽操作");
        // 将数据设置到拖拽对象中
        drag->setMimeData(data);
        // 函数名追加到文本编辑框中(拖拽开始标志)
        ui->textEdit->append(QString("%1  拖拽操作开始").arg(__func__));
        // 执行拖拽对象
        drag->exec();
        // 函数名追加到文本编辑框中(拖拽结束标志)
        ui->textEdit->append(QString("%1  拖拽操作结束").arg(__func__));
    }
}

void CDragTest::on_dragFlagBtn_clicked(bool checked)
{
    // 通过按钮选中状态切换控件接收拖拽的状态
    this->setAcceptDrops(checked);
}

CDragTest.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>CDragTest</class>
 <widget class="QWidget" name="CDragTest">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>429</width>
    <height>336</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QPushButton" name="dragFlagBtn">
     <property name="text">
      <string>Drag Flag</string>
     </property>
     <property name="checkable">
      <bool>true</bool>
     </property>
     <property name="checked">
      <bool>true</bool>
     </property>
    </widget>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QTextEdit" name="textEdit"/>
     </item>
     <item>
      <spacer name="horizontalSpacer">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>40</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
    </layout>
   </item>
   <item>
    <widget class="CWidget" name="widget" native="true">
     <property name="minimumSize">
      <size>
       <width>0</width>
       <height>0</height>
      </size>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <customwidgets>
  <customwidget>
   <class>CWidget</class>
   <extends>QWidget</extends>
   <header>CWidget.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

main.cpp

#include "CDragTest.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CDragTest w1;
    w1.show();

    CDragTest w2;
    w2.show();

    return a.exec();
}

总结

拖拽事件在实际生活中非常实用,除了普通的操作以外,还可以通过不同数据分辨实现不同的操作。

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lw向北.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值