在PyQt中,QObject是Qt框架的核心对象之一。QObject是一个基类,它提供了对象之间的信号和槽机制、父子对象关系管理、对象属性以及事件处理等功能。
以下是QObject类的一些常用特性和功能:
信号和槽机制:QObject支持信号和槽机制,用于实现对象之间的通信。通过定义信号和槽,可以在事件发生时触发、连接和处理功能。信号可以在特定条件下被发射,而槽则是处理信号的函数。
父子对象关系:QObject支持父子对象关系的管理。可以使用setParent()
方法将一个QObject对象设置为另一个QObject对象的父对象。当父对象被销毁时,它会负责销毁其所有的子对象。
对象属性:QObject支持动态属性机制,可以通过setProperty()
方法设置对象的属性值,并可以通过property()
方法获取属性值。属性可以用于存储对象的状态或其他自定义信息。
事件处理:QObject提供了处理事件的基本机制。可以通过重写event()
或eventFilter()
方法来处理对象接收到的事件。事件可以是鼠标事件、键盘事件或其他自定义事件。
对象生命周期管理:QObject对象在创建后可以自动管理其生命周期。在Python中,当一个QObject对象没有引用时,它会被Python的垃圾回收器销毁。同时,QObject的父子关系机制也可以在父对象销毁时自动销毁子对象。
QObject是PyQt中其他重要对象(如QWidget、QThread等)的基类,它为它们提供了共享的核心功能和特性。
下面,将从以下基本程序展开演示QObject的具体使用方法:
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QLabel的学习")
self.resize(500, 500)
self.setup_ui()
# 调用以下文章自定义的函数
def setup_ui(self):
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
注意:
在以上代码中,self
代表当前实例化的Window
对象。在Python中,通过使用self
关键字,可以在类的方法中引用对象自身。
在构造函数中的super().__init__()
调用中,self
被用于传递当前对象自身给父类的构造函数,确保父类的初始化操作能够正确地处理当前对象。
如以下代码所示,在Window()
类中自定义一个QObject_Inheritance_Structure_Testing(self)
方法,在该方法中,通过调用QObject.mro()
方法,可以获取到QObject类的方法解析顺序。方法解析顺序决定了当一个方法被调用时,解释器在哪个类中找到该方法的定义。通过打印每个继承类,可以查看继承结构中各个类的排列顺序。
# QObject继承结构测试
def QObject_Inheritance_Structure_Testing(self):
mros = QObject.mro()
for mro in mros:
print(mro)
运行结果:
这些打印结果表示了QObject
类的继承关系。QObject
类继承自sip.wrapper
类,sip.wrapper
类又继承自sip.simplewrapper
类,最后都继承自object
类。继承结构定义了这些类之间的层次关系,使得QObject
类可以具有基类和扩展类提供的功能和属性。
在进行QObject
对象的名称和属性操作时,可以使用以下 API:
setObjectName(name)
: 设置对象的名称,可以用于在后续代码中查找和识别具体的对象。一般这个名称是唯一的,当做对象的ID来使用。objectName()
: 获取对象的名称。setProperty(name, value)
: 设置对象的属性,可以用于存储和传递自定义的数据。property(name)
: 获取对象的属性值。dynamicPropertyNames()
: 获取对象所有动态属性的名称列表。以下将对演示如何使用这些API:
# QObject对象名称和属性
def Operation_of_QObject_object_names_and_attributes(self):
# QObject的对象操作
obj = QObject()
obj.setObjectName("notice") # 设置对象的名称
print(obj.objectName()) # 打印对象的名称
# QObject的属性操作
obj.setProperty("notice_level", "error") # 设置了notice_level属性,其值为error,同等于notice_level="error"
obj.setProperty("notice_level2", "warning")
print(obj.property("notice_level2")) # 打印notice_level2属性的值
print(obj.dynamicPropertyNames()) # 获取对象obj的所有动态属性名称列表并打印
运行结果:
在本篇文章中,QObject对象名称和属性的主要演示的应用场景:用于qss
的ID选择器,属性选择器,方便统一设置样式。
设置qss
样式方法一:使用setStyleSheet()
方法。
label = QLabel(self)
label.setText("Hello world")
# 设置qss样式
label.setStyleSheet("font-size: 20px; color: red;")
运行结果:
通过设置qss
样式,将字体的大小变为20px,颜色变为红色。
设置qss
样式方法二
QObject.qss
文件,在文件内写入对应的qss
样式QLabel#notice {
font-size: 20px;
color: red;
}
QLabel#notice[notice_level="warning"] {
font-size: 30px;
color: yellow;
}
在以上qss
样式中,notice
为对象的名称,notice_level
和warning
为对象的属性及其值。
with open("QObject.qss", "r") as f:
qApp.setStyleSheet(f.read()) # 读取整个字符串并赋值给app全局变量
label = QLabel(self)
label.setText("Hellow world")
label.setObjectName("notice") # 设置对象名称,即ID
label2 = QLabel(self)
label2.move(100, 100)
label2.setText("PyQt5")
label2.setObjectName("notice") # 设置对象名称,即ID
label2.setProperty('notice_level', 'warning') # 设置对象的属性及其值
btn = QPushButton(self)
btn.setText("我是按钮")
btn.move(50, 50)
在以上代码中,打开名为QObject.qss
的样式表文件,读取其中的内容,并将其应用于应用程序全局变量qApp
。因为样式表文件中只设置了QLabel
的样式,所以只会匹配QLabel
对象,并根据对象的名称和属性匹配其样式。
在PyQt中,可以使用以下API来操作QObject的父子对象:
setParent(parent)
: 将当前对象设置为指定父对象的子对象。当父对象被销毁时,所有的子对象也会被自动销毁。parent()
: 返回当前对象的父对象。children()
: 返回当前对象的直接子对象列表。findChild( type, objectName)
: 在当前对象的子对象中查找指定名称和类型的对象。如果找到,则返回该对象;否则返回 None。findChildren(type)
: 在当前对象的子对象中查找指定类型的所有对象并返回一个列表。其中,findChild
和findChildren
方法是一些方便的查找子对象的API。findChild
方法需要传入待查找对象的名称和类型作为参数;而findChildren
方法只需要传入待查找对象的类型即可。这两个方法都只会查找当前对象的直接子对象,不会递归查找其子孙对象。
尝试构造以下父子关系:
# QObject父子对象的操作
def QObject_Parent_Child_Object(self):
# 创建五个QObject对象
obj0 = QObject()
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj4 = QObject()
obj5 = QObject()
print('obj0', obj0) # 打印obj0对象的地址
print('obj1', obj1)
print('obj2', obj2)
print('obj3', obj3)
print('obj4', obj4)
print('obj5', obj5, '\n')
obj1.setParent(obj0) # 设置obj1的父对象为obj0
obj2.setParent(obj0) # 设置obj2的父对象为obj0
print('obj0 children: ', obj0.children(), '\n') # 查看obj0的直接子对象列表
print('未修改父对象前,父对象:', obj2.parent()) # 未修改父对象前
obj2.setParent(obj1)
print('修改父对象后,父对象:', obj2.parent(), '\n') # 修改父对象后
print('obj0 children: ', obj0.children()) # 修改obj2的父对象后,查看obj0的直接子对象列表
obj3.setParent(obj1) # 设置obj3的父对象为obj1
obj4.setParent(obj2) # 设置obj4的父对象为obj2
obj5.setParent(obj2) # 设置obj5的父对象为obj2
在以上代码中,设置了两次obj2的父对象,第一次设置的父对象为obj0,第二次设置的父对象为obj1。
运行结果:
从运行结果可看出,一个对象,它的父对象只能有一个,且以最后设置的父对象为主。
再观察以下代码,学习findChild(objectName, type)
和findChildren(type)
的使用:
# QObject父子对象的操作
def QObject_Parent_Child_Object(self):
# 创建五个QObject对象
obj0 = QObject()
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj4 = QObject()
obj5 = QObject()
print('obj0', obj0) # 打印obj0对象的地址
print('obj1', obj1)
print('obj2', obj2)
print('obj3', obj3)
print('obj4', obj4)
print('obj5', obj5, '\n')
obj1.setParent(obj0) # 设置obj1的父对象为obj0
obj2.setParent(obj0) # 设置obj2的父对象为obj0
obj2.setObjectName("2") # 设置obj2对象的名称为2
obj3.setParent(obj1) # 设置obj3的父对象为obj1
obj4.setParent(obj2) # 设置obj4的父对象为obj2
obj5.setParent(obj2) # 设置obj5的父对象为obj2
print(obj0.findChild(QObject)) # 返回第一个子对象,即返回obj1的地址
print(obj0.findChild(QObject, "2")) # 获取obj0的QObject类型且对象名称为2的子对象
print(obj0.findChild(QObject, "3")) # 获取obj0的QObject类型且对象名称为3的子对象,没有时返回None
print(obj0.findChildren(QObject)) # 获取obj0的所有QObject类型的子对象
运行结果:
在PyQt中,信号与槽(Signals and Slots)是一种用于实现对象间通信的机制。信号是由发送者发出的消息,而槽是接收信号并对其做出响应的方法。以下是PyQt中常用的信号与槽相关的API:
信号(Signal)相关的API:
pyqtSignal()
: 创建一个自定义信号。emit()
: 发出信号,即调用信号对象的emit()
方法。槽(Slot)相关的API:
@pyqtSlot()
: 将一个方法声明为槽函数。connect()
: 连接一个信号与一个槽函数。disconnect()
: 断开一个信号与一个槽函数的连接。sender()
: 返回发出信号的对象。blockSignals(bool)
: 暂时阻塞或取消阻塞信号。receivers(sign)
:返回连接到信号的接收器数量信号与槽的连接相关的API:
QMetaObject.connectSlotsByName(self, obj)
: 通过对象的命名约定自动连接信号与槽函数。# QObject的信号与槽
def Signal_and_slot_of_QObject(self):
self.obj = QObject()
def destroy_slot(obj):
print('对象被释放了', obj)
def obj_name_slot(name):
print('对象名称发生了改变', name)
self.obj.objectNameChanged.connect(obj_name_slot) # 建立与obj_name_slot槽函数的连接
self.obj.destroyed.connect(destroy_slot) # 建立与destroy_slot槽函数的连接
self.obj.setObjectName('xxx')
self.obj.objectNameChanged.disconnect() # 取消连接
self.obj.setObjectName('yyy')
self.obj.objectNameChanged.connect(obj_name_slot) # 再次建立与槽函数的连接
self.obj.setObjectName('xxyy')
self.obj.blockSignals(True) # 临时阻断连接
self.obj.setObjectName('111')
self.obj.blockSignals(False) # 重新连接
self.obj.setObjectName('222')
print(self.obj.receivers(self.obj.objectNameChanged)) # 获取objectNameChanged信号绑定的槽函数数量
del self.obj
运行结果: