18. 布局管理

发布时间 2023-12-30 19:39:50作者: 星光樱梦

一、布局管理

  布局管理是指我们在应用程序窗口上放置小部件的方式。我们可以使用绝对定位或布局类来放置小部件。使用布局管理器来管理布局是组织小部件的首选方式。

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

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

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

pip install pyside6

布局类控件

二、线性布局

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

2.1、水平布局

  QHBoxLayout 控件表示水平布局,它的特点是方法该布局管理器中的控件,默认水平排列。

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

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

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

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

  常用的控件对齐方式:

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

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

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()

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

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

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

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

        button2 = QPushButton("按钮2")
        layout.addWidget(button2)
  
        # 5.增加一个可伸缩的控件
        layout.addStretch(1)

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

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

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

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)

    # 2.创建一个窗口
    window = MyWidget()

    # 3.设置窗口对象大小
    window.resize(700, 500)

    # 4.展示窗口
    window.show()

    # 5.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

2.2、垂直布局

  QVBoxLayout 控件表示垂直布局,它的特点是方法该布局管理器中的控件,默认垂直排列。

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

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

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

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

  常用的控件对齐方式:

Qt.AlignmentFlag.AlignTop         # 垂直靠上对齐
Qt.AlignmentFlag.AlignBottom      # 垂直靠下对齐
Qt.AlignmentFlag.AlignVCenter     # 垂直居中对齐
Qt.AlignmentFlag.AlignCenter      # 居中对齐   
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):
        super().__init__()

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

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

        # 3.将按钮添加到布局管理器中
        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, 1, Qt.AlignmentFlag.AlignTop)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)

    # 2.创建一个窗口
    window = MyWidget()

    # 3.设置窗口对象大小
    window.resize(100, 500)

    # 4.展示窗口
    window.show()

    # 5.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

三、网格布局

  QGridLayout 被称为网格布局(即多行多列),它将位于其中的控件放入一个网格中。QGridLayout 控件需要将提供给它的控件划分为行和列,并把每个控件插入到正确的单元格中。

方法 说明
addWidget(widget, row, column, rowSpan, columnSpan, alignment=Qt.Alignment()) 添加控件,主要参数说明如下:
- widget:要添加的控件
- row:添加控件的起始行数
- column:添加控件的起始列数
- rowSpan:控件跨越的行数
- columnSpan:控件跨越的列数
- alignment:控件的对齐方式
setRowStretch(row, stretch) 设置行比例
setColumnStretch(column, stretch) 设置列比例
setHorizontalSpacing(spacing) 设置控件在水平方向上的间距
setVerticalSpacing(spacing) 设置控件在垂直方向上的间距
import sys

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

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()

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

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

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

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

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

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

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

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)

    # 2.创建一个窗口
    window = MyWidget()

    # 3.设置窗口对象大小
    window.resize(700, 500)

    # 4.展示窗口
    window.show()

    # 5.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

四、表单布局

  QFrameLayout 控件表示表单布局,该控件以表单方式进行布局,表单是一种网页中常见的与用户交互的方式,其主要由两列组成,第一列用来显示信息,给用户提示;而第二列需要用户进行输入或者选择。

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

  另外,表单布局还提供了一个 setRowWrapPolicy(policy) 方法,用来设置表单布局中每一列的拜摆放方式。

setRowWrapPolicy(policy)

  参数 policy 取值及其说明如下:

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):
        super().__init__()

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

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

        # 3.创建标签
        username_label = QLabel("用户名")
        username_text = QLineEdit()
  
        # 4.创建文本框
        username_text.setPlaceholderText("请输入用户名")

        # 5.将标签额文本框添加到表单布局中
        layout.addRow(username_label, username_text)

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

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

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)

    # 2.创建一个窗口
    window = MyWidget()

    # 3.设置窗口对象大小
    window.resize(700, 500)

    # 4.展示窗口
    window.show()

    # 5.进入程序的主循环并通过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):
        super().__init__()

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

        # 2.创建一个网格布局
        sub_layout = QGridLayout()

        # 3.创建按钮,并添加到网格布局中
        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)

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

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


if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)

    # 2.创建一个窗口
    window = MyWidget()

    # 3.设置窗口对象大小
    window.resize(700, 500)

    # 4.展示窗口
    window.show()

    # 5.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())