25. [Python GUI] PyQt5中拖放的基本原理

news2025/7/11 11:11:58

PyQt5的拖放

拖放涉及到的主要的一些类如下所示:

20221128012307

一、拖放的基本原理

1.1 拖放的动作

拖放操作包括两个动作:

  • 拖动(drag)
  • 放下(drop 或称为放置)。

当被拖动时拖动的数据会被存储为 MIME 类型的对象, MIME 类型使用 QMimeData 类来描述。 MIME 类型通常由剪贴板和拖放系统使用,以识别不同类型的数据。

  • 拖动点(drag site):
    拖动的起始位置。
  • 放下点(drop site):
    被拖动的对象放下的位置,若部件不能接受拖动的对象, Qt 会改变光标的形状(一个禁用形状)来向用户进行说明。

1.2 拖动的启动和结束

  • 启动拖放:
    拖放通过调用 QDrag::exec()函数而启动,该函数是一个阻塞函数(但不会阻塞主事件循环),这意味着在拖放操作结束之前,不会返回该函数,调用 QDrag::exec()函数后, Qt 拥有对拖动对象的所有权,并会在必要时将其删除。

  • 结束拖放:
    当用户放下拖动或取消拖动操作时结束拖放。

1.3 拖放产生的过程和事件

启动拖放后,会使数据被拖动,这时需要按住鼠标按键才能拖动需要拖动的数据,松开鼠标按键时意味着拖动结束。

默认情况下,部件不接受放下事件。使用 QWidget::setAcceptDrops()函数可设置部件是否接受放下事件(即,拖放完成时发送的事件)。只有在部件接受放下事件的情形下,才会产生以下事件。

  • QDragEnterEvent:拖动进入事件。
    当拖动操作进入部件时,该事件被发送到部件,忽略该事件,将会导至后续的拖放事件不能被发送。 通常在该部件上光标会在外观上显示为禁用的图形。

  • QDragMoveEvnet:拖动移动事件。
    当拖动操作正在进行时,以及当具有焦点时按下键盘的修饰键(比如 Ctrl)时, 发送该事件, 要使部件能接收到该事件,则该部件必须接受 QDragEnterEvent 事件。

  • QDropEvent:放下事件。
    在完成拖放操作时发送该事件,即当用户在部件上放下一个对象时,发送此事件。要使部件能接收到该事件,则该部件必须接受 QDragEnterEvent事件,且不能忽略 QDragMoveEvnt 事件。

  • QLeaveEvent:当拖放操作离开部件时发送该事件
    注意:要使部件能接收到该事件,必须要使拖动先进入该部件(即产生 QDragEnterEvent 事件),然后再离开该部件,才会产生 QLeaveEvent 事件。因很少使用该事件,因此本文不做重点介绍。

上文中提到的必须接受是指必须重新实现该事件的处理函数并接受该事件,不能忽略是指在处件事理函数中不明确调用 ignore()函数忽略该事件,这意味着可以不必重新实现该事件的处理函数。

以上事件产生的顺序为: QDragEnterEvent、 QDragMoveEvnet、 QDropEvent

20221128013420

1.4 编写拖放程序的步骤

  1. 在需要接受放下数据的部件上调用 QWidget::setAcceptDrops()函数以使该部件能接受拖放事件。

  2. 启动拖放: 通常在 mousePressEvent()或 mouseMoveEvent()函数中启动拖放,记住启动拖放就是调用 QDrag 对象的 exec()函数,因此也可以在 keyPressEvent()等函数中启动拖放(因很少这样做,所以本文不介绍这种情况下的拖放)。 在此步把需要拖动的数据保存在 QMimeData 对象中。

  3. 重新实现需要接受放下数据的部件的 dragEnterEvent()事件处理函数。

  4. 根据需要重新实现 dragMoveEvent 或 dropEvent()函数

1.5 简单的拖放示例代码

本示例程序示范了如何把数据从按钮A拖至按钮B:

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
from PyQt5.QtCore import QMimeData, qDebug
from PyQt5 import QtGui
from PyQt5.QtGui import QDrag
import sys

