简介
PyQt API 是一组包含大量类和函数的模块。核心模块如下:
- QtGui:包含了窗口系统、事件处理(QEvent)、2D 图像(QImage)、基本绘画、字体(QFont)和文字类;
- QtCore:包含所有的核心非 GUI 类;
- QtWidgets:包含一系列创建桌面应用的 UI 元素,所有的 GUI 元素都在这个模块中;
- QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类,所有的低级多媒体类倒在这个模块;
- QtNetwork:网络编程类;
- QtOpenGL:OpenGL 支持类;
- QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本;
- QtWebEngine:Qt 集成了 Web 浏览器;
- QtSql:包含整个 SQL 处理的类;
- QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具;
- QtSvg:包含显示 SVG 文件内容的类;
PyQt 库的核心就是 QtGui、QtCore 和 QtWidgets 三个模块,他们基本包含了 GUI 创建和逻辑处理所需的全部类,也是我们学习 PyQt 的核心。
PyQt5不兼容 PyQt4。PyQt5有一些巨大的改进:
- 重新组合模块,一些模块已经被废弃(QtScript),有些被分为两个子模块(QtGui, QtWebKit);
- 添加了新的模块,比如 QtBluetooth, QtPositioning,和 Enginio;
- 废弃了 SINGAL()和 SLOT()的调用方式,使用了新的信号和 xx 处理方式;
- 不再支持被标记为废弃的或不建议使用的 API;
信号与槽机制
在正式介绍 PyQt 的各个控件之前,先介绍一下 Qt 框架的信号与槽机制。信号与槽(Signal/Slots)是 Qt 编程的基础,也是 Qt 框架的一大特色。因为有了信号与槽机制的存在,在 Qt 中处理界面组件的交互操作时变得比较直观和简单。
信号(Signal)就是在特定情况下被发射(emit)的一种告示,例如 PushButton 按钮最常见的信号就是鼠标点击的时候发射的 clicked ()
信号;一个 ComboBox 最常见的信号是选择的项目发生变化的时候发射的 CurrentIndexChanged ()
信号。GUI 程序设计的主要内容就是对界面上各个组件发射的特定信号进行响应,只需要知道哪一个控件在什么情况下发射了哪些信号,然后合理地去响应这些信号即可。
槽(Slot)就是对信号响应的函数。槽的本质是一个函数,他可以直接被调用,这个和普通的函数没有什么不同,槽函数与普通函数不同的一点是:槽函数可以与一个信号关联,当信号被发射的时候,关联的槽函数会自动被执行。Qt 的类一般都有一些内建(build-in)的槽函数,例如 QWidget 有一个槽函数 close()
,其功能是关闭窗口,如果一个信号与之关联,当信号发射的时候就会关闭窗口。
信号与槽是一个非常复杂的机制,其底层就是 Qt 的事件机制,我将会在后面的博文中详细说明。
QObject
当我们打开 Qt-Designer 的时候,可以看到最顶层的 QObject 属性设置,具体如下图所示:
QObject 是所有对象的父对象,它定义了一个 QObject 是 Qt 对象模型的核心。这个模型的中心特性是一个非常强大的对象通信机制,称为信号和插槽。QObject 以对象树的形式组织自身。当创建 QObject 并将另一个对象作为父对象时,该对象将自动将其自身添加到父对象的子对象列表中,父对象取得子对象的所有权。QObject 在 Qt 中还提供了基本的定时器支持,高级定时器功能由 QTimer 进行实现。
重要方法和属性
设置控件的属性
setObjectName()
:设置控件的唯一标识符;objectName()
:获取控件的名称;setProperty()
:设置控件的一个属性;property()
:获取控件的属性;dynamicPropertyNames()
:动态的获取使用setProperty()
方法设置的属性名称。
设置父子关系
setParent()
:设置父对象。parent()
:获取父对象。children()
:获取所有的子对象。findchildren()
:查找改对象的所有子对象(可以指定查找的对象类型,还可以指定是查找直接还是所有子对象)
进行类型判断:
isWidgetType()
:判定是否是一个控件类型。inherits()
:判定一个对象时候直接/间接继承了指定的父类。
对象删除:
deleteLater()
:向主消息队列发送一个事件,下一次收到该事件的时候再进行清除。(删除对象的时候会删除任何父子关系)
定时器
startTimer()
:开启一个定时器。killTimer()
:删除定时器。timerEvent()
:定时器执行的事件。
信号
ObjectNameChanged
:对象名称发生改变的时候发出此信号。destory
:对象销毁的时候发出此信号。blockSignals
:对象临时屏蔽一个信号。
应用场景
- 用于 QSS 的 ID 选择器,方便统一设置格式;
- 控件内存管理
- 所有得到对象都可以在一个父对象中进行自我组织;
- 内存管理变得容易,当一个父对象被销毁,它的所有子对象也都被销毁了;
- 一个空间是否能够作为顶级窗口存在依赖于它是否有父控件,如果没有父控件那么它将作为顶级窗口存在;
- 简单定时器实现;
- 控件类型判断;
示例
下面的示例创建了三个 QObject 对象,并进行了如下演示:
- 设置 objectname 属性;
- 设置父子关系;
- 设置 property 属性;
# 定义三个QObject对象
widget1 = QObject()
widget2 = QObject()
widget3 = QObject()
# 设置三个控件的objectname并打印
widget1.setObjectName("widget1")
widget2.setObjectName("widget2")
widget3.setObjectName("widget3")
print(widget1.objectName()) -> widget1
print(widget2.objectName()) -> widget2
print(widget3.objectName()) -> widget3
# 设置父子关系并打印
# 只能显示直接子对象,不能显示间接子对象
widget3.setParent(widget2)
widget2.setParent(widget1)
print(widget1.children()) -> [<PyQt5.QtCore.QObject object at 0x0000026BC638D5E0>]
print(widget2.children()) -> [<PyQt5.QtCore.QObject object at 0x0000026BC638D790>]
print(widget1.children()[0].objectName()) -> widget2
print(widget2.children()[0].objectName()) -> widget3
# 设置property并打印
# 如果没有设置相应属性则返回None
widget1.setProperty("value", 1)
widget2.setProperty("value", 2)
widget3.setProperty("value", 3)
print(widget1.property('value')) -> 1
print(widget2.property('value')) -> 2
print(widget3.property('value')) -> 3
print(widget1.property('path')) -> None
下面的示例演示了 QObject 提供的定时器功能,一个 QObject 对象设置定时器,当定时器设定时间截止之后会自动调用对象的timerEvent方法(事件机制的一部分),示例源码如下:
# 定时器示例
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
# 计数器,看timerEvent的调用次数
self.counter = 0
# 设置一个1000毫秒的定时器
self.startTimer(1000, Qt.TimerType.PreciseTimer)
# 重写timerEvent方法
def timerEvent(self, event) -> None:
self.counter += 1
print(f"timerEvent第{self.counter}次调用")
if self.counter == 5:
print("调用结束,关闭窗口")
self.close()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec())
运行结果如下:
往期回顾
- 【PyQt】PyQt学习(一)框架介绍+环境搭建
文中难免会出现一些描述不当之处(尽管我已反复检查多次),欢迎在留言区指正,相关的知识点也可进行分享,希望大家都能有所收获!!