PyQt5中QGridLayout布局比例异常问题求助
解决QGridLayout中PyQtGraph PlotWidget高度比例异常问题
你试图通过QGridLayout的行跨度设置让包含5个绘图的self.p1高度为仅含1个绘图的self.p2的5倍,但实际效果完全相反。问题出在QGridLayout的行高不会自动均等分配,直接依赖行跨度无法保证比例,必须显式设置行的拉伸因子。
解决方案
使用QGridLayout.setRowStretch()方法指定行的拉伸比例,强制布局按设定的比例分配垂直空间:
- 将两个PlotWidget分别放在同一列的不同行,各占1行;
- 为对应行设置拉伸因子,比例为5:1;
- 调整左侧布局的行跨度,让它覆盖两个PlotWidget所在的行。
修改后的关键代码
# 左侧布局占用第0、1行,共2行 grid_layout.addLayout(vlayout_signals, 0, 0, 2, 1) # 将self.p1放在第0行第1列,self.p2放在第1行第1列 grid_layout.addWidget(self.p1, 0, 1) grid_layout.addWidget(self.p2, 1, 1) # 设置行拉伸比例:第0行占5份,第1行占1份 grid_layout.setRowStretch(0, 5) grid_layout.setRowStretch(1, 1)
完整修改后的代码
NFRAME = 200 * 6 import sys import numpy as np from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QWidget, QGridLayout, QComboBox, QSlider from PyQt5.QtGui import QColor import pyqtgraph as pg class MainWindow(QMainWindow): def __init__(self): super().__init__() grid_layout = QGridLayout() self.p1 = pg.PlotWidget() self.p2 = pg.PlotWidget() self.p1.plotItem.addLegend() self.p2.plotItem.addLegend() x = np.linspace(0, 2 * np.pi * 2, NFRAME) y1 = np.sin(2 * np.pi * 1 * x) y2 = 10 * np.sin(2 * np.pi * 2 * x) + 50 y3 = 20 * np.sin(2 * np.pi * 3 * x) + 200 y4 = 30 * np.sin(2 * np.pi * 4 * x) + 300 y5 = 40 * np.sin(2 * np.pi * 5 * x) + 400 self.ph1_y1 = self.p1.plot(x, y1, pen=pg.mkPen(QColor(255, 0, 0)), name="y1") self.ph1_y2 = self.p1.plot(x, y2, pen=pg.mkPen(QColor(255, 255, 0)), name="y2") self.ph1_y3 = self.p1.plot(x, y3, pen=pg.mkPen(QColor(0, 255, 255)), name="y3") self.ph1_y4 = self.p1.plot(x, y4, pen=pg.mkPen(QColor(255, 0, 255)), name="y4") self.ph1_y5 = self.p1.plot(x, y5, pen=pg.mkPen(QColor(102, 102, 255)), name="y5") self.ph2_y1 = self.p2.plot(x, 0 * x + 6) signal_select = QComboBox(self) signal_select.addItem("Item1") signal_select.addItem("Item2") signal_offset = QSlider(Qt.Orientation.Vertical) signal_gain = QSlider(Qt.Orientation.Vertical) hlayout_sliders = QHBoxLayout() hlayout_sliders.addWidget(signal_offset) hlayout_sliders.addWidget(signal_gain) hlayout_sliders_labels = QHBoxLayout() signal_offset_label = QLabel() signal_gain_label = QLabel() signal_offset_label.setText("Offset") signal_offset_label.setAlignment(Qt.AlignCenter) signal_gain_label.setText("Gain") signal_gain_label.setAlignment(Qt.AlignCenter) hlayout_sliders_labels.addWidget(signal_offset_label) hlayout_sliders_labels.addWidget(signal_gain_label) arduino_signal_reset = QPushButton("Reset") vlayout_signals = QVBoxLayout() vlayout_signals.addWidget(signal_select) vlayout_signals.addLayout(hlayout_sliders) vlayout_signals.addLayout(hlayout_sliders_labels) vlayout_signals.addWidget(arduino_signal_reset) # 修正布局设置 grid_layout.addLayout(vlayout_signals, 0, 0, 2, 1) grid_layout.addWidget(self.p1, 0, 1) grid_layout.addWidget(self.p2, 1, 1) grid_layout.setRowStretch(0, 5) grid_layout.setRowStretch(1, 1) widget = QWidget() widget.setLayout(grid_layout) self.setCentralWidget(widget) self.setWindowTitle('My software') if __name__ == '__main__': app = QApplication(sys.argv) windowExample = MainWindow() windowExample.show() sys.exit(app.exec_())
原理说明
QGridLayout默认会根据控件的最小尺寸分配行高,直接让控件占用多行时,这些行的高度会被控件的内容撑开,无法保证比例。通过setRowStretch()设置的拉伸因子,会在布局有额外空间时,按比例分配给对应行,从而强制实现你需要的5:1高度比。
内容的提问来源于stack exchange,提问作者shashashamti2008
相关产品推荐
相关产品推荐

