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

news2024/12/23 13:13:22

一、效果示例图

提示:主控件(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^/)

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ONE·C || 分支循环】

总言 C语言&#xff1a;分支循环。 文章目录总言1、分支语句1.1、if语句1.1.1、基本格式1.1.2、逻辑真假与悬空else1.1.3、练习1.2、switch语句1.2.1、基本格式&#xff1a;break、case、default1.2.2、练习&#xff1a;switch语句嵌套2、循环语句2.1、while循环2.1.1、基本格式…

uniapp实现界面可任意拖动小图标

uniapp实现界面可任意拖动小图标一、问题&#xff1a;二、解决步骤2.1 根据uni-app官方提供的案例&#xff0c;创建组件2.2 在需要的界面引入组件使用额外注意一、问题&#xff1a; 例如购物车小图标可任意拖动 二、解决步骤 2.1 根据uni-app官方提供的案例&#xff0c;创建…

Kubernetes教程(二)---集群网络之 Flannel 核心原理

来自&#xff1a;指月 https://www.lixueduan.com 原文&#xff1a;https://www.lixueduan.com/posts/kubernetes/02-cluster-network/ 本文主要记录了 Kubernetes 集群网络方案之 Flannel 核心原理详解&#xff0c;包括其隧道方案中的两种&#xff1a;UDP 实现和 VXLAN 实现…

Mysql之增删改查

这里的增删改查主要是对应表中的数据&#xff0c;不像前一篇那个列类型&#xff0c;耳机具体的哪一条数据 Insert 其实我们前面都用过好多次了 比如下面那个 可以 关于那个表名后面加不加&#xff08;列类型&#xff09;&#xff0c;下面有解释 INSERT INTO shanpin VALUES…

关于yolov8一些训练的情况

U神出品了最新的yolov8&#xff0c;从公开的参数量来看确实很优秀&#xff01;&#xff01;&#xff01;&#xff01;比如下图得一些指标&#xff1a; 可以看到s模型640得map已经达到了44.9&#xff0c;v8n得map也已经达到了37.3&#xff0c;很强了&#xff0c;但是实际上是怎么…

Python爬虫之Scrapy框架系列(3)——项目实战【某瓣top250电影信息获取】

目录&#xff1a;1. 某瓣电影top250首页电影信息的获取&#xff01;1.创建项目&#xff1a;2.创建爬虫文件&#xff1a;3.运行爬虫文件&#xff1a;4.设置请求头&#xff1a;5.获取到电影名字&#xff1a;5.1 使用shell交互式平台&#xff1a;5.1.1 首先&#xff1a;打开我们的…

239页10万字“联、管、用”三位一体雪亮工程整体建设方案

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 目录 1、 项目概述 1.1 项目背…

用R语言绘制泰勒级数的逼近过程

文章目录泰勒级数是如何被发现的用图像理解Taylor级数的逼近过程前情提要 R语言微积分极限π,e,γ\pi, e, \gammaπ,e,γ洛必达法则连续性和导数数值导数差商与牛顿插值方向导数 泰勒级数是如何被发现的 如果我是泰勒&#xff0c;我会把思考的起点建立在这样的一个等式上 f(n…

Windows10电脑重装系统详细步骤(纯净版)

目录 前言&#xff1a; 一、准备工作 二、下载pe工具 三、下载系统镜像ISO文件 获取方式一 获取方式二 获取方式三 四、进入pe系统 1.检查以上的准备工作是否完成 2.然后拔出来u盘插入要重装的电脑上面 3.然后按电源键开机&#xff08;不能点击重启&#xff01;&…

【Git 从入门到精通】使用Git将本地代码推送到Github

文章目录一、创建远程库二、Git操作远程库1.推送代码2.克隆代码3.拉取代码4.Pull request5.常用命令总结一、创建远程库 打开github.com&#xff0c;点击右上角加号&#xff0c;点击第一个选项。 填写库的基本信息&#xff0c;如果你想代码开源就选择public&#xff0c;否则就…

开发模型和测试模型

开发模型瀑布模型特点&#xff1a;线性结构&#xff0c;每个阶段只执行一次&#xff0c;必须完成上一个才能执行下一个。是其他模型的基础框架缺点&#xff1a;测试后置&#xff0c;1&#xff09;前面各个阶段的遗留的风险推迟到测试阶段才被发现&#xff0c;导致项目大面积返工…

【7】SCI易中期刊推荐——图像处理领域(中科院4区)

🚀🚀🚀NEW!!!SCI易中期刊推荐栏目来啦 ~ 📚🍀 SCI即《科学引文索引》(Science Citation Index, SCI),是1961年由美国科学信息研究所(Institute for Scientific Information, ISI)创办的文献检索工具,创始人是美国著名情报专家尤金加菲尔德(Eugene Garfield…

【LGR-(-17)】洛谷入门赛 #8个人思考

T306713 Hello, 2023 题目背景 Goodbye, 2022 Hello, 2023 题目描述 某 E 在 2022 年的幸运数字是 xxx&#xff0c;这个数可能是正的&#xff0c;也可能是负的。 某 E 想要知道 xmod2023x \bmod 2023xmod2023 的值。其中&#xff0c;mod\bmodmod 是取模操作。也就是说&am…

数据结构:线性表的顺序表示和实现

在实际应用程序中涉及的线性表的基本操作都需要针对线性表的具体存储结构加以实现。线性表可以有两种存储表示方法:顺序存储表示和链式存储表示。下面我们先说说顺序存储表示。 1、顺序表——线性表的顺序存储表示 在计算机中表示线性表的最简单的方法是用一组地址连续的存储…

Linux:自动化构建工具make/Makefile

文章目录一.前言二.Makefile如何写入/make命令使用2.1清楚依赖关系和依赖方法2.2删除文件2.3Makefile中的关键字.PHONY2.4一个小补充一.前言 在此之前我们已经可以用vim编写代码和用gcc编译代码。但是如果现在要写一个大型项目&#xff0c;一下子写了很多源文件&#xff0c;在…

C. Zero Path(DP)

Problem - 1695C - Codeforces 给你一个有n行和m列的网格。我们用(i,j)表示第i(1≤i≤n)行和第j(1≤j≤m)列的方格&#xff0c;用aij表示那里的数字。所有的数字都等于1或等于-1。 你从方格&#xff08;1,1&#xff09;开始&#xff0c;每次可以向下或向右移动一个方格。最后&…

基于结点的数据结构——链表(单链表双向循环链表)| 附完整源码 | C语言版

本章内容 1.什么是链表 2.链表常见几种形式 3.无头单向非循环链表的实现 3.1结点结构的定义 3.2函数接口的实现 3.2.1尾插 3.2.2尾删 4. 带头双向循环链表的实现 4.1结点结构的定义 4.2函数接口的实现 5.两种链表的差异 ①尾插与尾删的时间复杂度 ②头插与头删的时…

Ai 作图 stable-diffusion-webui prompt

文章参考了 prompt指导手册 &#xff1a; https://strikingloo.github.io/stable-diffusion-vs-dalle-2 https://prompthero.com/stable-diffusion-prompt-guide 一般来说&#xff0c;最好的稳定扩散提示会有这样的形式&#xff1a; “ [主要主题]的[图片类型] &#xff0…

C语言-文件操作(13.1)

目录 思维导图&#xff1a; 1. 为什么使用文件 2. 什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 3. 文件的打开和关闭 3.1 文件指针 3.2 文件的打开和关闭 4. 文件的顺序读写 4.1 对比一组函数 5. 文件的随机读写 5.1 fseek 5.2 ftell 5.3 rewind 6. 文本…

FeignClient调用源码解析

文章目录一、FeignClient二、整体流程1.使用FeignClient2.FeignClient整体调用流程三、源码解析1. 注解EnableFeignClients2. FeignClientsRegistrar3. Feign其他配置4. FactoryBean5. 方法调用一、FeignClient FeignClient作为SrpingCloud进行http请求的一个基础组件&#xf…