一、GUI布局管理简介

PyQt5中进行界面布局管理的方法主要由两种,一种是绝对定位,一种是使用布局管理器。Qt中使用绝对定位的布局方式无法自适应窗口的变化,因此Qt中提供了对界面组件进行布局管理的类,用于对界面组件进行管理,能够自动排列窗口中的界面组件,窗口大小变化后自动更新界面组件的大小。
PyQt5布局管理_布局管理器
QLayout是Qt中布局管理器的抽象基类,通过对QLayout的继承,实现了功能各异且互补的布局管理器。布局管理器不是界面组件,而是界面组件的定位策略;任意容器类型的组件都可以指定布局管理器;同一个布局管理器管理中的组件拥有相同的父组件,在设置布局管理器的同时已经隐式指定了父子关系。
Qt布局管理器的addWidget用于向布局管理器中插入控件,addLayout用于向布局管理器插入子布局管理器。

二、框布局

1、QHBoxLayout

QHBoxLayout提供了水平方式对控件进行布局管理。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QSizePolicy

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QHBoxLayout()
self.layout.setSpacing(20)
button = QPushButton("Button1")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.layout.addWidget(button)

button = QPushButton("Button2")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.layout.addWidget(button)

self.setLayout(self.layout)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

2、QVBoxLayout

QVBoxLayout提供了垂直方式对控件进行布局管理。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QSizePolicy

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QVBoxLayout()
self.layout.setSpacing(20)
button = QPushButton("Button1")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.layout.addWidget(button)

button = QPushButton("Button2")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.layout.addWidget(button)

self.setLayout(self.layout)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

3、嵌套布局

布局管理器可以相互嵌套,形成复杂的布局管理方式。QBoxLayout布局管理器的嵌套使用实例如下:
PyQt5布局管理_布局管理器_02

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QSizePolicy

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QVBoxLayout()
self.layout.setSpacing(20)
# 第一行按钮布局管理
hLayout1 = QHBoxLayout()
button = QPushButton("Button1")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
hLayout1.addWidget(button)
button = QPushButton("Button2")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
hLayout1.addWidget(button)
# 第二行按钮布局管理
hLayout2 = QHBoxLayout()
button = QPushButton("Button1")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
hLayout2.addWidget(button)
button = QPushButton("Button2")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
hLayout2.addWidget(button)
# 整体垂直布局管理
self.layout.addLayout(hLayout1)
self.layout.addLayout(hLayout2)

self.setLayout(self.layout)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

三、网格布局

QGridLayout布局管理器以网格的方式管理界面组件。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QPushButton, QSizePolicy

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QGridLayout()
self.layout.setSpacing(5)
button = QPushButton("Button1")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
self.layout.addWidget(button, 0, 0, 1, 1)

button = QPushButton("Button2")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
self.layout.addWidget(button, 0, 1, 1, 1)

button = QPushButton("Button3")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
self.layout.addWidget(button, 1, 0, 1, 1)

button = QPushButton("Button4")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
self.layout.addWidget(button, 1, 1, 1, 1)

button = QPushButton("Button5")
button.setMinimumSize(60, 30)
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# 列扩展,定位在第2行第1列位置,占1行2列
self.layout.addWidget(button, 2, 0, 1, 2)

self.setLayout(self.layout)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

四、表单布局

QFormLayout布局管理器使用表单的方式管理界面组件,表单中的标签和组件是相互对应的关系,支持嵌套使用。
PyQt5布局管理_控件_03

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QFormLayout, QVBoxLayout, QLineEdit
from PyQt5.QtCore import Qt

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QFormLayout()
self.layout.setSpacing(20)
self.layout.setLabelAlignment(Qt.AlignLeft)
self.layout.setFormAlignment(Qt.AlignRight)
nameEdit = QLineEdit()
mailEdit = QLineEdit()
vLayout = QVBoxLayout()
vLayout.setSpacing(6)
addrEdit1 = QLineEdit()
addrEdit2 = QLineEdit()
vLayout.addWidget(addrEdit1)
vLayout.addWidget(addrEdit2)
self.layout.addRow("Name:", nameEdit)
self.layout.addRow("Mail:", mailEdit)
self.layout.addRow("Address:", vLayout)

self.setLayout(self.layout)
self.setWindowTitle("FTP")

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

PyQt5布局管理_控件_04

五、栈式布局

QStackedLayout栈式布局管理器管理的所有组件在垂直于屏幕的方向上,每次只有一个界面组件会显示在屏幕上,只要最顶层的界面组件会被显示。
QStackedLayout栈式布局管理器的特点如下:
A、组件大小一致,且充满父组件的显示区
B、不能直接嵌套其它布局管理器
C、能够自由切换需要显示的组件
D、每次仅能显示一个界面组件
PyQt5布局管理_布局管理器_05

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QStackedLayout, QVBoxLayout, QPushButton

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QStackedLayout()
self.layout.addWidget(QPushButton("Button1"))
self.layout.addWidget(QPushButton("Button2"))
self.layout.addWidget(QPushButton("Button3"))
self.layout.addWidget(QPushButton("Button4"))

self.setLayout(self.layout)
self.setWindowTitle("Stack Layout")
# 设置栈顶显示第2个组件
self.layout.setCurrentIndex(2)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

QStackedLayout栈式布局管理器不能直接嵌套其它布局管理器,但可以通过QWidget容器组件间接嵌套使用其它布局管理器。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QStackedLayout, QVBoxLayout, QPushButton

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QStackedLayout()
self.layout.addWidget(QPushButton("Button1"))

# 容器型组件
widget = QWidget()
vLayout = QVBoxLayout()
vLayout.addWidget(QPushButton("Button2"))
vLayout.addWidget(QPushButton("Button3"))
widget.setLayout(vLayout)
self.layout.addWidget(widget)

self.layout.addWidget(QPushButton("Button4"))

self.setLayout(self.layout)
self.setWindowTitle("Stack Layout")
# 设置栈顶显示第1个组件
self.layout.setCurrentIndex(1)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

六、分割器

QSplitter是一个带切分条(splitter handle)的布局管理器,可以通过setHandleWidth()函数来设置切分条的宽带。QSplitter可以通过setOrientation()函数来指定分割方向,子组件按加载顺序进行指定方向排列。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QVBoxLayout, QSplitter
from PyQt5.QtCore import Qt

class MainWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.layout = QVBoxLayout()
self.mainSplitter = QSplitter(self)
self.layout.addWidget(self.mainSplitter)
self.setLayout(self.layout)
# 水平线分割
self.mainSplitter.setOrientation(Qt.Horizontal)

rightSplitter = QSplitter(self)
# 垂直线分割
rightSplitter.setOrientation(Qt.Vertical)
textEdit = QTextEdit()
textEdit.setText("Window2")
rightSplitter.addWidget(textEdit)
textEdit = QTextEdit()
textEdit.setText("Window3")
rightSplitter.addWidget(textEdit)

textEdit = QTextEdit()
textEdit.setText("Window1")
self.mainSplitter.addWidget(textEdit)
self.mainSplitter.addWidget(rightSplitter)
# 分割比例
self.mainSplitter.setStretchFactor(0, 1)
self.mainSplitter.setStretchFactor(1, 2)

self.mainSplitter.show()
self.setWindowTitle("Splitter")

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 200)
window.show()

sys.exit(app.exec_())

PyQt5布局管理_嵌套_06