17. 布局控件

一、布局管理

  布局(layout)的一个作用是确定界面上各种控件之间的相对位置,使控件排列起来横平竖直;另一个作用是在窗口的尺寸发生变化时,窗口上的控件的尺寸也随同窗口发生变化,以使窗口不会出现大面积的空白区域或者控件不被窗口或其他控件挡住。

  之前,我们使用控件时基本上都是采用绝对布局的方式,即为每个小部件都指定它的位置和大小(以像素为单位)。当使用绝对定位时,如果调整窗口大小,小部件的大小和位置不会改变。如果决定更改布局,必须完全重新设计布局,这是繁琐且耗时的工作。

  PySide6 中提供了布局控件,以便更优雅地管理容器内的小部件定位。 布局管理器相对于绝对定位的优势是 窗口内的小部件会自动调整大小

  在手动创建布局时,一般都用 setLayout(QLayout) 方法设置窗口或容器控件内部的布局,也可以在创建布局时指定布局的父控件。常用的布局控件如下:

  • 水平布局(QHBoxLayout),可以把多个控件以 水平 的顺序依次排开;
  • 垂直布局(QVBoxLayout),可以把多个控件以 垂直 的顺序依次排开;
  • 栅格布局(QGridLayout),可以以网格的形式把多个控件以 矩阵 形式排列;
  • 表单布局(QFormLayout),可以以 两列 的形式排列控件。

  我们可以在终端中使用 pip 安装 pyside6 模块。

pip install pyside6

布局控件

  布局有关的类都直接或间接继承 QLayout 类,它的常用方法如下:

addWidget(w:QWidget) -> None                                                # 添加控件
removeWidget(w:QWidget) -> None                                             # 移除控件

setAlignment(w:QWidget, alignment:Qt.Alignment) -> None                     # 设置控件对齐方式
setAlignment(l:QLayout, alignment:Qt.Alignment) -> None                     # 设置布局对齐方式

setContentsMargins(margins:QMargins) -> None                                # 设置控件边距
setContentsMargins(left:int, top:int, right:int, bottom:int) -> None        # 设置控件边距

setSizeConstraint(arg__1:QFormLayout.SizeConstraint) -> None                # 设置控件随窗口大小变化时尺寸的变化方式

  用 setSizeConstraint(QLayout.SizeConstraint) 方法可以设置控件随窗口大小改变时尺寸的变化方式。枚举类型参数 QLayout.可以取值如下:

QLayout.SizeConstraint.SetDefaultConstraint     # 表示控件的最小尺寸根据setMinimunSize(QSize)方法或setMinimunSize(int,int)方法设定的值确定
QLayout.SizeConstraint.SetNoConstraint          # 表示控件尺寸的变化量不受限制
QLayout.SizeConstraint.SetMinimumSize           # 表示将控件的尺寸设置成由控件的setMinimumSize()方法设定的尺寸值
QLayout.SizeConstraint.SetFixedSize             # 表示将控件的尺寸设置成由控件的sizeHint()方法获取的尺寸值
QLayout.SizeConstraint.SetMaximumSize           # 表示将控件的尺寸设置成由控件的setMaximumSize()方法设定的尺寸值
QLayout.SizeConstraint.SetMinAndMaxSize         # 表示控件的尺寸可以在最小值和最大值之间变化。

二、线性布局

  线性布局是将放入其中的组件按照水平或者垂直的方式来布局,也就是控制放入其中的组件横向排列或纵向排列。其中,横向排列的称为 水平布局管理器,用 QHBoxLayout 控件表示。纵向排列的称为 垂直布局管理器,用 QVBoxLayout 控件表示。在水平局部管理器中,每一列只能放一个组件;在垂直布局管理器中,每一行只能放一个组件。

  QHBoxLayout 和 QVBoxLayout 都继承于 QBoxLayout,QBoxLayout 的常用方法如下:

addWidget(widget:QWidget, stretch:int=0, alignment:Qt.Alignment=Qt.Alignment()) -> None                     # 添加控件,可设置伸缩系数和对齐方式
addLayout(layout:QLayout, stretch:int=0) -> None                                                            # 添加子布局,可设置伸缩系数
addSpacing(size:int) -> None                                                                                # 添加固定长度的占位空间
addStretch(stretch:int=0) -> None                                                                           # 添加可伸缩的空间
addStrut(arg__1:int) -> None                                                                                # 指定垂向最小值

insertWidget(index:int, widget:QWidget, stretch:int=0, alignment:Qt.Alignment=Qt.Alignment()) -> None       # 根据索引插入控件,可设置伸缩系数和对齐方式
insertLayout(index:int, layout:QLayout, stretch:int=0) -> None                                              # 根据索引插入子布局,可设置伸缩系数
insertSpacing(index:int, size:int) -> None                                                                  # 根据索引插入固定长度的占位空间
insertStretch(index:int, stretch:int=0) -> None                                                             # 根据索引插入可伸缩的空间

setStretch(index:int, stretch:int) -> None                                                                  # 设置索引设置控件或布局的伸缩系数
stretch(index:int): int                                                                                     # 获取第index个控件的伸缩比例系数

setDirection(arg__1:QBoxLayout.Direction) -> None                                                           # 设置布局方向
setStretchFactor(w:QWidget, stretch:int) -> bool                                                            # 给控件设置伸缩系数,成功则返回True
setStretchFactor(l:QLayout, stretch:int) -> bool                                                            # 给布局设置伸缩系数,成功则返回True

  用 addWidget(QWidget,stretch:int=0,Qt.Alignment) 方法和 addLayout(QLayout,stretch:int=0) 方法可在末尾添加控件和子布局,其中参数 stretch 是布局内部各控件和子布局的相对伸缩系数,相对伸缩系数取整数,同时可以指定控件的对齐方式 Qt.Alignment;Qt.Alignment 取值如下:

Qt.AlignmentFlag.AlignLeft        # 左对齐
Qt.AlignmentFlag.AlignRigh        # 右对齐
Qt.AlignmentFlag.AlignJustify     # 水平两端对齐
Qt.AlignmentFlag.AlignHCenter     # 水平居中对齐

Qt.AlignmentFlag.AlignCenter      # 居中对齐

Qt.AlignmentFlag.AlignTop         # 垂直靠上对齐
Qt.AlignmentFlag.AlignBottom      # 垂直靠下对齐
Qt.AlignmentFlag.AlignVCenter     # 垂直居中对齐

  用 addStrut(int) 方法可以设置水平布局在竖直方向的最小高度,也可设置竖直布局在水平方向的最小宽度。

  用 setDirection(QBoxLayout.Direction) 方法可以设置布局的方向,例如把水平布局改变成竖直布局,参数 QBoxLayout.Direction 可以取值如下:

QBoxLayout.Direction.LeftToRight        # 从左到右水平布局
QBoxLayout.Direction.RightToLeft        # 从右到左水平布局
QBoxLayout.Direction.TopToBottom        # 从上到下竖直布局
QBoxLayout.Direction.BottomToTop        # 从下到上竖直布局

2.1、水平布局

  QHBoxLayout 控件表示 水平布局,它的特点是方法该布局管理器中的控件,默认 水平排列。在创建布局管理器对象后,我们需要调用 setLayout(layout) 方法将布局管理器添加到窗体中。

  用 QHBoxLayout 类创建实例对象的方法如下:

QHBoxLayout(parent:QWidget=None)

  其中,parent窗口 或者 容器 类控件。

  我们可以使用 addWidget(w) 方法向布局管理器中添加控件。然后,我们可以用 addSpacing(size) 方法用来设置控件的左右间距。然后,我们还可以使用 addStretch(stretch=0) 方法用来增加一个可伸缩的控件。

  在使用 addWidget() 方法向布局管理器中添加控件时,还可以指定控件的伸缩量和对齐方式。

addWidget(qWidget, stretch=0, alignment=Qt.Alignment())

  其中,qWidget 表示要添加的控件,stretch 表示控件的伸缩量,设置该伸缩量之后,控件会随着窗口的变化而变化;alignment 用来指定控件的对齐方式。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QHBoxLayout
from PySide6.QtWidgets import QPushButton

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个水平布局管理器
        layout = QHBoxLayout()

        # 3.创建按钮
        button1 = QPushButton("按钮1")

        # 4.将按钮添加到布局管理器中
        layout.addWidget(button1)

        # 5.设置控件的左右间距
        layout.addSpacing(30)

        button2 = QPushButton("按钮2")
        layout.addWidget(button2)

        # 6.增加一个可伸缩的控件
        layout.addStretch(1)

        button3 = QPushButton("按钮3")
        layout.addWidget(button3)
        layout.addStretch(2)

        button4 = QPushButton("按钮4")
        layout.addWidget(button4)
        layout.addStretch(1)

        # 7.将布局管理器添加到窗体中
        self.setLayout(layout)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

2.2、垂直布局

  QVBoxLayout 控件表示 垂直布局,它的特点是方法该布局管理器中的控件,默认 垂直排列。在创建布局管理器的同时,我们可以指定要设置布局的窗口。

  用 QVBoxLayout 类创建实例对象的方法如下:

QVBoxLayout(parent:QWidget=None)

  其中,parent窗口 或者 容器 类控件。

  我们可以使用 addWidget(w) 方法向布局管理器中添加控件。然后,我们可以用 addSpacing(size) 方法用来设置控件的上下间距。然后,我们还可以使用 addStretch(stretch=0) 方法用来增加一个可伸缩的控件。

  在使用 addWidget() 方法向布局管理器中添加控件时,还可以指定控件的伸缩量和对齐方式。

addWidget(qWidget, stretch=0, alignment=Qt.Alignment())

  其中,qWidget 表示要添加的控件,stretch 表示控件的伸缩量,设置该伸缩量之后,控件会随着窗口的变化而变化;alignment 用来指定控件的对齐方式。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QVBoxLayout
from PySide6.QtWidgets import QPushButton
from PySide6.QtCore import Qt

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个垂直布局管理器
        layout = QVBoxLayout(self)

        # 3.创建按钮
        button1 = QPushButton("按钮1")

        # 4.将按钮添加到布局管理器中
        layout.addWidget(button1, 1, Qt.AlignmentFlag.AlignTop)

        button2 = QPushButton("按钮2")
        layout.addWidget(button2, 2, Qt.AlignmentFlag.AlignTop)

        button3 = QPushButton("按钮3")
        layout.addWidget(button3, 2, Qt.AlignmentFlag.AlignTop)

        button4 = QPushButton("按钮4")
        layout.addWidget(button4, 3, Qt.AlignmentFlag.AlignTop)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

三、表单布局

  表单布局 QFormLayout 由左右两列和多行构成,将控件放到左右两列中,通常左列放置 QLabel 控件,用来显示信息,给用户提示;右列放置 QLineEdit 控件、QSpinBox 等输入控件,需要用户进行输入或者选择。我们也可以让一个控件单独占据一行。

  表单布局 QFormLayout 继承自 QLayout,用 QFormLayout 类创建实例对象的方法如下所示:

QFormLayout(parent:QWidget=None)

  其中parent是窗口或容器类控件。

  QFormLayout 类的常用方法如下:

