本文学习《PySide6/PyQt6 快速开发与实践》书中一个关于综合布局的案例代码,进行逐行的理解并注释,特记录。
# -*- coding: utf-8 -*-
"""
介绍布局管理的综合案例
"""
import sys
from PySide6.QtWidgets import *
'''
说明:这个案例继承了QDialog类,这个类也属于窗口类,没有最小化和最大化按钮,只有关闭按钮项
'''
class LayoutDemo(QDialog):
def __init__(self, parent=None):
super(LayoutDemo, self).__init__(parent)
self.NumGridRows = 3
self.NumButtons = 4
# 执行创建菜单、水平布局,网格布局,表单布局的自定义函数,创建相关小部件及进行布局
self.createMenu()
self.createHorizontalGroupBox()
self.createGridGroupBox()
self.createFormGroupBox()
# 创建一个文本框的实例对象,并设置一条纯文本的信息,这个控件(小部件)将占用顶层布局中剩余的控件。
bigEditor = QTextEdit()
bigEditor.setPlainText("这个小部件占用了顶层布局中的所有剩余空间。")
'''
下面3行代码代码用于在创建Qt对话框(QDialog)时,添加一组标准的按钮(如“OK”和“Cancel”)并处理它们的点击事件。
第1行:
创建了一个QDialogButtonBox对象,它是一组按钮的容器。
QDialogButtonBox.Ok | QDialogButtonBox.Cancel是一个位掩码,用于指定在按钮框中显示哪些按钮。
这里,|运算符用于组合Ok和Cancel两个标志,意味着按钮框将包含“OK”和“Cancel”两个按钮。
第2行:
这行代码连接了accepted信号到self.accept槽。当用户点击“OK”按钮时,accepted信号会被发射。
通过连接到self.accept,对话框将执行其“接受”操作(通常是关闭对话框并返回QDialog.Accepted)。
第3行:
这行代码连接了rejected信号到self.reject槽。当用户点击“Cancel”按钮时,rejected信号会被发射。
通过连接到self.reject,对话框将执行其“拒绝”操作(通常是关闭对话框并返回QDialog.Rejected)。
这里的“关闭窗口”实际上是QDialog的默认行为,当调用reject方法时,对话框会被关闭。
这种设计是基于用户的期望:当用户点击“Cancel”按钮时,他们通常期望对话框被关闭,并且任何未保存的更改都不会被应用。
总结起来,点击“Cancel”按钮会发射rejected信号,这个信号连接到self.reject,从而导致对话框关闭。
'''
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
# 通过实例化QVBoxLaylout类(垂直布局类),创建一个顶层布局对象
mainLayout = QVBoxLayout()
# 1、在顶层布局对象中添加菜单控件对象
mainLayout.setMenuBar(self.menuBar)
# 2、在顶层布局对象中添加一个QGroupBox对象,这个对象管理一个水平布局对象
mainLayout.addWidget(self.horizontalGroupBox)
# 3、在顶层布局对象中添加一个QGroupBox对象,这个对象管理一个网格布局对象
mainLayout.addWidget(self.gridGroupBox)
# 4、在顶层布局对象中添加一个QGroupBox对象,这个对象管理一个表单布局对象
mainLayout.addWidget(self.formGroupBox)
# 5、在顶层布局对象中添加上面创建的文本框对象
mainLayout.addWidget(bigEditor)
# 6、在顶层布局对象中添加上面使用QDialogButtonBox类创建的一个包含OK与Cancel两个按钮的容器
mainLayout.addWidget(buttonBox)
# 把顶层布局对象,添加到窗口中
self.setLayout(mainLayout)
# 设置窗口的的标题
self.setWindowTitle("一个创建QDialog类窗口的综合布局案例")
# 创建菜单的函数
def createMenu(self):
# 通过QMenuBar类,给窗口创建一个菜单对象
self.menuBar = QMenuBar()
# 通过QMenu创建一个菜单项,命名为“文件”
fileMenu = QMenu("文件", self)
# 给菜单项对象添加一个动作
exitAction = fileMenu.addAction("退出")
# 把菜单项添加到菜单中
self.menuBar.addMenu(fileMenu)
# 设置菜单动作exitAction对象的鼠标单击,触发连接窗口的关闭窗口的接受内置信号,实现关闭窗口
exitAction.triggered.connect(self.accept)
# 创建一个QGroupBox容器对象,在其中添加一个水平布局对象,水平布局对象中,使用for循环添加几个按钮
def createHorizontalGroupBox(self):
self.horizontalGroupBox = QGroupBox("包含一个水平布局对象")
layout = QHBoxLayout()
for i in range(0, self.NumButtons):
button = QPushButton("按钮 %d" % (i + 1))
layout.addWidget(button)
self.horizontalGroupBox.setLayout(layout)
# 创建一个QGroupBox容器对象,在其中添加一个网格布局对象,网格布局对象中,使用for循环添加几个按钮
def createGridGroupBox(self):
self.gridGroupBox = QGroupBox("一个网格布局")
layout = QGridLayout()
# 上面定义了全局变量self.NumGridRows=3 ,使用for循环创建6个对象,添加到网格对象中
for i in range(0, self.NumGridRows):
label = QLabel("行 %d:" % (i + 1))
lineEdit = QLineEdit()
layout.addWidget(label, i + 1, 0) # 第一个便签对象在网格的(1,0)处添加
layout.addWidget(lineEdit, i + 1, 1) # 第一个Line文本框对象在网格的(1,1)处添加
# 创建一个多行文本框对象
smallEditor = QTextEdit()
smallEditor.setPlainText("这个控件占据了网格布局的大约三分之二空间。")
# 在网格布局对象的第0行第2列(实际是第3列,因为索引从0开始),占据4行1列的空间
layout.addWidget(smallEditor, 0, 2, 4, 1)
# 设置索引为第1、2列(当行文本及多行文本)拉伸因子,随着窗口拉伸,便签大小不会变化,文本框会变化
layout.setColumnStretch(1, 10)
layout.setColumnStretch(2, 20)
self.gridGroupBox.setLayout(layout)
# 创建一个QGroupBox容器对象,在其中添加一个表单布局对象,非常简单添加3行2列(每行1个标签小部件,一个输入类小部件)
def createFormGroupBox(self):
self.formGroupBox = QGroupBox("一个表单布局")
layout = QFormLayout()
layout.addRow(QLabel("行 1, 长文本:"), QLineEdit())
layout.addRow(QLabel("行 2:"), QComboBox())
layout.addRow(QLabel("行 3:"), QSpinBox())
self.formGroupBox.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
demo = LayoutDemo()
demo.show()
sys.exit(app.exec())