Sub Widget and Sub Layout#
在一个大型 Widget 中, 里面可能包含很多小的 Widget, 这些小的 Widget 都有各自的 Layout. 把逻辑类似的小的 Widget 放在一可复用的类中是一种很好的组织代码的方式. 但是这里有几个很细的问题, 但是会使得最终呈现的效果差别巨大. 这里我们直接把结论放在这里, 如果你已经了解这其中的细节了, 你可以直接参考这里的结论. 而如果你不了解细节, 则建议运行示例代码来查看两者的区别:
把很多 Widget 组织到一起的时候, 是开一个随便什么 Class, 还是一定要开一个
PySide6.QtWidgets.QWidget
的子类呢?- 你可以用一个 Widget 实例来组织多个子 Widget, 把他们都变成自己的属性既可. 但这个父 Widget 本身有一个
setLayout
的方法. 这里有两种做法: 在父 Widget 中调用
setLayout
方法, 然后在 Root Widget 中的 Layout 中, 使用addWidget(父Widget)
将父 Widget 添加进来.在父 Widget 仅仅是把 Layout 作为一个属性设置好, 但是不调用
setLayout
. 然后在 Root Widget 中的 Layout 中, 使用addLayout(父Widget.main_layout)
将父 Widget 的 Layout 添加进来.
- 你可以用一个 Widget 实例来组织多个子 Widget, 把他们都变成自己的属性既可. 但这个父 Widget 本身有一个
结论: 这两个问题其实是一个问题. 如果你希望让这些被组织到一起的 Widget 限制在一个隐形的方框容器中, 那么就用 PySide6.QtWidgets.QWidget
+ root_widget.addWidget()
的方式. 这样会将父 Widget 作为一个有边界的整体, 从 Root Widget 是无法直接触碰到 父 Widget 里面的小 Widget 的. 而如果你只是想增加代码复用, 那么你用随便什么 Class 都可以, 仅仅是作为一个内存中的数据容器. 然后用 root_widget.addLayout()
的方式将父 Widget 的 Layout 添加进来.
sub_widget_and_sub_layout_1_1.py
1# -*- coding: utf-8 -*-
2
3"""
4这是一个用于演示对于拥有自己一套 layout 的子 widget, 在父 widget 中什么时候应该用 addWidget,
5什么时候应该用 addLayout 的演示. 这个例子要用
6``sub_widget_and_sub_layout_1_1.py`` 和 ``sub_widget_and_sub_layout_1_2.py``
7一起比较来看才能看出区别.
8
9这个例子是在子 widget 用使用 setLayout 方法定义子 widget 的 layout, 然后在父 widget 中使用
10addWidget 方法添加子 widget 到父 widget 中.
11
12结论, 子 widget 有一个隐形的方框, 并且有 margin, 所以看起来要离最外面的边框远一点.
13"""
14
15from PySide6.QtWidgets import (
16 QWidget,
17 QLabel,
18 QVBoxLayout,
19 QMainWindow,
20)
21from PySide6 import QtWidgets
22import sys
23
24
25class LabelListWidget(QWidget):
26 def __init__(self, parent, ith: int):
27 super().__init__(parent)
28 self.ith = ith
29
30 self.main_layout = QVBoxLayout()
31
32 for j in range(1, 1 + 3):
33 label_wgt = QLabel(f"Label {self.ith}-{j}", parent=parent)
34 self.main_layout.addWidget(label_wgt)
35
36 self.setLayout(self.main_layout)
37
38
39class MainWidget(QWidget):
40 def __init__(self, parent):
41 super().__init__(parent)
42 self.label_list_1 = LabelListWidget(self, ith=1)
43 self.main_lay = QVBoxLayout()
44 self.main_lay.addWidget(self.label_list_1)
45 self.setLayout(self.main_lay)
46
47
48class MainWindow(QMainWindow):
49 def __init__(self):
50 super().__init__()
51 self.main_wgt = MainWidget(self)
52 self.main_wgt.setStyleSheet("Border: 1px solid black;")
53 self.setCentralWidget(self.main_wgt)
54 self.setWindowTitle("Sub Widget and Sub Layout Example 1-1")
55 self.show()
56
57
58if __name__ == "__main__":
59 app = QtWidgets.QApplication(sys.argv)
60 main = MainWindow()
61 sys.exit(app.exec())
sub_widget_and_sub_layout_1_2.py
1# -*- coding: utf-8 -*-
2
3"""
4这是一个用于演示对于拥有自己一套 layout 的子 widget, 在父 widget 中什么时候应该用 addWidget,
5什么时候应该用 addLayout 的演示. 这个例子要用
6``sub_widget_and_sub_layout_1_1.py`` 和 ``sub_widget_and_sub_layout_1_2.py``
7一起比较来看才能看出区别.
8
9这个例子是在子 widget 不使用 setLayout 方法, 而只是定义子 widget 中的 main_layout 的定义,
10然后再然后在父 widget 中使用 addLayout 方法添加子 widget 的 layout 到父 widget 的 layout 中.
11
12结论, 子 widget 有一个隐形的方框, 由于这里没有用子 widget, 而是直接将子 widget 中的 子 widget
13的元素加到总的 layout 中取, 所以看起来离外面的边框近一点.
14"""
15
16from PySide6.QtWidgets import (
17 QWidget,
18 QLabel,
19 QVBoxLayout,
20 QMainWindow,
21)
22from PySide6 import QtWidgets
23import sys
24
25
26class LabelListWidget(QWidget):
27 def __init__(self, parent, ith: int):
28 super().__init__(parent)
29 self.ith = ith
30
31 self.main_layout = QVBoxLayout()
32
33 for j in range(1, 1 + 3):
34 label_wgt = QLabel(f"Label {self.ith}-{j}", parent=parent)
35 self.main_layout.addWidget(label_wgt)
36
37
38class MainWidget(QWidget):
39 def __init__(self, parent):
40 super().__init__(parent)
41 self.label_list_1 = LabelListWidget(self, ith=1)
42 self.main_lay = QVBoxLayout()
43 self.main_lay.addLayout(self.label_list_1.main_layout)
44 self.setLayout(self.main_lay)
45
46
47class MainWindow(QMainWindow):
48 def __init__(self):
49 super().__init__()
50 self.main_wgt = MainWidget(self)
51 self.main_wgt.setStyleSheet("Border: 1px solid black;")
52 self.setCentralWidget(self.main_wgt)
53 self.setWindowTitle("Sub Widget and Sub Layout Example 1-2")
54 self.show()
55
56
57if __name__ == "__main__":
58 app = QtWidgets.QApplication(sys.argv)
59 main = MainWindow()
60 sys.exit(app.exec())