addRow(label:QWidget, field:QWidget) -> None                            # 末尾添加行,两个控件分别在左右
addRow(label:QWidget, field:QLayout) -> None                            # 末尾添加行,控件在左,布局在右
addRow(labelText:str, field:QWidget) -> None                            # 末尾添加行,左侧创建名为labelText的标签,右侧是控件
addRow(labelText:str, field:QLayout) -> None                            # 末尾添加行,左侧创建名为labelText的标签,右侧是布局
addRow(widget:QWidget) -> None                                          # 末尾添加行,只有一个控件,控件占据左右两侧
addRow(layout:QLayout) -> None                                          # 末尾添加行,只有一个布局,布局占据左右两侧

insertRow(row:int, label:QWidget, field:QWidget) -> None                # 在第row行插入行,两个控件分别在左右
insertRow(row:int, label:QWidget, field:QLayout) -> None                # 在第row行插入行,控件在左,布局在右
insertRow(row:int, labelText:str, field:QWidget) -> None                # 在第row行插入行,左侧创建名为labelText的标签,右侧是控件
insertRow(row:int, labelText:str, field:QLayout) -> None                # 在第row行插入行,左侧创建名为labelText的标签,右侧是布局
insertRow(row:int, widget:QWidget) -> None                              # 在第row行插入行,只有一个控件,控件占据左右两侧
insertRow(row:int, layout:QLayout) -> None                              # 在第row行插入行,只有一个布局,布局占据左右两侧

removeRow(row:int) -> None                                              # 删除第row行及其控件
removeRow(widget:QWidget) -> None                                       # 删除控件
removeRow(layout:QLayout) -> None                                       # 删除布局

setHorizontalSpacing(spacing:int) -> None                               # 设置水平间距
setVerticalSpacing(spacing:int) -> None                                 # 设置垂直间距

setRowWrapPolicy(policy:QFormLayout.RowWrapPolicy) -> None              # 设置行换行策略

rowCount() -> int                                                       # 获取行数

setLabelAlignment(alignment:Qt.Alignment) -> None                       # 设置左列对齐方式
setFormAlignment(alignment:Qt.Alignment) -> None                        # 设置控件在表单布局中的对齐方式

setFieldGrowthPolicy(policy:QFormLayout.FieldGrowthPolicy) -> None      # 设置可伸缩空i教案的伸缩方式

  表单布局最常用的方式是 addRow(labelText, field),该方法用来向表单布局中添加一行,在一行中可以添加两个控件,分别位于一行中的两列上。

  另外,表单布局还提供了一个 setRowWrapPolicy(policy) 方法,用来设置表单布局中每一列的摆放方式。参数为 QFormLayout.RowWrapPolicy 枚举类型,取值如下:

QFormLayout.RowWrapPolicy.DontWrapRows   # 字段总是放在标签旁边,这是默认设置
QFormLayout.RowWrapPolicy.WrapAllRows    # 字段总是布局在标签下面
QFormLayout.RowWrapPolicy.WrapLongRows   # 如果空间足够字段放在标签的旁边,否则字段放在标签的下面
import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QFormLayout
from PySide6.QtWidgets import QLabel, QLineEdit, QPushButton

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个表单布局管理器
        layout = QFormLayout(self)

        # 3.设置表单布局中每一列的摆放方式
        layout.setRowWrapPolicy(QFormLayout.RowWrapPolicy.WrapLongRows)

        # 4.创建标签
        label_username = QLabel("用户名")
        text_username = QLineEdit()

        # 5.创建文本框
        text_username.setPlaceholderText("请输入用户名")

        # 6.将标签和文本框添加到表单布局中
        layout.addRow(label_username, text_username)

        label_password = QLabel("密码")
        text_password = QLineEdit()
        text_password.setPlaceholderText("请输入密码")
        text_password.setEchoMode(QLineEdit.EchoMode.PasswordEchoOnEdit)
        layout.addRow(label_password, text_password)

        button_login = QPushButton("登录")
        layout.addRow(button_login)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

