Qt——拖拽

news2025/1/16 16:48:37

Qt的拖拽可以按字面意思分为两部分。一般来说我们常见的拖拽分别由两个程序合作完成。例如我们经常把桌面的文件拖拽进其他目录:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== 编辑

拖拽方可以发起多个拖拽类型(复制、链接、移动等),接收方可以选择接受其中某个类型或者直接拒绝。除此之外,拖拽支持多种数据格式,并且还可以在同一个应用程序中进行(托和拽操作均由同一个exe发起)。我们通过一个示例程序来学习,这个程序包含以下功能:

  • 内部发起拖拽。
  • 切换可接受的拖拽动作:移动、拷贝、链接。
  • 支持多种拖拽数据:image、html、text、color等。
  • 拖拽区域高亮。

1. 内部拖拽

我们在主窗口内部放置了3个Label,分别可以用来演示3种不同数据类型的拖拽效果。如果鼠标左键在这几个标签区域内按下并且移动距离超过5个像素,我们就发起拖拽动作,可能的拖拽类型为:Copy、Move、Link。通过QDrag类我们就能发起一个拖拽动作,这个类还提供了setPixmap()setHotSpot()函数类供我们自定义拖拽时的图像和位置,这里我们就不设置了。

调用QDrag::exec()就能进入拖拽的事件处理循环了,注意在Linux和Mac上,这个exec并不会阻塞全局的消息循环;在Windows上,它是阻塞的:

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() & Qt::LeftButton) {
        m_dragStartPos = event->pos();

        if (m_imageLabel->geometry().contains(event->pos()))
            m_dragLabel = m_imageLabel;
        else if (m_colorLabel->geometry().contains(event->pos()))
            m_dragLabel = m_colorLabel;
        else if (m_htmlLabel->geometry().contains(event->pos()))
            m_dragLabel = m_htmlLabel;
        else
            m_dragStartPos = QPoint();
    }

    QMainWindow::mousePressEvent(event);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    QDrag drag(this);

    if (m_dragStartPos.isNull())
        goto end;
    if ((event->pos() - m_dragStartPos).manhattanLength() < 5)
        goto end;

    ...

    drag.exec(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction);

end:
    QMainWindow::mouseMoveEvent(event);
}

2. 可接受拖拽类型切换

这个功能我们通过菜单来实现,因为同一时间只接受一种类型,因此这几个菜单要求必须互斥。互斥菜单这个概念我们在代码里选择使用QActionGroup,虽然自己实现切换也不麻烦,但是这样更快更方便。每个子菜单触发时会切换可接受拖拽类型,Qt提供了3种基本类型:Move、Copy、Link。拖拽显示时,Copy类型是一个+号,Move类型是一个,Link类型是一个粗体的斜箭头:

void MainWindow::createMenus()
{
    auto menu = this->menuBar()->addMenu(tr("Acceptable Drags"));

    auto copyAction = menu->addAction("Only Copy",
                        this, SLOT(onlyAcceptCopyDrag()),
                        QKeySequence(Qt::CTRL + Qt::Key_C));
    copyAction->setCheckable(true);
    copyAction->setChecked(true);
    m_actionGroup.addAction(copyAction);

    auto moveAction = menu->addAction("Only Move",
                        this, SLOT(onlyAcceptMoveDrag()),
                        QKeySequence(Qt::CTRL + Qt::Key_M));
    moveAction->setCheckable(true);
    moveAction->setChecked(false);
    m_actionGroup.addAction(moveAction);

    auto linkAction = menu->addAction("Only Link",
                        this, SLOT(onlyAcceptLinkDrag()),
                        QKeySequence(Qt::CTRL + Qt::Key_L));
    linkAction->setCheckable(true);
    linkAction->setChecked(false);
    m_actionGroup.addAction(linkAction);
}

3. 多种拖拽数据类型

我们在发起拖拽的时候设置传递的数据及类型,通过QDrag::setMimeData()函数来设置传入的数据及类型。这个函数接受一个QMimeData类型的指针,这个类用MIME来区分数据类型。对于常见的类型它提供了方便的函数setHtml()setColorData()等,我们只需要传入数据就可以了:html和texx类型的数据以字符串表示,Image和Color类型数据以QVariant表示;对于自定义类型,我们需要调用setData()函数,同时传入MIME类型和对应的数据(因为使用简单,代码中没有演示)。数据获取则通过对应的html()imageData()data()等函数:

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    ...

    QMimeData* mimeData = new QMimeData();
    if (m_dragLabel == m_htmlLabel)
        mimeData->setHtml("<html>This is a html page</html>");
    if (m_dragLabel == m_colorLabel)
        mimeData->setColorData(QVariant(QColor(Qt::cyan)));
    if (m_dragLabel == m_imageLabel)
        mimeData->setImageData(QVariant(QPixmap(":/img/image.jpg")));
    drag.setMimeData(mimeData);

    ...
}

