You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PyQt5隐藏部件后如何调整窗口至更小尺寸且不固定大小?

问题:PyQt5中隐藏图表后窗口resize无效,如何动态调整窗口大小?

我正在实现点击按钮隐藏/显示图表的功能,但隐藏图表后调用self.resize()似乎被忽略,窗口无法恢复到之前的小尺寸。用setFixedSize()虽然能生效,但我不想固定窗口尺寸,尝试用setSizePolicy()取消固定也没效果。我的代码如下:

import sys
import matplotlib.pyplot as plt
from PyQt5.Qt import QSizePolicy
from PyQt5.QtWidgets import (
    QDialog, QApplication, QGridLayout, QWidget,
    QGroupBox, QPushButton
)
from matplotlib.backends.backend_qt5agg import \
    FigureCanvasQTAgg as FigureCanvas

class MainWindow(QDialog):
    def __init__(self):
        super().__init__()
        self.layout = QGridLayout()
        self.setLayout(self.layout)

        self.settings = QGroupBox('Settings:')
        self.settingsLayout = QGridLayout()
        self.settings.setLayout(self.settingsLayout)
        self.showFigureBtn = QPushButton('Show Figure')
        self.settingsLayout.addWidget(self.showFigureBtn)
        self.layout.addWidget(self.settings)

        self.figureWidget = QWidget()
        self.figureWidget.setMinimumSize(300, 300)
        self.figureLayout = QGridLayout(self.figureWidget)
        self.fig, self.ax = plt.subplots()
        self.canvas = FigureCanvas(self.fig)
        self.figureLayout.addWidget(self.canvas)
        self.figureWidget.setLayout(self.figureLayout)
        self.layout.addWidget(self.figureWidget)
        self.figureWidget.setVisible(False)

        self.showFigureBtn.clicked.connect(self.toggle_figure)
        self.min_size = (300, 100)
        self.resize(*self.min_size)

    def toggle_figure(self):
        state = not self.figureWidget.isVisible()
        if state:
            self.showFigureBtn.setText('Hide Figure')
            self.min_size = self.size()
            self.figureWidget.setVisible(state)
        else:
            self.showFigureBtn.setText('Show Figure')
            self.figureWidget.setVisible(state)
            self.resize(self.min_size)
            # self.setFixedSize(self.min_size)
            # self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    GUI = MainWindow()
    GUI.show()
    sys.exit(app.exec_())

解决方案

这个问题的核心是Qt的布局管理器会自动调整窗口大小以适应内容,当你隐藏图表组件后,布局会重新计算,但直接调用resize()会被布局的自动调整逻辑覆盖。另外你当前记录min_size的时机也不对——应该在隐藏前保存你想要恢复的尺寸,而不是显示时记录当前窗口大小。

下面是修复后的代码,我标注了关键改动点:

import sys
import matplotlib.pyplot as plt
from PyQt5.QtWidgets import (
    QDialog, QApplication, QGridLayout, QWidget,
    QGroupBox, QPushButton, QLayout
)
from matplotlib.backends.backend_qt5agg import \
    FigureCanvasQTAgg as FigureCanvas

class MainWindow(QDialog):
    def __init__(self):
        super().__init__()
        # 设置布局的尺寸约束,确保允许窗口缩小到合理尺寸
        self.layout = QGridLayout()
        self.layout.setSizeConstraint(QLayout.SetDefaultConstraint)
        self.setLayout(self.layout)

        self.settings = QGroupBox('Settings:')
        self.settingsLayout = QGridLayout()
        self.settings.setLayout(self.settingsLayout)
        self.showFigureBtn = QPushButton('Show Figure')
        self.settingsLayout.addWidget(self.showFigureBtn)
        self.layout.addWidget(self.settings)

        self.figureWidget = QWidget()
        self.figureWidget.setMinimumSize(300, 300)
        self.figureLayout = QGridLayout(self.figureWidget)
        self.fig, self.ax = plt.subplots()
        self.canvas = FigureCanvas(self.fig)
        self.figureLayout.addWidget(self.canvas)
        self.figureWidget.setLayout(self.figureLayout)
        self.layout.addWidget(self.figureWidget)
        self.figureWidget.setVisible(False)

        self.showFigureBtn.clicked.connect(self.toggle_figure)
        # 初始最小尺寸固定为设置面板的大小
        self.min_size = (300, 100)
        self.resize(*self.min_size)

    def toggle_figure(self):
        state = not self.figureWidget.isVisible()
        if state:
            self.showFigureBtn.setText('Hide Figure')
            self.figureWidget.setVisible(state)
            # 显示图表后让窗口自动适配内容
            self.adjustSize()
        else:
            self.showFigureBtn.setText('Show Figure')
            self.figureWidget.setVisible(state)
            # 先让布局重新计算最小需要的尺寸
            self.adjustSize()
            # 再设置回目标最小尺寸
            self.resize(self.min_size)
            # 允许用户之后自由调整窗口大小
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    GUI = MainWindow()
    GUI.show()
    sys.exit(app.exec_())

关键改动说明:

  1. 布局尺寸约束:给主布局添加setSizeConstraint(QLayout.SetDefaultConstraint),确保布局允许窗口缩小到内容所需的最小尺寸(默认其实是这个值,但明确设置更稳妥)
  2. 调整时机:显示图表时调用adjustSize()让窗口自动适配图表+设置面板的大小;隐藏图表时,先调用adjustSize()让布局计算出仅显示设置面板的最小尺寸,再调用resize()设置回你想要的min_size
  3. 修正min_size记录逻辑:不再在显示图表时记录当前尺寸,而是固定初始的最小尺寸(如果你需要动态记录隐藏前的窗口大小,可以在隐藏前添加self.min_size = self.size()
  4. 恢复尺寸策略:隐藏后设置setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding),确保用户之后可以自由调整窗口大小,不会被固定

这样修改后,点击按钮隐藏图表时窗口会正确缩回到你设置的最小尺寸,同时保持窗口可自由调整的特性。

内容的提问来源于stack exchange,提问作者mapf

火山引擎 最新活动