PyQt5中QGridLayout的setRowStretch不生效问题如何解决
问题描述
在PyQt5中使用QGridLayout布局开发计算器GUI时,调用setRowStretch()方法想要实现按钮行的垂直拉伸效果,但方法始终没有达到预期,而同布局下的setColumnStretch()方法可以正常工作。
复现代码
import PyQt5.QtWidgets as qtw import PyQt5.QtGui as qtg import PyQt5.QtCore as qtcore class MainWindow(qtw.QWidget): def __init__(self): super().__init__() # Add a title self.setWindowTitle('Calculator - Anh Nguyen') # Create a label my_label = qtw.QLabel("0") # Set background color my_label.setStyleSheet("background-color: #e3e1da;\ border: 1px solid black") my_label.setMaximumHeight(50) # Align label text my_label.setAlignment(qtcore.Qt.AlignmentFlag.AlignVCenter | qtcore.Qt.AlignmentFlag.AlignRight) my_label.setFont(qtg.QFont('Helvetica', 20)) # Add grid layout for calculator buttons main_gridlayout = qtw.QGridLayout() main_gridlayout.addWidget(my_label, 0, 0, 1, 4) main_gridlayout.addWidget(qtw.QPushButton('%'), 1, 0) main_gridlayout.addWidget(qtw.QPushButton('CE'), 1, 1) main_gridlayout.addWidget(qtw.QPushButton('C'), 1, 2) main_gridlayout.addWidget(qtw.QPushButton('BKSP'), 1, 3) main_gridlayout.addWidget(qtw.QPushButton('7'), 2, 0) main_gridlayout.addWidget(qtw.QPushButton('8'), 2, 1) main_gridlayout.addWidget(qtw.QPushButton('9'), 2, 2) main_gridlayout.addWidget(qtw.QPushButton('/'), 2, 3) main_gridlayout.addWidget(qtw.QPushButton('4'), 3, 0) main_gridlayout.addWidget(qtw.QPushButton('5'), 3, 1) main_gridlayout.addWidget(qtw.QPushButton('6'), 3, 2) main_gridlayout.addWidget(qtw.QPushButton('-'), 3, 3) main_gridlayout.addWidget(qtw.QPushButton('1'), 4, 0) main_gridlayout.addWidget(qtw.QPushButton('2'), 4, 1) main_gridlayout.addWidget(qtw.QPushButton('3'), 4, 2) main_gridlayout.addWidget(qtw.QPushButton('+'), 4, 3) main_gridlayout.addWidget(qtw.QPushButton('+/-'), 5, 0) main_gridlayout.addWidget(qtw.QPushButton('0'), 5, 1) main_gridlayout.addWidget(qtw.QPushButton('.'), 5, 2) main_gridlayout.addWidget(qtw.QPushButton('='), 5, 3) # This is NOT working: main_gridlayout.setRowStretch(1,1) # This is working main_gridlayout.setColumnStretch(2,1) self.setLayout(main_gridlayout) self.show() app = qtw.QApplication([]) mw = MainWindow() app.exec_()
问题原因
setRowStretch()方法本身没有故障,视觉上不生效是两个PyQt5布局默认规则共同导致的:
QPushButton默认的垂直大小策略为QSizePolicy.Fixed:该策略下按钮的高度会固定为自身推荐高度(sizeHint返回值),就算布局给所在行分配了更多垂直空间,按钮也不会主动拉伸占满空间,只会保持原有高度居中显示,看起来就像行拉伸没有生效。- 拉伸因子设置范围不对:代码中仅给索引为1的按钮行设置了拉伸因子1,其余4行按钮所在行(索引2-5)的拉伸因子默认是0,就算拉伸规则生效,窗口的多余垂直空间也只会全部分配给第1行,其余按钮行依然保持原有高度。
setColumnStretch()能正常工作的原因是QPushButton默认水平大小策略为QSizePolicy.Preferred,允许水平方向拉伸填满分配到的列空间。
修复方案
如果需要所有按钮行均匀占满显示标签下方的全部垂直空间、按钮自动拉伸填满对应行,做两处修改即可:
- 给所有按钮行(索引1到5)设置相同的拉伸因子,让各行按比例平分多余垂直空间
- 将所有按钮的垂直大小策略改为
QSizePolicy.Expanding,允许按钮跟随行的分配空间拉伸高度
替换原有设置拉伸的代码片段即可:
# 给1-5行的按钮行设置相同拉伸因子,均匀分配垂直空间 for row_idx in range(1, 6): main_gridlayout.setRowStretch(row_idx, 1) # 遍历布局内所有控件,将按钮的大小策略改为双向可扩展 for i in range(main_gridlayout.count()): item = main_gridlayout.itemAt(i) w = item.widget() if isinstance(w, qtw.QPushButton): w.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.Expanding)
如果只需要某一行单独占用多余垂直空间,只给对应行设置拉伸因子,同时修改该行内按钮的垂直大小策略即可。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