其实个人觉得QMimeData不是很好用,没有获取当前类型的功能,只能约定好或者一个一个去尝试。

4. 拖拽区域高亮

  • 当拖拽进入窗口之中时,会触发dragEnterEvent()事件,我们在这里高亮窗口背景;
  • 当我们接受拖拽事件(通过QDragEnterEvent::accept()或者QDropEvent::acceptProposedAction())后,窗口会收到dragMoveEvent()事件。QDragMoveEvent事件包含一个answerRect()函数,返回相对于窗口的当前拖拽范围,我们通过判断来选择是否绘制中心的高亮区域。有趣的是这个范围大小始终是1x1,它被当成点来处理。
  • 当拖拽离开窗口时,会触发dragLeaveEvent()事件,我们进行重绘。

下面是该部分代码:

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    event->setDropAction(m_acceptableDropAction);
    event->accept();
    m_currentBkColor = m_dragEnteredColor;

    QWidget::dragEnterEvent(event);
}

void MainWindow::dragLeaveEvent(QDragLeaveEvent *event)
{
    m_currentBkColor = m_dragLeavedColor;

    repaint();
    QWidget::dragLeaveEvent(event);
}

void MainWindow::dragMoveEvent(QDragMoveEvent *event)
{
    if (m_acceptableRect.contains(event->answerRect()))
        m_currentDragableAreaColor = m_highlightColor;
    else
        m_currentDragableAreaColor = m_unhighlightColor;

    repaint();
}

5. 运行结果

 

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

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

相关文章

《分布式技术原理与算法解析》学习笔记Day25

负载均衡 负载均衡是分布式可靠性中非常关键的一个问题&#xff0c;它在一定程度上反映了分布式系统对业务处理的能力。 什么是负载均衡&#xff1f; 负载均衡可以分为两种&#xff1a; 请求负载均衡&#xff0c;即将用户的请求均衡的分发到不同的服务器进行处理。数据负载…

扬帆优配|弹性增强 双向波动明显 人民币汇率走势将回归基本面

离岸人民币对美元汇率走势图 美联储加息预期起波澜&#xff0c;人民币汇率再临“7”关口。 到2月27日16时30分&#xff0c;在岸人民币对美元汇率收盘报6.9645&#xff1b;离岸人民币对美元汇率盘中最低触及6.9896&#xff0c;险些失守6.99关口。 人民币汇率走贬的一起&#x…

Odoo | Webserivce | 5分钟学会【JSONRPC】接口开发 - 换USERID(进阶)

文章目录JSONRPC - 换取USERID简述换取USERID1. 代码示例2. 换取结果JSONRPC - 换取USERID 简述 从Odoo JSONRPC 接口入门篇&#xff0c;可以发现我们直接传入了USERID&#xff0c;这只是为了方便快速测试。 其实按照常规流程&#xff0c;应该通过【用户名USERNAME】和【用户…

【LeetCode】No.237. 删除链表中的节点 – Java Version

题目链接&#xff1a;https://leetcode.cn/problems/delete-node-in-a-linked-list/ 1. 题目介绍&#xff08;237. 删除链表中的节点&#xff09; 有一个单链表的 head&#xff0c;我们想删除它其中的一个节点 node。 给你一个需要删除的节点 node 。你将 无法访问 第一个节点…

consul注册中心服务All service checks failing及解决

文章目录consul注册中心服务All service checks failing问题一&#xff1a;能注册&#xff0c;有报错&#xff0c;中间件不可用问题二&#xff1a;能注册&#xff0c;没报错&#xff0c;通不过检查问题三&#xff1a;同一个服务&#xff0c;注册了很多次consul注册中心服务All …

springBoot内容响应和内容协商原理

spring提供了15种默认返回值处理器&#xff1a; 一、处理返回值&#xff1a; this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest)二、获取对应的返回值处理器&#xff1a; private HandlerMethodReturnVa…

《第一行代码》 第九章:使用网络技术

一&#xff0c;WebView的用法 活动布局的代码&#xff1a; <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"><WebViewandroid:id&…

九龙证券|消费电子遇冷后转向动力储能赛道,但毛利率仍弱于同行

近年来&#xff0c;新能源的热度居高不下&#xff0c;顶着赛道光环&#xff0c;2月17日证监会发表信息显现&#xff0c;广州明美新能源股份有限公司&#xff08;简称明美新能&#xff09;首发上市取得通过。公司方案挂牌深交所创业板&#xff0c;并方案募资4.50亿元&#xff0c…

【RocketMQ】RocketMQ 5.0版本任意时刻延迟消息的实现原理浅析

