一、父子对象API
我们在这里简单演示一下父子对象API的具体用法以及代码实现,父子对象API有五个,分别是setParent、parent、children、findChild、findChildren,接下来对每一个API都具体演示一下。
1、setParent(parent)和parent()
setParent
方法的作用就是给一个QObject对象设置一个父对象,并且每个对象的父对象只能设置一个。parent的作用就是获取某个对象的父对象,代码如下:
obj1 = QObject()
obj2 = QObject()
print("obj1", obj1)
print("obj2", obj2)
obj1.setParent(obj2) # 设置obj1的父对象为obj2
print(obj1.parent())
效果如下,因为输出的是引用,所以我们只能先打印obj1
和obj2
才能知道谁是谁的父对象:
这里提醒一下,QLabel对象不能设置QObject对象为自己的父对象,一个可见控件和一个不可见控件是不能相互设置父子关系的!!!
2、children()
children
的作用是获取某个对象的所有直接子对象
,我们可以先构造一个父子关系图,关系图如下:
构造代码如下:
obj0 = QObject()
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj4 = QObject()
obj5 = QObject()
#
print("obj0", obj0)
print("obj1", obj1)
print("obj2", obj2)
print("obj3", obj3)
print("obj4", obj4)
print("obj5", obj5)
#
obj1.setParent(obj0)
obj2.setParent(obj0)
obj3.setParent(obj1)
obj4.setParent(obj2)
obj5.setParent(obj2)
我们可以尝试输出obj4
的父亲和obj0
的孩子,代码如下:
print("obj4-parent", obj4.parent())
print("obj0-child", obj0.children()) # 获取obj0的直接子对象,只有一级
结果如下:
很明显的看出,只输出了obj0
的两个直接子对象。
3、findChild(参数1,参数2,参数3),findChildren(参数1,参数2,参数3)
findChild
函数的意思是,根据条件,在所有子对象中获取符合条件的一个子对象,或者说是获取一个指定名称和类型的子对象,即使有多个符合条件的子对象,也只会输出一个。三个参数的含义为:
参数一是子对象的类型,可以是单个类型变量(QObject)也可以是类型元祖((QPushButton, QLabel))
参数二是子对象的对象名称(或者说是对象ID),可以省略,省略的话就意味着从所有该类型变量中查找,输出查找到的第一个子对象
参数三有两个选择:
1、Qt.FindDirectChildrenOnly:默认选项,递归查找,在所有子对象中查找
2、Qt.FindDirectChildrenOnly:只在直接子对象中查找
findChildren
的参数和findChild
的一样,只不过是返回所有查找到的子对象,而不是只返回一个,我们可以实验一下这两个函数:
print(obj0.findChild(QObject)) # 找到obj0的类型为QObject的子对象,找到一个就结束
print(obj0.findChildren(QObject)) # 找到obj0的类型为QObject的所有子对象,包括子孙对象
效果如下:
我们给obj3
设置一个名称:
obj3.setObjectName("3")
按名称查找子对象:
print(obj0.findChildren(QObject, "3", Qt.FindChildrenRecursively)) # 找到obj0的类型为QObject,对象名称为3的子对象
结果如下:
二、具体案例
1、内存管理机制
所有这些控件其实是一棵QObject继承树
,所有的对象都是直接或者间接的继承自QObject,所以说QObjects在一棵对象树中组织他们自己。当创建一个QObject时,如果使用了其他对象作为父对象,那么,他就会被添加到父对象的children列表中。当父对象被销毁时,这个QObject对象也会被销毁。我们可以演示一下,在下面的代码中,obj1
是局部变量,执行完函数会立即释放,而ojb2
是obj1的子对象,被obj1所指向,不会被自动释放,我们监控obj2的释放信号,当obj2被释放时就打印信息,代码如下:
obj1 = QObject()
obj2 = QObject()
obj2.setParent(obj1)
# 监听obj2对象被释放
obj2.destroyed.connect(lambda : print("obj2对象被释放")) # 当obj2对象销毁时,执行里面的lambda函数
结果如下:
所以父对象被销毁,子对象也会被销毁。
对于QWidget组件来说,QWidget组件扩展了QObject对象的父子关系,在QWidget中,当一个控件设置了父控件时,会包含在父控件中,会受到父控件的区域裁剪(也就是子控件大小不能超过父控件),父控件被删除时子控件会自动删除。
一个对话框,上面有很多操作按钮(取消,ok等),按钮和对话框本身是父子控件关系。我们操作的时候i,是操作的对话框控件本身,而不是其内部的子控件(按钮等)。当对话框被删除时,内部的子控件也会自动的删除。
2、对Qt控件的影响
还有一个比较重要的作用就是对子控件样式的设置,可以将父控件的某一类子控件全部遍历出来,给每一个子控件都设置对应的样式,就不用一个个的去设置样式了,代码如下:
win_root = QWidget()
win_root.setWindowTitle("学习python")
win_root.resize(500, 500)
label = QLabel(win_root) # 设置父控件第一种方式
label.setText("社会我唐哥")
# label.setStyleSheet("background-color: cyan;")
label2 = QLabel(win_root)
label2.move(50, 50)
label2.setText("人狠话不多")
# label2.setStyleSheet("background-color: cyan;")
btn = QPushButton()
btn.setText("按钮")
btn.move(100, 100)
btn.setParent(win_root) # 设置父控件第二种方式
for sub_widget in win_root.findChildren(QLabel): # 给所有QLabel子对象设置背景颜色
sub_widget.setStyleSheet("background-color: cyan;")
效果如下: