当前位置:首页>python>7天上手PyQt6 Python 桌面应用开发之PyQt6 高级应用

7天上手PyQt6 Python 桌面应用开发之PyQt6 高级应用

  • 2026-09-03 06:33:50
7天上手PyQt6 Python 桌面应用开发之PyQt6 高级应用

概述

从核心基类 QObject 的底层原理,到信号槽的通信魔法,再到 QTimer 定时任务与 PyInstaller 打包发布,带你吃透 PyQt6 工程化开发的关键技能,让你的桌面应用从 Demo 走向可交付成品!

PyQt6 高级应用

(一)基类 QObject 类介绍以及应用

QObject 是 Qt 库中最重要的类之一。作为所有 Qt 类的基类,QObject 提供了信号槽机制、对象树、动态属性、元对象系统、事件处理机制、线程安全、国际化等许多重要特性,这些特性可以帮助开发者轻松实现模块间通信、组件化、程序设计以及事件处理等方面的功能。

在 Qt 框架下编程,不管用不用到 Qt 的特性,都推荐自定义类继承 QObject 类,这样在需要的时候,就可以随时使用 Qt 基于 QObject 类提供的各种特性和机制,而且可以让自定义的类很好地融入到 Qt 的框架之中。

具体来讲,QObject 主要实现了以下特性:

  1. 信号槽机制:QObject 通过定义信号(signal)和槽(slot)来实现对象间的通信。当信号被触发时,与该信号相对应注册的槽函数将会被自动调用。一个信号可以连接到多个槽函数上,也可以将多个信号连接到同一个槽函数。信号 / 槽机制是 Qt 中最强大和最独特的功能之一,可以帮助开发者在不同的对象之间进行通信,处理事件等。

  2. 对象树:QObject 支持管理对象树结构的方式。它允许对象包含一个父对象和零个或多个子对象。当父对象被删除时,其所有子对象也会被自动销毁。这个特性使得我们在 Qt 程序中组织和管理 QObject 及其子类之间的依赖关系变得更容易。

  3. 动态属性:QObject 支持添加动态属性。这意味着,除了一组已经存在的静态属性之外,每个对象实例还可以动态地创建和设置新的属性,这些属性不需要在编译器层面进行定义和声明。这种灵活性使得 QObject 能够适应各种场景的需求。

  4. 元对象系统:元对象系统(Meta-Object System)是 QObject 的另一个重要特性。它为每个 QObject 和其子类提供运行时类型信息,包括对象的类名、属性、方法和信号等信息,这些信息都可以在运行时被访问或者修改。元对象系统赋予了 Qt 框架独特的能力,例如能够自动序列化和反序列化对象及其成员等,同时也是实现 Qt 信号槽机制的关键技术。

  5. 事件处理机制:QObject 支持通过发送和接收事件来实现对象间的通信。Qt 中的事件是指某种对象发生的一些动作或状态变化,通常包含一个事件类型和一些参数。QObject 可以捕获并处理各种类型的事件,也可以派发(dispatch)事件给其他对象进行处理。

  6. 线程安全:QObject 被设计为线程安全的基础构建单元。这意味着 QObject 默认可以在多线程环境下直接使用,而无需考虑同步问题。但是,如果需要在不同线程之间交互对象,还是需要小心地设计和管理线程模型。

  7. 国际化:QObject 提供国际化(Internationalization /i18n)函数,帮助开发人员使应用程序能够方便地本地化,支持多语言切换。i18n 函数提供消息翻译,日期和时间格式化以及数字格式转换等功能。

补充方法说明

QObject 的 setObjectName() 方法用于设置对象名称,理论上不可以重复。在给控件设置样式的时候,可以用到这个对象属性。

测试代码标识

UI 生成测试代码:

QObject 常用方法

注:QObject 是 Qt 所有对象的基类(非可视化控件),核心作用是为所有 Qt 对象提供核心能力(信号与槽、父子对象管理、属性 / 名称设置、事件处理等),是 Qt 框架的基础核心类,以下是其高频实用方法:

  1. setObjectName ():设置对象的唯一名称标识,传入字符串(如setObjectName("main_btn")),用于通过名称查找对象、样式表精准匹配控件,是对象标识的核心方法。

  2. objectName ():获取对象的名称标识,返回字符串,用于校验对象名称、通过名称定位对象(如findChild())。

  3. setParent ():设置当前对象的父对象,传入 QObject 子类对象(如setParent(main_window)),管理对象生命周期(父对象销毁时自动销毁子对象)、构建对象树。

  4. parent ():获取当前对象的父对象,返回 QObject 对象(无父对象则返回 None),读取对象的层级归属。

  5. children ():获取当前对象的所有直接子对象列表,返回List[QObject],遍历子对象(如批量修改子控件属性)。

  6. findChild ():查找指定类型 + 名称的直接 / 间接子对象,参数为(对象类型, 名称, 查找选项)(如findChild(QPushButton, "submit_btn")),精准定位子对象。

  7. findChildren ():查找所有指定类型 + 名称的直接 / 间接子对象,返回列表(如findChildren(QLineEdit)),批量获取同类型子对象。

  8. deleteLater ():标记对象为待销毁,在 Qt 事件循环空闲时销毁对象(安全销毁,避免内存泄漏),是 Qt 推荐的对象销毁方式。

  9. connect ():绑定信号与槽函数,核心方法(如btn.clicked.connect(self.on_click)),实现对象间的事件通信,支持多信号绑定、参数传递。

  10. disconnect ():断开信号与槽函数的绑定,参数为(信号, 槽函数)(如btn.clicked.disconnect(self.on_click)),停止指定的事件通信。

  11. sender ():在槽函数中获取触发信号的源对象,返回 QObject 对象,识别是哪个对象触发了当前槽函数(如多个按钮绑定同一槽函数时区分来源)。

  12. setProperty ():设置对象的自定义属性,参数为(属性名, 属性值)(如setProperty("status", "active")),为对象添加额外的自定义数据。

  13. property ():获取对象的自定义属性值,传入属性名返回值(如property("status")),读取自定义数据。

  14. dynamicPropertyNames ():获取对象所有自定义属性的名称列表,返回List[QByteArray],遍历所有自定义属性。

  15. installEventFilter ():为对象安装事件过滤器,传入 QObject 子类对象(需重写eventFilter()),拦截并处理对象的所有事件(如拦截按钮点击、键盘输入)。

  16. removeEventFilter ():移除已安装的事件过滤器,传入过滤器对象,停止事件拦截。

  17. event ():处理对象的原始事件(需重写),返回布尔值(True 表示事件已处理,False 表示继续传递),自定义事件处理逻辑。

  18. eventFilter ():事件过滤器的核心方法(需重写),参数为(目标对象, 事件),返回布尔值,实现对目标对象事件的拦截 / 修改。

  19. timerEvent ():处理定时器事件(需重写),参数为 QTimerEvent 对象,自定义定时器触发后的逻辑。

  20. startTimer ():启动定时器,传入定时时长(ms),返回定时器 ID,触发周期性的timerEvent()。

  21. killTimer ():停止指定 ID 的定时器,传入定时器 ID,终止周期性事件触发。

  22. metaObject ():获取对象的元对象,返回 QMetaObject 对象,用于反射(如获取对象类名、属性列表、信号槽信息)。

  23. className ():获取对象的类名称(字符串),如obj.className()返回 "QPushButton",识别对象类型。

  24. inherits ():判断对象是否继承自指定类,传入类名 / 类对象返回布尔值(如obj.inherits("QWidget")),校验对象的继承关系。

  25. isWidgetType ():判断对象是否为 QWidget 子类(可视化控件),返回布尔值,区分可视化 / 非可视化对象。

  26. isWindowType ():判断对象是否为窗口类(QWindow/QMainWindow 等),返回布尔值,识别窗口对象。

  27. thread ():获取对象所属的线程,返回 QThread 对象,识别对象运行的线程环境。

  28. moveToThread ():将对象移动到指定线程,传入 QThread 对象,实现对象的跨线程操作(需遵循 Qt 线程规则)。

总结

QObject 核心用法:setObjectName()设置对象标识、setParent()管理父子对象、connect()/disconnect()绑定 / 断开信号槽、deleteLater()安全销毁对象,是最基础且高频的操作;

(二)信号与槽

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。

一个信号可以连接到多个槽函数上,也可以将多个信号连接到同一个槽函数。

这个槽的话,也分两种,一种是不同控件内置的槽函数,还有一种是我们自己定义的槽函数。

控件内置的槽编辑器,我们菜单 视图 -> 信号 / 槽 编辑器 点开。

(三)QTimer 计时器控件

QTimer 常用方法

