目前为止,我们在界面上创建的控件,都是通过 move 函数来调整控件位置的,或者通过 setGeometry 函数来调整控件的位置和大小,这种布局我们叫做绝对定位布局。这种布局的缺陷很多,如果一个界面上控件太多,或者我们想动态调整控件的大小,显然使用上面的方式会增加编程的难度。
PyQt5 提供了相应的布局类可以对界面上的控件进行布局管理,这种布局我们叫做布局类布局,这些布局类有框布局(Boxlayout)和网格布局(QGridLayout),本节课我们就来学习这两种布局类。
Boxlayout 有两种布局类,QHBoxLayout 可以创建水平布局,QVBoxLayout 可以创建垂直布局。下面我们先使用 QHBoxLayout 类对控件进行布局管理。
import sys from PyQt5.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QApplication) class HBoxLayoutExample(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): okButton = QPushButton("OK") # 创建一个 OK 按钮 cancelButton = QPushButton("Cancel") # 创建一个 Cancel 按钮 hbox = QHBoxLayout() # 创建一个水平布局 hbox.addStretch(1) # 给水平布局增加一个间隔元素,值设为 1 hbox.addWidget(okButton) # 给水平布局增加一个 ok 按钮 hbox.addWidget(cancelButton) # 给水平布局增加一个 cancel 按钮 self.setLayout(hbox) # 给界面加入水平布局 self.setGeometry(600, 200, 800, 500) self.setWindowTitle('框布局') self.show() app = QApplication(sys.argv) ex = HBoxLayoutExample() app.exec_()
我们在创建一个水平布局后,由于添加控件默认是从左往右自动排序的(这个可以通过 setLayoutDirection(Qt.RightToLeft)方法更改成从右往左排序),首先用 addStretch(1) 函数给布局添加一个间隔元素之后,然后再调用 addWidget 函数增加两个按钮。
addStretch(1) 中的参数是比例的意思,但是这里我们在水平方向只添加了一个间隔元素,所以不管这里的值是多少,它都会占满这里的剩余空间。比如,我们再添加一个 Strech,参数哪怕设置为 0,我们可以看到运行结果依然是两个 Strech 平分剩余空间(0:0),修改上例代码如下。
hbox.addStretch(0) # 间隔元素值设为 0 hbox.addWidget(okButton) hbox.addStretch(0) # 间隔元素值设为 0 hbox.addWidget(cancelButton)
但是如果前者为 1,后者为 0,那么后者是不起作用的,修改上例代码如下。
hbox.addStretch(1) # 间隔元素值设为 1 hbox.addWidget(okButton) hbox.addStretch(0) # 间隔元素值设为 0 hbox.addWidget(cancelButton)
我想现在大家对 Strech 和水平布局应该有个感性的认识了,那么怎么把这个水平布局放在右下方呢?这里是新建一个垂直方向的子布局,把上面这个水平方向布局添加到垂直布局下面,代码如下。
import sys from PyQt5.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QApplication) class HVBoxLayoutExample(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): okButton = QPushButton("OK") # 创建一个 OK 按钮 cancelButton = QPushButton("Cancel") # 创建一个 Cancel 按钮 hbox = QHBoxLayout() # 新建一个水平布局 hbox.addStretch(1) # 给水平布局增加一个间隔元素,值设为 1 hbox.addWidget(okButton) # 给水平布局增加一个 OK 按钮 hbox.addWidget(cancelButton) # 给水平布局增加一个 cancel 按钮 vbox = QVBoxLayout() # 新建一个垂直布局 vbox.addStretch(1) # 给垂直布局增加一个间隔元素,值设为 1 vbox.addLayout(hbox) # 给垂直布局增加上面的水平布局 self.setLayout(vbox) # 把垂直布局加进界面内 self.setGeometry(600, 200, 800, 500) self.setWindowTitle('框布局2') self.show() app = QApplication(sys.argv) ex = HVBoxLayoutExample() app.exec_()
QGridLayout 是将窗口分割成行和列的网格来进行排列,通常可以使用函数 addWidget 将被管理的控件添加到窗口中,或者使用 addLayout 函数将布局添加到窗口中,也可以通过 addWIdget 函数对所添加的控件设置行数与列数的跨越,最后实现网格占据多个窗格。
我们先使用单一的网格单元格,也就是一个网格里面布局一个控件。
import sys from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QPushButton class GridLayoutExample(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): grid = QGridLayout() # 创建一个网格布局 self.setLayout(grid) # 给界面加入网格布局 # 创建按钮的标签列表 names = ['Cls', 'Back', '', 'Close', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '0', '.', '=', '+'] # 在网格中创建一个位置列表 positions = [(i, j) for i in range(5) for j in range(4)] # 创建按钮并通过 addWIdget 方法添加到布局中 for position, name in zip(positions, names): if name == '': continue button = QPushButton(name) grid.addWidget(button, *position) self.move(300, 150) self.setWindowTitle('网格布局') self.setGeometry(600, 200, 800, 500) self.show() app = QApplication(sys.argv) ex = GridLayoutExample() sys.exit(app.exec_())
上面的例子中,每个控件都占用网格的一个单元格,但控件也可以使用 addWidget 重载方法,将行和列跨越更多数量的单元格。
import sys from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit, QTextEdit, QGridLayout, QApplication) class GridLayoutExample2(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): titleLabel = QLabel('标题') authorLabel = QLabel('作者') contentLabel = QLabel('内容') titleEdit = QLineEdit() authorEdit = QLineEdit() contentEdit = QTextEdit() grid = QGridLayout() grid.setSpacing(10) # 设置组件之间的间距 grid.addWidget(titleLabel, 1, 0) # 布局在第 1 行第 0 列 grid.addWidget(titleEdit, 1, 1) # 布局在第 1 行第 1 列 grid.addWidget(authorLabel, 2, 0) # 布局在第 2 行第 0 列 grid.addWidget(authorEdit, 2, 1) # 布局在第 2 行第 1 列 grid.addWidget(contentLabel, 3, 0) # 布局在第 3 行第 0 列 grid.addWidget(contentEdit, 3, 1, 5, 1) # 布局在第 3 行第 1 列,跨越 5 行 1 列 self.setLayout(grid) self.setGeometry(600, 200, 800, 500) self.setWindowTitle('网格布局2') self.show() app = QApplication(sys.argv) ex = GridLayoutExample2() app.exec_()
上面例子中,我们创建一个窗口,其中有三个标签,两个行编辑和一个文本编辑窗口小控件,然后使用 QGridLayout 完成布局。在添加一个小的控件到网格的时候,我们可以提供小部件的行和列的跨度,在上面例子中,reviewEdit 控件跨度 5 行。
掌握框布局。
掌握网格布局和网格的跨度布局。
编程把我们本节例子中的计算器布局中的每个按钮的宽度增加一倍。
感觉很多新人布局管理器用不好,界面搞得一团糟
这个资料非常不错
只是能调整拉伸比例,一旦在Design界面把控件套上layout,你就不能象未套上layout时调整单个控件大小了,你只能拉伸layout使控件变大小(因为控件无法用鼠标拉伸了),但拉伸layout会影响layout中的其它控件大小,所以有时你需打破布局调整个大慨又重复套layout,这样不如手写代码
layout是自适应布局,所以大小和位置是自动的,而不是手动调整。要调整,就到右下角属性栏里,调整stretch的拉伸比例
仔细看了好久还是感觉用不利索,不得要领,这货估计还得现场演示一下才行。ui编辑器里面布局管理器就一小红线框,层数多了,鼠标拖放操作都巨麻烦,qt自带的example全都是手写布局管理器的。并没有ui编辑器里面使用布局管理器的例子。
大佬,layout可以设置控件比例是layoutStretch吗