class MyButton(QPushButton):
    def __init__(self, text:str) -> None:
        super().__init__(text)
        
    def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
        '''
        在该事件中启动拖放
        '''
        # 将需要拖动的数据放入QMimeData对象中,该对象用于保存需要传递的数据
        # 数据的内容完全由程序员自行设定。通常为界面上所选择的内容。
        my_mime_data = QMimeData()
        
        # 这是QMimeData中存储的内容,即拖放的数据
        my_mime_data.setText(self.text())
        
        # 设置拖动的数据,该函数会获得QMimeData的所有权
        my_drag = QDrag(self)
        my_drag.setMimeData(my_mime_data)
        
        # 启动拖放
        my_drag.exec_()
        
    def dragEnterEvent(self, e: QtGui.QDragEnterEvent) -> None:
        '''
        处理是否接受拖动事件
        '''
        # 接受拖动进入事件
        e.accept()
        
        # 若忽略该事件,则不会再发送之后的事件,拖放至此结束,这会导致鼠标光标显示为禁用的图形
        # e.ignore()
        
    def dropEvent(self, e: QtGui.QDropEvent) -> None:
        '''
        处理拖动的数据(当然了,也可以不做任何处理)
        '''
        # 设置此部件的文本为拖动对象中的文本
        self.setText(e.mimeData().text())
        
        # 此事件不影响后续事件,可接受也可忽略
        # e.accept()
        # e.ignore()
        
class MyWidget(QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)
        self.__init_ui()
        
    def __init_ui(self):
        btn_a = MyButton('AAA')
        btn_b = MyButton('BBB')
        btn_a.setAcceptDrops(False)
        btn_b.setAcceptDrops(True)
        
        layout = QHBoxLayout()
        layout.addWidget(btn_a)
        layout.addWidget(btn_b)
        self.setLayout(layout)
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    my_widget = MyWidget()
    my_widget.show()
    sys.exit(app.exec_())

运行效果如下:

原始状态:
20221128025023

在按钮AAA上按下鼠标左键不动并拖动到图示位置,由于主窗口不接受放下事件,因此光标显示为禁用的状态
20221128025214

拖动AAA到按钮BBB上时,会发送QDragEnterEvent事件,同时光标改变形状,表示BBB按钮可以接受拖动的数据,
在按钮BBB上释放鼠标时,此时发送QDropEvent事件,按钮BBB的文本被修改为拖动对象中保存的数据。
20221128025250

至此,拖动结束。

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

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

相关文章

C++——new和delete关键字

什么是new和delete new和delete不是函数,和sizeof一样都是C定义的关键字,不同的是sizeof在编译时就可以确定其返回值,而new和delete相对复杂 示例 string *ps new string("hello world");如果换做c语言,上面这句话就…

数据库——数据库备份与恢复

目录 原因: 数据库的备份与恢复: 1、使用MySQLdump命令备份 2、恢复数据库 表的导入和导出 1、表的导出 2、表的导入 原因: 尽管采取了一些管理措施来保证数据库的安全,但是不确定的意外情况总是有可能造成数据的损失,…

数据库理论 05 关系数据库设计——基于《数据库系统概念》第七版

通过E-R图转换得出一组关系模式后 **选择1:**把一些关系模式合并为更大的关系 —— 会产生过多的数据冗余 inst_dept(ID, name, salary, dept_name, building, budget)如果通过E-R模型转换得出如下两个关系模式 sec_class(sec_id, building, room_number) and se…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java计算机专业建设管理系统3286d

面对老师五花八门的设计要求,首先自己要明确好自己的题目方向,并且与老师多多沟通,用什么编程语言,使用到什么数据库,确定好了,在开始着手毕业设计。 1:选择课题的第一选择就是尽量选择指导老师…

ThreadLocal源码解析 1.运行原理

ThreadLocal源码解析—运行原理 简介 ThreadLocal 类用来提供线程内部的局部变量,这种变量在多线程环境下访问(通过 get 和 set 方法访问)时能保证各个线程的变量相对独立于其他线程内的变量,分配在堆内的 TLAB 中。 ThreadLoc…

【Mybatis编程:根据若干个id批量删除相册(动态SQL)】

目录 1. 执行的SQL语句 2. 在AlbumMapper.java接口添加抽象方法 3. 在AlbumMapper.xml中配置以上抽象方法映射的SQL语句 4. 标签书写规范 1. 执行的SQL语句 需要执行的SQL语句大致是: delete from pms_album where id? or id? or ... id? delete from pms…

《机器学习实战》10.K-均值聚类算法

目录 利用K-均值聚类算法对未标注数据分组 K-均值聚类算法 2 使用后处理来提高聚类性能 3 二分K-均值算法 4 示例:对地图上的点进行聚类 4.1 Yahoo!PlaceFinder API 4.2 对地理坐标进行聚类 5 本章小结 本章涉及到的相关代码和数据 利用K-均值聚…

Unity基本编译环境设置(代码自动补全)

