Pyqt5之布局管理
上一篇讲述了一些窗口部件,当时往界面上拖放部件时都是随意放置的,这对于学习部件的使用没有太大的影响,但是,对于一个完善的软件,布局管理却是必不可少的。 无论是想要界面中部件有一个很整齐的排列,还是想要界面能适应窗口的大小变化,都 要进行布局管理。Qt中主要提供了 QLayout 类及其子类来作为布局管理器,它们可以实现常用的布局管理功能,QLayout及其子类的关系如下图所示。
一、布局管理系统
Qt的布局管理系统提供了简单而强大的机制来自动排列一个窗口中的部件,确保它们有效地使用空间。Qt包含了一组布局管理类来描述怎样在应用程序的用户界面中对部件进行布局,比如QLayout的几个子类,这里将它们称作布局管理器。所有 QWidget 类的子类的实例(对象)都可以使用布局管理器来管理位于其中的子部件, QWidget::setLayOut()函数可以在一个部件上应用布局管理器。一旦一个部件上设置了布局管理器,那么它会完成以下几种任务:
定位子部件;
- 感知窗口默认大小;
- 感知窗口最小大小;
- 改变大小处理;
- 当内容改变时自动更新:
- 字体大小,文本或子部件的其他内容随之改变;
- 隐藏或显示子部件;
- 移除一个子部件。
1.1 布局管理器
QLayout类是布局管理器的基类,是一个抽象基类,继承自 QObject 和 QLayoutItem 类,而 QLayoutltem 类提供了 一个供 QLayout 操作的抽象项目。QLayout 和 QLayoutItem 都是在设计自己的布局管理器时才使用的,一般只需要使用 QLayout 的几个子类就可以了,分别是 QBoxLayout(基本布局管理器)、QGridLayout(栅格布局管理器)、QFormLayout(表单布局管理器)和QStackedLayout(栈布局管理器)。
1. 基本布局管理器(QBoxLayout)
基本布局管理器 QBoxLayout 类可以使子部件在水平方向或者垂直方向排成一列,将所有的空间分成一行盒子,然后将每个部件放入一个盒子中。它有两个子类 QHBoxLayont 水平布局管理器和 QVBoxLayout 垂直布局管理器。单击主界面,查看它的属性栏,最后面的部分是其使用的布局管理器的属性,如下图所示。
2. 栅格布局管理器(QGridLayout)
栅格布局管理器QGridLaycnit类使得部件在网格中布局,它将所有的空间分隔成一些行和列,行和列的交叉处就形成了单元格,然后将部件放人一个确定的单元格中.
3. 表单布局管理器(QFormLayout)
表单布局管理器 QFormLayout 类用来管理表格的输入部件及其相关的标签,将它的子部件分为两列,左边是一些标签,右边是一些输入部件,比如行编辑器或者数字选择框等。其实如果只是起到这样的布局作用,那么用QGridLayout就完全可以做到 了,之所以添加QFormLayout类,是因为它有独特的功能。下面看一个例子。
先将前面在MyWidget类的构造函数中自己添加的代码全部注释掉,然后进入设计模式,这里使用另外一种方法来使用布局管理器。从部件栏中找到 Form Layout,将其拖入到界面上,然后双击或者在它上面右击,选择“添加窗体布局行菜单。然后在弹出的“添加表单布局行”对话框中输人标签文字“姓名(&N):”,则下面自动填写了“标签名称”、“字段类型”和“字段名称”等,并且设置了伙伴关系。这里使用了 QLineEdit 行编辑器,当然也可以选择其他部件。而填写的标签文字中(&N)要注意括号必须是英语半角的,表明它的加速键是Alt + N,设置伙伴关系表示当按下Alt + N时,光标会自动跳转到标签后面对应的行编辑器中。按下确定键便会在布局管理器中添加一个标签和一个行编辑器。按照这种方法,再添加3行:性别(&S),使用 QComoBox;年龄 (&A),使用QSpinBox;邮箱(&M),使用 QLineEdit。可以按下加速键 Alt + N,光标就可以定位到“姓名”标签后的行编辑器中。
上面的添加表单行是在设计器中完成的,也可以在代码中使用 addRow() 函数来完成。表单布局管理器为设计填写表单的窗口提供了方便的功能,其实还有一些实用的特性。表单管理器也可以像普通管理器一样使用,但是,如果不是为了设计这样的表单,一般会使用栅格布局管理器。
1.2 可扩展窗口
一个窗口可能有很多选项是扩充的,只有在必要的时候才显示出来,这时就可以使用一个按钮,用来隐藏或者显示多余的内容,就是所谓的可扩展窗口。要实现可扩展窗 口,就要得力于布局管理器的特性,那就是当子部件隐藏时,布局管理器自动缩小,当子部件重新显示时,布局管理器再次放大。下面看一个具体的例子。
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class AppGui(QWidget):
def __init__(self):
super(AppGui, self).__init__()
self.initUI()
def initUI(self):
# self无父窗口,不是窗口部件,而是个窗口
self.setWindowTitle("我是widget")
# label1 无父窗口,是个窗口
vLayout = QVBoxLayout()
formLayout = QFormLayout()
vLayout.addLayout(formLayout)
label1 = QLabel("我是个窗口1")
label2 = QLabel("我是个窗口2")
label3 = QLabel("我是个窗口3")
label4 = QLabel("我是个窗口4")
label1.setText("姓名(&N)")
label2.setText("性别(&S)")
label3.setText("年龄(&A)")
label4.setText("email(&M)")
nameLineEdit = QLineEdit()
sexComoBox = QComboBox()
ageSpinBox = QSpinBox()
emailLineEdit = QLineEdit()
formLayout.addRow(label1, nameLineEdit)
formLayout.addRow(label2, sexComoBox)
formLayout.addRow(label3, ageSpinBox)
formLayout.addRow(label4, emailLineEdit)
hLayout = QHBoxLayout()
fontComboBox = QFontComboBox()
checkbox = QCheckBox()
checkbox.setText("隐藏可扩展窗口")
hLayout.addWidget(fontComboBox)
hLayout.addWidget(checkbox)
spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
vLayout.addItem(spacerItem)
vLayout.addLayout(hLayout)
self.textEdit = QTextEdit()
vLayout.addWidget(self.textEdit)
self.setLayout(vLayout)
checkbox.toggled['bool'].connect(self.set_textEditVisible)
def set_textEditVisible(self, checked):
self.textEdit.setHidden(checked)
if __name__ == '__main__':
# 创建应用程序
app = QApplication(sys.argv)
# 在应用程序里创建窗口
ui = AppGui()
# 显示窗口
ui.show()
# 进入程序的主循环、并通过exit函数确保主循环安全结束
sys.exit(app.exec_())
1.3 分裂器
分裂器 QSplitter 类提供了一个分裂器部件,和 QBoxLayout 很相似,可以完成布局管理器的功能,但是包含在它里面的部件,默认是可以随着分裂器的大小变化而进行相应大小变化的。比如一个按钮放在布局管理器中,它的垂直方向默认是不会被拉伸的,但是放到分裂器中就可以被拉伸。还有一个不同就是,布局管理器是继承自 QObject 类的,而分裂器却是继承自 QFrame 类,QFrame 类又是继承自 QWidget 类,也就是说,分裂器拥有 QWidget 类的特性,它是可见的,而且可以像 QFrame —样设置边框。下面看一个例子。
新建Qt Gui应用,项目名称为mySplitter,类名My Widget,基类选择QWidget。 建好项目后打开 mywidget. ui 文 件,然后往上面拖人4个 Push Button, 同时选中这4个按钮然后右击,选择 “布局—使用分裂器水平布局”菜单项, 将这4个按钮放到一个分裂器中。将分裂器拉大点,并在属性栏中设置其 frameShape 为 Box,frameShadow 为 Raised,line Width为5。此时运行程序,效果如下图