四、栅格布局

  栅格布局 QGridLayout(或称为网格布局)提供多行多列的布局位置,可以把控件或子布局放到这些布局节点上,也可以让一个控件或子布局占用多行多列的布局位置。QGridLayout 控件需要将提供给它的控件划分为行和列,并把每个控件插入到正确的单元格中。

  QGridLayout 类的常用方法如下:

# 在指定的行列位置添加控件
addWidget(widget:QWidget, row:int, column:int, alignment:Qt.Alignment=Qt.Alignment()) -> None
# 在指定的行列位置添加控件,控件可以设置成跨多行多列
addWidget(widget:QWidget, row:int, column:int, rowSpan:int, columnSpan:int, alignment:Qt.Alignment=Qt.Alignment()) -> None
# 添加子布局
addLayout(layout:QLayout, row:int, column:int, alignment:Qt.Alignment=Qt.Alignment()) -> None
# 添加子布局
addLayout(layout:QLayout, row:int, column:int, rowSpan:int, columnSpan:int, alignment:Qt.Alignment=Qt.Alignment()) -> None

rowCount() -> int                                           # 获取行数
columnCount() -> int                                        # 获取列数
cellRect(row:int, column:int) -> QRect                      # 获取单元格的矩形区域

setRowStretch(row:int, stretch:int) -> None                 # 设置行的伸缩系数
setColumnStretch(column:int, stretch:int) -> None           # 设置列的伸缩系数
setHorizontalSpacing(spacing:int) -> None                   # 设置水平间距
setVerticalSpacing(spacing:int) -> None                     # 设置垂直间距
setRowMinimumHeight(row:int, minSize:int) -> None           # 设置行的最小高度
setColumnMinimumWidth(column:int, minSize:int) -> None      # 设置列的最小宽度
import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QGridLayout
from PySide6.QtWidgets import QPushButton

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个栅格布局管理器
        layout = QGridLayout(self)

        # 3.创建按钮
        button_1 = QPushButton("按钮1")

        # 4.将按钮添加到布局管理器中
        layout.addWidget(button_1, 0, 0)

        button_2 = QPushButton("按钮2")
        layout.addWidget(button_2, 0, 1)

        button_3 = QPushButton("按钮3")
        layout.addWidget(button_3, 1, 0)

        button_4 = QPushButton("按钮4")
        layout.addWidget(button_4, 1, 1)

        button_5 = QPushButton("按钮5")
        layout.addWidget(button_5, 2, 0, 1, 2)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

五、布局管理器的嵌套

  在进行用户界面设计时,很多时候只通过一种布局很难实现实现的效果,这是就需要将多种布局管理器进行混合使用,即布局管理器的嵌套。

  多种布局管理器之间可以互相嵌套,在实现布局管理器时,只需要记住以下两点原则:

  • 在一个布局文件中,最多只能有一个顶层布局管理器。如果想要使用多个布局管理器,就需要使用一个根布局管理器将它们包括起来。
  • 不能嵌套太深。如果嵌套太深,则会影响性能,主要会降低页面的加载速度。
import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QHBoxLayout, QGridLayout
from PySide6.QtWidgets import QPushButton, QTextEdit

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个水平布局管理器
        layout = QHBoxLayout(self)

        # 3.创建一个栅格布局
        sub_layout = QGridLayout()

        # 4.创建按钮,并添加到栅格布局中
        button1 = QPushButton("按钮1")
        sub_layout.addWidget(button1, 0, 0)

        button2 = QPushButton("按钮2")
        sub_layout.addWidget(button2, 0, 1)

        button3 = QPushButton("按钮3")
        sub_layout.addWidget(button3, 1, 0, 1, 2)

        # 5.将网格布局添加到水平布局中
        layout.addLayout(sub_layout)

        # 6.创建文本框控件,并添加到水平布局中
        text = QTextEdit()
        layout.addWidget(text)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())
posted @   星光映梦  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
历史上的今天:
2024-01-05 39. DAC输出正弦波
点击右上角即可分享
微信分享提示