基本说明: 中国 Unity 官网下载地址:https://unity.cn/releases 请下载 Unity HUB 来管理和安装你的 Unity 各种版本 场景一: Windows系统 |Unity 2020之前的版本 |Visual Studio Community编辑器 电脑中没有任何…

并发控制常用定位方法及解决措施

并发控制常用定位方法及解决措施 7.1 排队问题 出现业务阻塞、性能下降、查询无响应等类似现网问题时,通过以下方法可以排查是否排队问题并定位排队原因,同时根据排队原因给出相应规避措施。 7.1.1 确认是否排队 首先确认是否排队问题,其…

力扣(LeetCode)2095. 删除链表的中间节点(C++)

快慢指针 设置哑结点,便于删除头结点。找到链表的中间结点,可以用快慢指针从头结点出发,慢指针最后停在中间结点。删除中间结点,应当找中间结点的前一个结点。于是想到加入哑结点,这样初始快慢指针既可以往前一个位置…

RADServer应用程序的交钥匙应用程序基础

RADServer应用程序的交钥匙应用程序基础 RADServer是快速构建和部署基于服务的应用程序的交钥匙应用程序基础。RAD Server提供自动化的Delphi和CREST/JSON API发布和管理、企业数据库集成中间件、IoT Edgeware和一系列应用程序服务,如用户目录和身份验证服务、推送通…

retimer芯片调式总结

1,主备状态是否ok。 看里面的0-3工作在Master(master Active), 4-7 工作在Master(wait master),主控0-3,备控4-7. current postion说明: typedef enum {VEGA_HMUX_SWITCH_TO_MASTER = 0,VEGA_HMUX_SWITCH_TO_SLAVE = 1,VEGA_HMUX_SWITCH_TO_PATTERN = 2,VEGA_HMUX_SWITC…

VSCode配置ssh连接本地wsl方法

1、首先需要安装插件Remote-SSH 2、其次在wsl子系统中安装ssh服务并设置允许密码登入 3、开启ssh服务并查看wsl子系统的IP地址 4、返回vscode里面的Remote SSH插件,点击下图中的那个号进行设置: 首先输入的是连接名字 ,按enter键确认之后选…

施工企业数字化转型如何避免IT技术与企业管理的“两张皮”

工程项目是建筑产业的最基本单元,企业的生产经营数据都来源于项目,通过量化建造过程中的生产、管理要素,利用IoT、BIM、大数据、AI等核心技术,实时采集现场真实、唯一、精准、有效的工程项目资金、成本、进度、质量、安全、技术等…

NET:Spire.XLS 12.11.3 supports a variety of new formulas

Spire.XLS 12.11.3 supports a variety of new formulas 发现度娘破解版Spire.XLS for .NET is a professional Excel .NET API that can be used to create, read, write, convert and print Excel files in any type of .NET ( C#, VB.NET, ASP.NET, .NET Core, .NET 5.0, .…

【纯虚函数】设计一个形状类——矩形、圆形、三角形,分别计算三种当前图形的周长和面积

目录 一、纯虚函数 抽象类 纯虚函数概念: 抽象类的概念: 二、习题 题目: 代码: 测试结果: 一、纯虚函数 抽象类 纯虚函数概念: 是指没有具体实现的虚成员函数。用于这样的情况:设计一个…

QT+Python人脸表情特征识别

程序示例精选 QTPython人脸表情特征识别 前言 QTPython是非常经典的窗体编程组合,功能完善,可视化界面美观易维护,这篇博客针对人脸表情特征识别方面编写代码,代码整洁,规则,易读,对学习与使用P…

docker安装及优化

一、docker安装步骤详解 docker初期版本是1.13&#xff08;同一版本&#xff0c;开源&#xff09; ——》分类型 1.15 - 1.17 过程中分成两种。 ①开源社区 docker-ce ②企业版 docker-ee <span style"color:#000000"><span style"background-colo…

《web结课作业的源码》中华传统文化题材网页设计主题——基于HTML+CSS+JavaScript精美自适应绿色茶叶公司(12页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

石化技术杂志石化技术杂志社石化技术编辑部2022年第10期目录

工业、生产《石化技术》投稿&#xff1a;cnqikantg126.com 衰减全反射傅里叶变换红外光谱测定溴化丁基橡胶中硬脂酸钙含量 俞培富;王晗;李振;邓洁;宋轶;姜旭鞠; 1-292 聚丙烯催化剂均聚性能实验研究 关健;付玉祥; 3-5 无损检测在石油钻具失效检验中的应用 李梅英;吕…