更新时间:2025-09-28 18:11点击:44
四、PyQt5高级组件(QTableView、QListView、容器、多线程等)
4-1、容器
PyQt是一个Python编程语言的GUI工具包,它提供了很多容器用来布置和管理GUI组件。下面是一些常见的PyQt容器:
QMainWindow:主窗口容器,通常包含菜单栏、工具栏、状态栏等。
QWidget:基本的用户界面元素容器,可以作为其他容器的子容器。
QGroupBox:分组框容器,可以将相关的组件放到一个分组框中,使它们更易于组织和查看。
QTabWidget:选项卡容器,可以在多个选项卡中放置不同的组件,让用户轻松地在它们之间切换。
QStackedWidget:堆栈容器,可以在同一位置上堆叠多个组件,只显示其中的一个,让用户可以轻松地在它们之间切换。
QScrollArea:滚动区域容器,当容器中的组件太大,无法在当前视图中完全显示时,可以使用滚动区域容器。
QSplitter:拆分器容器,可以将容器水平或垂直拆分为两个或更多子容器,让用户可以自由地调整它们的大小。
QToolBar:工具栏容器,可以在主窗口或其他容器中放置多个工具栏,让用户可以快速访问常用功能。
注意:布局和容器可以相互转换
以下为创建QGroupBox分组容器:
以下为将分组容器转换为栅格布局:

五、PyQt5布局管理(QBoxLayout、QGridLayout、QFormLayout、嵌套布局)
5-1、水平布局、垂直布局、栅格布局
水平布局(Horizontal layout):
是一种在用户界面中使用的布局方式,其中控件或窗口部件(widget)沿着水平方向排列。这意味着,每个控件或窗口部件都被放置在前一个控件或窗口部件的右侧,从而形成一个水平排列。
水平布局常常用于在用户界面中放置多个控件或窗口部件,使它们在水平方向上对齐并占用相同的空间。水平布局在许多图形用户界面工具包中都得到了支持,例如 PyQt、Qt、JavaFX 等。
水平布局通常与垂直布局(Vertical layout)结合使用,以便在用户界面中实现复杂的布局。例如,您可以使用水平布局将两个按钮水平排列在一起,然后使用垂直布局将这两个按钮与其他控件组合在一起,以便在用户界面中实现更复杂的布局。
如下图所示为将五个按钮放置在垂直布局中去:

如下图所示为垂直布局和水平布局结合的案例:

栅格布局(Grid Layout)
是一种基于网格的布局系统,允许开发者在页面中创建复杂的布局结构。栅格布局使用一个网格来组织页面元素,将页面划分为一系列的行和列。开发者可以通过指定网格中的单元格位置和大小来控制元素的布局。
栅格布局的主要特点是它可以非常灵活地定位和调整元素的位置和大小,而不需要依赖传统的文档流布局。栅格布局可以处理复杂的布局结构,并且可以自适应不同的屏幕尺寸和设备。同时,栅格布局也提供了丰富的布局调整方式,例如自适应、固定宽度、最大宽度、最小宽度等。
在栅格布局中,通过使用grid容器来定义网格布局,通过grid-template-rows、grid-template-columns、grid-template-areas等属性来定义网格的行列布局。开发者可以使用grid-row、grid-column等属性来指定元素所占的网格单元格位置和大小。
总的来说,栅格布局是一种强大的布局工具,可以帮助开发者快速创建复杂的布局结构,并且可以适应不同的屏幕尺寸和设备。
如下图所示为一个栅格布局的案例:

5-2、QFormLayout
FormLayout是一种用于构建图形用户界面(GUI)中表单的布局管理器。它可以在表单中自动地安排各种控件(例如文本框、复选框、下拉框等)的位置和大小,以便它们以最优化的方式显示在表单上。
FormLayout的主要目的是简化表单的设计和排版工作,以及提高表单的可读性和易用性。使用FormLayout,设计人员可以轻松地创建各种不同类型的表单,例如登录表单、注册表单、数据输入表单等,而无需手动调整每个控件的位置和大小。
FormLayout可以根据表单中控件的类型和数量,自动地生成最佳的布局。它可以根据控件之间的相对关系和层次结构,调整每个控件的位置和大小,以确保它们之间的间距和对齐方式是一致的。这样,即使用户调整了表单的大小或缩放了它,控件的位置和大小也会随之自动调整,以适应新的尺寸。
FormLayout还提供了一些常用的功能,例如表单边距、控件间距、对齐方式、自动换行等。这些功能使得表单更加易于管理和修改,同时也提高了表单的可读性和易用性。
总之,FormLayout是一种非常有用的表单布局工具,可以使表单设计和排版变得更加高效和方便。使用FormLayout可以减少手动工作量,提高表单的质量和用户体验。
如下图所示为:右边为QFormLayout,相比于Grid Layout,QFormLayout使用起来更加的灵活。

5-3、QGridLayout
5-3-1、QGridLayout简单介绍
GridLayout(网格布局)是一种PyQt5中的布局管理器,用于将控件以网格的形式排列在窗口中。每个单元格可以包含一个控件,且所有单元格大小相等。
在GridLayout中,控件被按照行和列的方式排列。行和列从0开始编号。控件可以跨越多个行和列,这是通过指定控件的位置以及它在行和列中所占的单元格数量来实现的。
以下是GridLayout的一些重要特点:
创建GridLayout对象:可以通过将QWidget作为参数传递给QGridLayout构造函数来创建一个GridLayout对象。然后可以使用addWidget()方法将控件添加到布局中。
指定控件的位置:可以使用addWidget()方法的第二个和第三个参数来指定控件的位置。例如,addWidget(button, 0, 0)将button添加到第0行和第0列的单元格中。
控件的大小和跨度:可以使用addWidget()方法的第四个和第五个参数来指定控件在行和列中所占的单元格数量。例如,addWidget(label, 0, 0, 1, 2)将label添加到第0行和第0列的单元格中,并让它跨越第0列和第1列的两个单元格。
添加空白单元格:可以使用addSpacing()方法添加空白的单元格,从而调整控件之间的距离。
对齐方式:可以使用setAlignment()方法设置控件在单元格中的对齐方式。可以指定水平和垂直方向的对齐方式,也可以将对齐方式设置为水平和垂直方向的组合。
自动调整大小:可以使用setColumnStretch()和setRowStretch()方法来设置单元格的大小。可以使用addStretch()方法添加一个伸缩项,以便在窗口大小改变时自动调整大小。
5-3-2、QGridLayout案例分析(简单计算器实现)
在这个例子中,我们创建了一个计算器窗口,并使用QGridLayout将所有控件排列成表格形式。我们使用QPushButton创建了所有数字和运算符按钮,并将它们添加到网格布局中。我们还使用QLineEdit创建了结果文本框,并将其放置在布局的顶部。
当用户单击按钮时,我们使用on_button_clicked()方法来更新结果文本框。如果用户单击等号按钮,我们计算表达式并在文本框中显示结果。如果表达式无效,则在文本框中显示“Error”。
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout, QPushButton, QLineEdit
class CalculatorWindow(QMainWindow):
def __init__(self):
super().__init__()
# 设置窗口属性
self.setWindowTitle("Calculator")
self.setFixedSize(300, 300)
# 设置中心窗口
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
# 创建布局
grid_layout = QGridLayout()
central_widget.setLayout(grid_layout)
# 添加文本框
self.result_line_edit = QLineEdit()
self.result_line_edit.setAlignment(Qt.AlignRight)
self.result_line_edit.setReadOnly(True)
grid_layout.addWidget(self.result_line_edit, 0, 0, 1, 4)
# 添加按钮
buttons = [
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
]
positions = [(i, j) for i in range(1, 5) for j in range(4)]
for position, button_label in zip(positions, buttons):
button = QPushButton(button_label)
button.setMaximumWidth(50)
button.clicked.connect(self.on_button_clicked)
grid_layout.addWidget(button, *position)
def on_button_clicked(self):
button = self.sender()
button_label = button.text()
if button_label == "=":
try:
result = str(eval(self.result_line_edit.text()))
except (SyntaxError, ZeroDivisionError):
result = "Error"
self.result_line_edit.setText(result)
else:
self.result_line_edit.setText(self.result_line_edit.text() + button_label)
if __name__ == "__main__":
app = QApplication(sys.argv)
calculator = CalculatorWindow()
calculator.show()
sys.exit(app.exec_())
输出如下:

5-3-3、QGridLayout综合案例分析
复杂案例,感兴趣的可以自己粘贴运行看一下样式。:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QLabel, QVBoxLayout, QLineEdit, QGridLayout
from pyqt5Custom import ToggleSwitch
class ColorToggleButton(QPushButton):
def __init__(self, color, parent=None):
super().__init__(parent)
self.color = color
self.setCheckable(True)
self.setMinimumSize(50, 50)
self.setStyleSheet(f"background-color: {self.color.name()}")
def mousePressEvent(self, event):
super().mousePressEvent(event)
self.setChecked(True)
class ColorPicker(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 创建垂直布局
vBox = QVBoxLayout()
# 将垂直布局设置为主布局
self.setLayout(vBox)
##################################################
# #
# plc_device_parm #
# #
##################################################
self.plc_device_parm = QWidget()
self.plc_device_lyt = QVBoxLayout()
self.plc_device_lyt.setSpacing(5)
self.plc_device_lyt.setAlignment(Qt.AlignTop | Qt.AlignCenter)
self.plc_device_parm.setLayout(self.plc_device_lyt)
# 设置背景色
# self.plc_device_parm.setStyleSheet("background-color: #E6E6FA;")
self.plc_device_lyt.addWidget(QLabel("<span style='font-size:30px;'>设备参数</span>"),
alignment=Qt.AlignHCenter)
self.plc_device_lyt.addWidget(QLabel(
"<span style='font-size:15px; color:#777777;'>Detailed information of device.</span>"),
alignment=Qt.AlignHCenter)
self.plc_device_lyt.addSpacing(100)
# -------------------------------
# 添加表格
# -------------------------------
# 第一行标题
labels = [QLabel('APC投入切除'), QLabel('当前运行状态'), QLabel('当前运行频率'), QLabel('手动频率'),
QLabel('手动频率设置'), QLabel('频率运行上限'), QLabel('频率运行下限'), QLabel('手动启停按钮'),
QLabel('APC运行指令'), QLabel('APC频率指令')]
# 创建GridLayout
self.grid_layout = QGridLayout()
# 设置行间距为10
self.grid_layout.setVerticalSpacing(10)
# 所有的列都设置为固定宽度
for i in range(10):
self.grid_layout.setColumnMinimumWidth(i, 150)
for i in range(11):
if i < 7:
self.grid_layout.addWidget(QLabel(f"{i + 1}#冷却塔风机"), i + 1, 0)
elif i < 9:
self.grid_layout.addWidget(QLabel(f"{i - 6}#冷却泵"), i + 1, 0)
else:
self.grid_layout.addWidget(QLabel(f"{i - 8}#冷冻泵"), i + 1, 0)
# 设置第一行标题
for j in range(10):
self.grid_layout.addWidget(labels[j], 0, j + 1, alignment=Qt.AlignCenter)
# 添加第二列按钮
self.grid_layout.addWidget(ToggleSwitch(text="", style="ios", on=True), i + 1, 1, alignment=Qt.AlignCenter)
# 添加第三列文本框
line_edit = QLineEdit("运行")
line_edit.setEnabled(False)
line_edit.setStyleSheet("background-color: #00FF00; color: black")
line_edit.setFixedWidth(60)
line_edit.setFixedHeight(30)
self.grid_layout.addWidget(line_edit, i + 1, 2, alignment=Qt.AlignCenter)
# 添加第四列文本框
line_edit = QLineEdit("45.0")
line_edit.setEnabled(False)
line_edit.setStyleSheet("background-color: white; color: black")
line_edit.setFixedWidth(60)
line_edit.setFixedHeight(30)
self.grid_layout.addWidget(line_edit, i + 1, 3, alignment=Qt.AlignCenter)
# 添加第五列文本框
line_edit = QLineEdit("45.0")
line_edit.setEnabled(False)
line_edit.setStyleSheet("background-color: #C0C0C0; color: black")
line_edit.setFixedWidth(60)
line_edit.setFixedHeight(30)
self.grid_layout.addWidget(line_edit, i + 1, 4, alignment=Qt.AlignCenter)
# 第六列添加一组按钮
# 因为QButtonGroup并不是QWidget的子类,所以不能直接添加到QGridLayout中。如果需要将QButtonGroup添加到布局中,
# 需要使用一个QWidget包装一下QButtonGroup,然后将QWidget添加到布局中。
button_widget = QWidget()
button_layout = QHBoxLayout(button_widget)
button_1 = QPushButton("➕")
button_1.setFixedSize(60, 30)
button_layout.addWidget(button_1)
button_2 = QPushButton("➖")
button_2.setFixedSize(60, 30)
button_layout.addWidget(button_2)
self.grid_layout.addWidget(button_widget, i + 1, 5, alignment=Qt.AlignCenter)
# 第七列
line_edit = QLineEdit("50.0")
line_edit.setEnabled(False)
line_edit.setStyleSheet("background-color: #C0C0C0; color: black")
line_edit.setFixedWidth(60)
line_edit.setFixedHeight(30)
self.grid_layout.addWidget(line_edit, i + 1, 6, alignment=Qt.AlignCenter)
# 第八列
line_edit = QLineEdit("25.0")
line_edit.setEnabled(False)
line_edit.setStyleSheet("background-color: #C0C0C0; color: black")
line_edit.setFixedWidth(60)
line_edit.setFixedHeight(30)
self.grid_layout.addWidget(line_edit, i + 1, 7, alignment=Qt.AlignCenter)
# 第9列
button_widget = QWidget()
button_layout = QHBoxLayout(button_widget)
button_1 = QPushButton("启动")
button_1.setFixedSize(60, 30)
button_1.setStyleSheet("background-color: lightgreen;")
button_layout.addWidget(button_1)
button_2 = QPushButton("停机")
button_2.setFixedSize(60, 30)
button_2.setStyleSheet("background-color: lightgray;")
button_layout.addWidget(button_2)
self.grid_layout.addWidget(button_widget, i + 1, 8, alignment=Qt.AlignCenter)
# 第十列
line_edit = QLineEdit("0.000")
line_edit.setEnabled(False)
line_edit.setStyleSheet("background-color: white; color: black")
line_edit.setFixedWidth(60)
line_edit.setFixedHeight(30)
self.grid_layout.addWidget(line_edit, i + 1, 9, alignment=Qt.AlignCenter)
# 第十一列
line_edit = QLineEdit("0.000")
line_edit.setEnabled(False)
line_edit.setStyleSheet("background-color: white; color: black")
line_edit.setFixedWidth(60)
line_edit.setFixedHeight(30)
self.grid_layout.addWidget(line_edit, i + 1, 10, alignment=Qt.AlignCenter)
# 将GridLayout添加到主布局中去
vBox.addLayout(self.grid_layout)
# -------------------------------
# 添加调控背景色的按钮
# -------------------------------
self.plc_device_lyt.addSpacing(50)
self.color_Layout = QHBoxLayout()
self.color_widget = QWidget()
self.color_widget.setFixedSize(300, 100)
self.color_widget.setLayout(self.color_Layout)
colors = [
QColor("#F5F5DC"),
QColor("#E6E6FA"),
QColor("#E4F2F2"),
QColor("#F2E4E4"),
QColor("#F2EEE4"),
QColor("#E4F2E4"),
QColor("#E4E4F2"),
QColor("#F2F2E4")
]
for color in colors:
button = ColorToggleButton(color)
button.setFixedSize(30, 30)
button.clicked.connect(self.update_color)
self.color_Layout.addWidget(button)
# 将颜色块添加到布局中去
self.plc_device_lyt.addWidget(self.color_widget, alignment=Qt.AlignHCenter)
def update_color(self):
# 设置背景色
self.plc_device_parm.setStyleSheet(f"background-color: {self.sender().color.name()};")
if __name__ == '__main__':
app = QApplication(sys.argv)
picker = ColorPicker()
picker.show()
sys.exit(app.exec_())