注:QTimer 是定时器控件(非可视化),核心作用是触发周期性或一次性的定时任务(如倒计时、数据刷新、动画帧更新),基于 Qt 事件循环实现,是界面定时操作的核心组件,以下是其高频实用方法:

  1. setInterval ():设置定时器触发间隔(核心方法),传入整数(单位:毫秒),如setInterval(1000)(每 1 秒触发一次),定义定时周期。

  2. interval ():获取当前定时器的触发间隔,返回整数(毫秒),校验定时周期配置是否符合预期。

  3. start ():启动定时器,无参数时使用已设置的 interval,也可传入整数临时指定间隔(如start(500)),是触发定时任务的核心操作。

  4. stop ():停止定时器,终止后续的定时触发,适配需要暂停定时任务的场景(如暂停倒计时)。

  5. setSingleShot ():设置是否为单次触发模式,传入布尔值(True = 单次触发,False = 周期性触发(默认)),如setSingleShot(True)(仅触发一次后自动停止),适配一次性定时任务(如延迟提示)。

  6. isSingleShot ():判断是否为单次触发模式,返回布尔值,校验触发模式配置。

  7. isActive ():判断定时器是否处于激活状态(正在运行),返回布尔值,校验定时器是否在工作。

  8. remainingTime ():获取定时器距离下次触发的剩余时间,返回整数(毫秒,未激活则返回 - 1),读取定时任务的剩余时长(如倒计时剩余秒数)。

  9. setTimerType ():设置定时器类型,核心枚举值:

  10. QTimer.TimerType.PreciseTimer:高精度定时器(优先保证精度,占用更多资源);

  11. CoarseTimer:普通精度定时器(误差 ±5%,默认);

  12. VeryCoarseTimer:低精度定时器(误差 ±1 秒),适配不同精度需求的场景。

  13. timerType ():获取当前定时器类型,返回枚举值,校验精度配置。

  14. timeout.connect ():绑定定时器触发信号,核心交互方法(如timer.timeout.connect(self.update_data)),定时器触发时执行绑定的槽函数。

  15. timeout.disconnect ():断开定时器触发信号与槽函数的绑定,停止指定槽函数的定时执行(如timer.timeout.disconnect(self.update_data))。

  16. setParent ():设置定时器的父对象,传入 QObject 子类对象(如setParent(main_window)),管理定时器生命周期(父对象销毁时自动停止并销毁定时器)。

  17. parent ():获取定时器的父对象,返回 QObject 对象,读取定时器的归属层级。

  18. deleteLater ():标记定时器为待销毁,在 Qt 事件循环空闲时销毁(安全释放资源,避免内存泄漏),是 Qt 推荐的销毁方式。

  19. static singleShot ():静态快捷方法,无需手动实例化 QTimer,直接创建单次触发的定时任务,如QTimer.singleShot(2000, self.show_tip)(2 秒后执行 show_tip 函数),简化单次定时任务开发。

总结

QTimer 核心用法:setInterval()设置定时间隔、start()/stop()启动 / 停止定时器、timeout.connect()绑定定时触发的槽函数,是最基础且高频的操作;

(四)利用 Pyinstaller 打包发布程序

准备工作

PyQt6 程序的打包发布,即将.py 代码文件打包成可以直接双击执行的.exe 文件,在 Python 中并没有内置可以直接打包程序的模块,而是需要借助第三方模块实现。打包 Python 程序的第三方模块有很多,其中最常用的就是 Pyinstaller。

安装 Pyinstaller

pip install Pyinstaller 

-i https://pypi.tuna.tsinghua.edu.cn/simple

打包普通 Python 程序

普通 Python 程序指的是完全使用 Python 内置模块或者对象实现的程序,程序中不包括任何第三方模块。

使用 Pyinstaller 打包普通 Python 程序的步骤如下。

打开系统的 CMD 命令窗口,使用 cd 命令切换到.py 文件所在路径(如果.py 文件不在系统盘 C 盘,需要先使用 “盘符:” 命令来切换盘符),然后输入 “pyinstaller -F 文件名.py” 命令进行打包

下面是一些常用的命令行选项:

-F:将所有文件打包为一个单独的可执行文件。

-D:将所有文件打包为一个目录,包含可执行文件和所有依赖的文件。

-c:将程序与命令提示符结合在一起,以便在命令提示符下运行。

-d:将调试信息打包进可执行文件中。

-onefile:将所有文件打包为一个单独的可执行文件。

-o:指定输出文件的位置。

-w:打包为窗口文件。

-p DIR, --path=DIR:设置导入路径,从而导入需要的模块

测试代码4.HelloWord.py

打包命令:

pyinstaller -F 4.helloworld.py

打包 PyQt6 程序

前面使用 “pyinstaller -F” 命令可以打包没有第三方模块的普通 Python 程序,但如果程序中用到了第三方模块,在运行打包后的.exe 文件时就会出现找不到相应模块的提示。

我们就以打包 PyQt6 程序为例进行详细讲解。

PyQt6 是一个第三方的模块,可以设计窗口程序,因此在使用 pyinstaller 命令打包其开发的程序时,需要使用 --paths 指定 PyQt6 模块所在的路径;另外,由于是窗口程序,所以在打包时需要使用 - w 指定打包的是窗口程序,还可以使用 --icon 指定窗口的图标。

pyinstaller --paths PyQt6模块路径 -F -w 

--icon=窗口图标文件 文件名.py

参数说明:

  • --paths:指定第三方模块的安装路径。

  • -w:表示窗口程序。

  • --icon:可选项,如果设置了窗口图标,则指定相应文件路径;如果没有,则省略。

  • 文件名.py:窗口程序的入口文件。

执行报错,找不到ui文件。 这里注意,所有的项目资源文件,包括Ui,图片等资源文件,都要放到dist目录下。

部分应用打包也可能不需要指定PyQt6模块路径pymysql模块路径,这跟版本有关系

这里打包一个table表格案例

pyinstaller -F -w 10.QTableWidget表格控件Main.py

结束语

1

后续我会持续输出优质、实用的内容,也欢迎大家在评论区留言,说说你们最想学习的内容、遇到的困惑,我们一起交流、一起进步。

愿每一位软件人,都能在这里收获知识、突破自我,在自己的赛道上发光发热✨

最新文章

随机文章