一、布局管理器的作用
PySide6包含一组布局管理类,用于描述小部件在应用程序中的布局方式,当小部件的可用空间发色和那个变化时,这些布局会自动定位和调整小部件的大小,确保它们的排列一致,并且用户界面作为一个整体仍然可用(比如一个按钮被放大了好多倍,但是功能一样可以使用且不变),主要是确保主界面尺寸变化,界面中的各个部件尺寸变化后,尽可能地比较协调及美观。
所有的QWidget子类都可以使用布局来管理它们的子类,使用QWidget.setLayout()函数可以把布局应用到小部件。当以这种方式在Widget上设置布局时,它负责以下任务:
1、子部件的定位。
2、合理化窗口的默认尺寸。
3、合理化窗口的最小尺寸。
4、调整窗口的大小。
5、内容更改时自动更新:
- 子部件的字号、文本或者其它内容
- 隐藏或者显示子部件
- 删除子小部件。
二、PySide6中的布局类:
Pyside6中有很多布局类,允许以像素为单位指定测量值,而且支持QtDesigner,主要有如下:
QLayout-----------------------------布局管理器的基类,一般不单独使用,由具体类继承
QLayoutItem-----------------------QLayout操作的抽象类
QBoxLayout------------------------水平或者垂直排列子部件
QButtonGroup---------------------用于组织按钮小部件组的容器
QFormLayout----------------------用于输入小部件机器相关标签的形式
QGraphicsAnchor-----------------表示在QGraphicsAnchorLayout中两个项目之间的锚点
QGraphicsAnchorLayout--------可以在图形视图中将小部件锚定在一起布局
QGridLayout------------------------在网格中布局小部件
QGroupBox--------------------------带有标题的分组框
QHBoxLayout-----------------------水平排列小部件,是QBoxLayout类的子类
QVBoxLayout------------------------垂直排列小部件,是QBoxLayout类的子类
QSizePolicy--------------------------描述水平和垂直方向调整策略的布局属性
QSpacerItem------------------------布局中的空白
QStrackedLayout------------------一堆小部件,一次只能看到一个小部件
QStrackedWidget------------------一堆小部件,一次只能看到一个小部件
QWidgetItem------------------------代表小部件的布局项
三、QLayout及其子项
QLayout是布局管理器的基类,它一般不会单独使用,是由具体类QBoxLayout、QGridLayout、QFormLayout和QStrackedLayout继承的抽象基类。这些布局方式对应如下的布局类:
- 水平/垂直布局类(QBoxLayout):可以把所添加的控件在水平/垂直方向上依次排列。它有两个子类,即QHBoxLayout和QVBoxLayout。
- 网格布局类(QGridLayout):可以把所添加的控件以网格的形式排列。
- 表单布局类(QFormLayout):可以把所添加的控件以两列的形式排列。
- 堆叠布局类(QStrackedLayout):可以用于创建类似于QTabWidget提供的用户界面。
四、布局的整个过程
向布局管理器添加小部件时,布局过程如下:
1、所有小部件最初将根据它们在函数QWidget.setPolicy()和QWidget.sizeHint()分配一定的空间。
2、如果存在小部件设置了拉伸因子 stretch >0 ,那么它们将按照哦啊其拉伸因子的比例分配空间。
3、如果所有小部件的拉伸因子设置为 0 ,那么它们只会在没有其它小部件需要空间的情况下获得更多空间。其中空间首先分配给具有扩展大小策略(Expanding Size Policy) 的小部件。
4、如果小部件分配的空间小于其最小尺寸(最小尺寸如果未指定minimum size 则由minimum size hint 提供),那么小部件会被分配到它所需要的最小尺寸(若小部件没有设置minimum size 或mininum size hint ,则其大小由拉伸因子决定)
5、任何分配的空间大于最大尺寸的小部件,都将分配到它们所需的最大尺寸(若小部件没有设置maximum size ,在这种情况下,拉伸因子其决定作用)
五、sizePolicy和sizeHint 的理解
sizeHint保存小部件的推荐大小,如果该值无效,则没有尺寸建议。如果此小部件没有布局,则sizeHint()默认返回无效大小,否则返回布局的首选大小。
sizePolicy保存小部件的默认布局行为,如果有一个QLayout管理这个小部件的子部件,则使用该布局指定的sizePolicy。如果没有QLayout管理,则使用sizePolicy的结果。
sizePolicy的默认策略是Preferred/Preferred(首先/优先),这意味着Widget可以自由调整大小,但更倾向sizeHint()返回的大小。类似按钮的小部件设置大小的策略可以指定它们的水平拉伸,但是垂直固定。这同样适用于LineEdit控件(如QLineEdit、QSpinBox、QComboBox)和其它水平方向的小部件(如QProgressBar)。QToolBarButton通常是方形,因此它允许在两个方向上增长。支持不同方向的小部件(如QSlider、QScrollBar、QHeader)仅指定在相应方向上的拉伸。
六、Q(V/H)BoxLayout
采用QBoxLayout 可以在水平和垂直方向上排列控件,它的两个子类为QHBoxLayout和QHBoxLayout,分别是水平和垂直布局。
使用QBoxLayout需要在初始化过程中传递方向参数,参数值(0/1/2/3)分别代表从左到右水平排列、从右到左水平排列、从上到下垂直排列,从下向上垂直排列。
更简单的方法是使用QHBoxLayout/QVBoxLayout,就可以不用传递参数。
如果QBoxLayout不是顶级布局,则必须先将其添加到其父布局中,然后才能对其进行操作,添加布局的常规方式是调用父布局的.addLayout()函数。特别说明的是,对于继承MainWindow的主窗口,主窗口不能直接添加QBoxLayout这类布局对象, 继承MainWindow的主窗口,有一个中央布局窗口,这个窗口是这类布局对象的父布局。而继承Widget类对象的主窗口,可以直接添加QBoxLayout布局对象。
使用以下4个函数中一个可以向QBoxLayout布局对象中添加对象(控件)或者嵌套子布局对象。
1、addWidget(arg__1:QWidget,stretch:int=0,alignment:Qt.Alignment=Default(Qt.Alignment))
上面的方法(函数)将其它小部件(QWidget的子类控件)添加到Q(V/H)BoxLayout中,并且可以根据需要设置拉伸因子和对齐方式,stretch参数是拉伸因子,只在QBoxLayout中的方向上有小,并且是在QBoxLayout中相对于其它控件的拉伸。stretch的默认值为0,如果添加的所有部件的stretch的值都是0,则Qt会根据每个小部件的QWidget.sizePolicy()函数分配空间。stretch值越大的部件会有更大的比例进行拉伸。参数alignment用于控制部件的对齐方式,一次最多可以使用一个水平标志和一个垂直标志,如alignment = Qt.AlignLeft | QtAlignTop,表示水平方向上左对齐和垂直方向上靠上对齐。
2、addSpacing(size:int):创建一个空框,这个框不可以随着窗口的大小而改变。
3、addStretch(stretch:int):创建一个空框,可以根据窗口的大小自动伸缩,伸缩比例由拉伸因子stretch的值决定。
4、addLayout(layout:QWidget.QLayout,stretch:int=0):将包含一个QLayout的框添加(嵌套)到QBoxLayout中,并且可以根据需要设置拉伸因子stretch。
边距默认值由样式提供,小部件的默认边距是9像素,窗口的默认边距是11像素,间距默认与顶级布局边距宽度相同,或者与父布局相同。QBoxLayout提供了一下2个函数用来修改边距。
(1)setContentsMargins():用于设置QBoxLayout每侧的外边框的宽度,这是沿QBoxLayout的4个边上的保留空间的宽度。
代码如下:
‘’‘
setContentsMargins(self,left:int,top:int,rigth:int,bottom:int) -->None
’‘’
# 设置边距,距离左边的对象10像素,距离上面的对象20像素,距离右侧对象40像素,距离下面对象60像素
layout.setContentsMargins(10,20,40,60)
(2)setSpacing():用于设置QBoxLayout内相邻框之间的宽度(可以使用addSpacing或者insertSpacing在特定的位置设置更多的空间)。
要从布局中删除小部件,可以调用removeWidget()函数。在小部件上调用QWidget.hide()可以在布局中隐藏小部件,调用QWidget.show()函数则可以取消隐藏。
七、一个案例代码:
特别注意:水平布局中的前三个按钮,窗口拉伸,仅第二个按钮大小会拉伸,咨询文言一心等大模型也没有给出很好的答案,经过测试,如果在addWidget('按钮控件',stretch=i,alignment=*)中设置了alignment属性,按钮大小就不会被拉伸,而是附近空间拉伸。
# -*- coding: utf-8 -*-
"""
【简介】
QBoxLayout布局管理例子,QHBoxLayout是主布局,添加到窗口,QVBoxLayout布局做为子布局,嵌套到水平布局中。
"""
import sys
from PySide6.QtWidgets import *
from PySide6.QtCore import Qt
class BoxLayoutDemo(QWidget):
def __init__(self, parent=None):
super(BoxLayoutDemo, self).__init__(parent)
self.setWindowTitle("Q(H/V)BoxLayout布局管理例子")
self.resize(800, 200)
# 水平布局按照从左到右的顺序进行添加按钮部件。
layout = QHBoxLayout()
# addWidget
layout.addWidget(QPushButton('按钮一'), stretch=1, alignment=Qt.AlignLeft | Qt.AlignTop)
layout.addWidget(QPushButton('按钮二'), stretch=1)
layout.addWidget(QPushButton('按钮三'), alignment=Qt.AlignRight | Qt.AlignBottom)
# addStretch
layout.addStretch(2)
layout.addWidget(QPushButton('按钮四'), stretch=1, alignment=Qt.AlignTop)
layout.addStretch(1)
layout.addWidget(QPushButton('按钮五'), stretch=2)
# addSpacing
layout.addSpacing(10)
layout.addWidget(QPushButton('按钮六'))
# addLayout
vlayout = QVBoxLayout()
for i in range(3):
vlayout.addWidget(QPushButton('垂直布局按钮%s' % (i + 1)))
# 设置边距
vlayout.setContentsMargins(10, 20, 40, 60)
vlayout.setSpacing(10)
layout.addLayout(vlayout)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = BoxLayoutDemo()
form.show()
sys.exit(app.exec())