3. 布局管理器入门:QHBoxLayout水平布局、QVBoxLayout垂直布局、布局嵌套与伸缩因子(stretch)

布局管理器,说白了就是帮我们自动排列控件的工具。你想想看,如果每个按钮、每个输入框都要手动计算坐标,那界面稍微一调整,整个代码就得重写。我刚开始学Qt时,就吃过这个亏——写死坐标的界面,窗口一拉大,控件全挤在左上角,丑得没法看。

后来我才明白,布局管理器才是正道。今天我们就从最基础的两种布局讲起:水平布局和垂直布局。再聊聊它们怎么嵌套,以及伸缩因子怎么用。

3.1 QHBoxLayout:水平布局

QHBoxLayout,就是把控件从左到右排成一行。我习惯叫它「横着排」。你放三个按钮进去,它们就肩并肩站好。

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

app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle('水平布局示例')

layout = QHBoxLayout()
btn1 = QPushButton('按钮1')
btn2 = QPushButton('按钮2')
btn3 = QPushButton('按钮3')

layout.addWidget(btn1)
layout.addWidget(btn2)
layout.addWidget(btn3)

window.setLayout(layout)
window.show()
sys.exit(app.exec_())

运行一下,三个按钮从左到右排开。窗口拉宽,按钮间距自动变大。嗯,这就是布局管理器的好处——自适应。

小技巧: 如果你想让按钮靠右对齐,可以在添加控件之前先加一个「弹簧」:layout.addStretch()。这样弹簧会占据左边空间,把按钮挤到右边去。

3.2 QVBoxLayout:垂直布局

QVBoxLayout正好相反,从上到下排。我叫它「竖着排」。用法和水平布局几乎一模一样。

layout = QVBoxLayout()
layout.addWidget(btn1)
layout.addWidget(btn2)
layout.addWidget(btn3)

就这么简单。三个按钮从上到下依次排列。窗口拉高,间距自动调整。

我在项目中遇到过一个问题:垂直布局里放了一堆控件,结果窗口高度不够,底部的按钮被截断了。后来我加了一个滚动区域(QScrollArea),才解决。所以,如果你控件太多,记得考虑滚动条。

3.3 布局嵌套:组合拳才是王道

光有水平和垂直还不够。实际项目中,我们经常需要混合使用。比如:左边一个垂直布局放标签和输入框,右边一个垂直布局放按钮,外面再套一个水平布局把它们并排放。

这就是布局嵌套。说白了,就是把一个布局当作控件,塞进另一个布局里。

# 外层水平布局
main_layout = QHBoxLayout()

# 左侧垂直布局
left_layout = QVBoxLayout()
left_layout.addWidget(QLabel('用户名:'))
left_layout.addWidget(QLineEdit())
left_layout.addWidget(QLabel('密码:'))
left_layout.addWidget(QLineEdit())

# 右侧垂直布局
right_layout = QVBoxLayout()
right_layout.addWidget(QPushButton('登录'))
right_layout.addWidget(QPushButton('注册'))
right_layout.addStretch()  # 让按钮靠上

# 嵌套
main_layout.addLayout(left_layout)
main_layout.addLayout(right_layout)

window.setLayout(main_layout)

你看,这样一组合,界面就灵活多了。左侧是表单,右侧是操作按钮。布局嵌套可以无限层,但建议别超过三层,否则代码可读性会下降。

注意: 嵌套布局时,用 addLayout() 而不是 addWidget()。我刚开始就搞混过,结果控件死活不显示。检查了半天才发现是方法用错了。

3.4 伸缩因子(stretch):控制空间分配

伸缩因子,是布局管理器里最强大的功能之一。它决定了当窗口大小变化时,控件之间如何分配多余的空间。

举个例子:三个按钮水平排列,我希望按钮2占据的空间是按钮1的两倍,按钮3和按钮1一样大。怎么做?

layout = QHBoxLayout()
layout.addWidget(btn1, 1)   # 伸缩因子为1
layout.addWidget(btn2, 2)   # 伸缩因子为2
layout.addWidget(btn3, 1)   # 伸缩因子为1

窗口拉宽时,按钮2会获得两倍于按钮1和按钮3的额外空间。说白了,伸缩因子就是「抢地盘」的权重。

我曾经在做一个监控面板时,需要让中间的图表区域尽可能大,两侧的工具栏只占最小空间。我就把中间的控件伸缩因子设为5,两侧设为1。效果立竿见影。

核心要点: 伸缩因子只分配「多余空间」,不会压缩控件的最小尺寸。如果窗口太小,控件会保持最小大小,不会无限缩小。

3.5 知识体系总览

下面这张图,帮你理清本章的核心逻辑:

布局管理器知识体系 QHBoxLayout 从左到右排列 addWidget() addStretch() QVBoxLayout 从上到下排列 addWidget() addStretch() 布局嵌套 addLayout() 混合使用 灵活组合 伸缩因子(stretch) 控制多余空间的分配比例 addWidget(控件, 伸缩因子) 核心思想:用布局管理器代替手动坐标,让界面自适应

3.6 避坑指南

最后,分享几个我踩过的坑:

  • 布局不生效? 检查一下是不是忘了调用 setLayout()。我犯过这种低级错误,找了半小时。
  • 控件大小不对? 看看是不是设置了固定大小(setFixedSize())。布局管理器对固定大小的控件无能为力。
  • 嵌套布局乱了? 建议从外到内逐层构建。先搭好外层框架,再填充内部细节。
  • 伸缩因子不工作? 确认一下是不是所有控件都设置了伸缩因子。如果有一个没设,它默认是0,不会参与空间分配。

嗯,布局管理器就讲到这里。记住一句话:能用布局解决的问题,别用手动坐标。你的界面会感谢你的。

课后练习: 用QHBoxLayout和QVBoxLayout做一个简单的登录界面。左侧放标签和输入框,右侧放登录和取消按钮。试试给按钮设置不同的伸缩因子,观察窗口大小变化时的效果。