文章目录意外发现设计方案时间轮定时消息存储具体实现流程图流程步骤意外发现 无意间从官方的最新的客户端代码中看到下面的Example&#xff1a; 感兴趣的可以看看这个介绍&#xff1a;https://rocketmq.apache.org/docs/featureBehavior/02delaymessage 生产者&#xff1a;…

【ES】Elasticsearch之数据类型

文章目录1、Mapping1.1 Mapping的作用1.2 Dynamic Mapping1.3 字段控制参数1.3.1 index1.3.2 Index Options1.3.3 null_value1.3.4 copy_to2、数据类型2.1 核心数据类型2.1.1 字符串类型2.1.2 数字类型2.1.3 日期类型2.1.3.1 date2.1.3.2 date_nanos2.1.4 布尔类型2.1.5 二进制…

java中使用protobuf总结

基本没怎么接触过java编程&#xff0c;别的团队发过来一个用java编写的存储pb的文件&#xff0c;让拆分和解析&#xff0c;硬着头皮做一下&#xff0c;在此将步骤做个记录&#xff1a;下载安装protobufhttps://github.com/protocolbuffers/protobuf/tags?afterv3.6.1.2编译pro…

Python大数据培训班特色优势及工作方向

Python大数据培训班有多个大数据培训班类型&#xff0c;同时也包括训练营、学徒班、就业班等。 具体班型&#xff1a; 大数据挖掘与人工智能&#xff08;大数据分析&#xff09;学徒班、大数据应用开发学徒班 大数据挖掘与人工智能&#xff08;大数据分析&…

网络安全从入门到精通:30天速成教程到底有多狠?你能坚持下来么?

毫无疑问&#xff0c;网络安全是当下最具潜力的编程方向之一。对于许多未曾涉足计算机编程的领域「小白」来说&#xff0c;深入地掌握网络安全看似是一件十分困难的事。至于一个月能不能学会网络安全&#xff0c;这个要看个人&#xff0c;对于时间管理不是很高的&#xff0c;肯…

DDOS攻击和CC攻击分别是什么?

CC攻击其实是DDOS攻击的一种。CC攻击的前身CC攻击的前身是一个名为Fatboy攻击程序&#xff0c;而之所以后来人们会成为CC&#xff0c;是因为DDOS攻击发展的初期阶段&#xff0c;绝大部分DDOS攻击都能被业界熟知的“黑洞”&#xff08;collapsar&#xff0c;一种安全防护产品&am…

生成和查看dump文件

在日常开发中&#xff0c;即使代码写得有多谨慎&#xff0c;免不了还是会发生各种意外的事件&#xff0c;比如服务器内存突然飙高&#xff0c;又或者发生内存溢出(OOM)。当发生这种情况时&#xff0c;我们怎么去排查&#xff0c;怎么去分析原因呢&#xff1f; 1. 什么是dump文…

云服务器迁移 (全网最省钱最详细攻略)

0x00 背景服务器续费比较贵&#xff0c;由于旧的云服务器用的时间比较长&#xff0c;上面部署的应用&#xff0c;环境复杂、数据多&#xff0c;在新的服务器部署比较麻烦&#xff0c;所以想到把服务器环境制作成镜像。新服务器的选择上&#xff0c;我这里选择的天翼云服务器&am…

IGKBoard(imx6ull)-PWM编程蜂鸣器编程控制

文章目录1- PWM介绍2- PWM使能&#xff08;1&#xff09;添加配置&#xff08;2&#xff09;export、unexport与npwm属性文件&#xff08;3&#xff09;duty_cycle、enable和period属性文件3- PWM测试编程&#xff08;1&#xff09;PWM8管脚连接&#xff08;2&#xff09;流程介…

京东JDBook笔记本怎么安装Win10系统使用?

京东JDBook笔记本怎么安装Win10系统使用&#xff1f;有用户使用的京东JDBook笔记本电脑系统是Win7系统的&#xff0c;最近想要去将系统升级到Win10来使用。那么如何将Win7的系统重装Win10呢&#xff1f;以下为大家带来详细的操作步骤图文教程。 准备工作&#xff1a; 1、U盘一个…

视频和视频帧:FFMPEG CPU解码API介绍

写在前面本文将介绍的如何用FFMPEG API做视频解码。视频解码&#xff0c;是将压缩后的视频&#xff08;压缩格式如H264&#xff09;通过对应解码算法还原为YUV视频流的过程&#xff1b;在计算机看来&#xff0c;首先输入一段01串&#xff08;压缩的视频&#xff09;&#xff0c…

用 @types 前缀的包是什么?有什么用?

前言 解决过 TypeScript 的项目大概都是从两个方向&#xff0c;Vue3 方向和 React Native 方向&#xff0c;而在 React Native 方向上我经常会遇到一个烦人的错误 Could not find a declaration file for module ‘juejin-type-study’. ‘d:/fe-project/nodejs/types-study/n…