自定义折叠Widget导致窗口尺寸异常,如何恢复原始高度?
解决Qt可折叠Section Widget折叠后窗口高度不重置的问题
问题描述
之前参考的Qt可展开/折叠Section Widget实现方案存在缺陷:当Widget展开后再关闭,窗口尺寸不会自动重置,会留下空白区域。

以下是最小复现代码(需导入原方案中的Spoiler组件):
QApplication a(argc, argv); QWidget* widget = new QWidget(); widget->setFixedWidth(500); QVBoxLayout* mainLayout = new QVBoxLayout(widget); QFrame* widgetTop = new QFrame(); widgetTop->setFrameShape(QFrame::StyledPanel); widgetTop->setFixedHeight(50); QHBoxLayout* layoutTop = new QHBoxLayout(widgetTop); QLabel* labelTop = new QLabel("widget-top"); labelTop->setAlignment(Qt::AlignCenter); layoutTop->addWidget(labelTop); mainLayout->addWidget(widgetTop); QFrame* widgetMiddle = new QFrame(); widgetMiddle->setFrameShape(QFrame::StyledPanel); widgetMiddle->setFixedHeight(150); QHBoxLayout* layoutMiddle = new QHBoxLayout(widgetMiddle); QLabel* labelMiddle = new QLabel("widget-middle"); labelMiddle->setAlignment(Qt::AlignCenter); layoutMiddle->addWidget(labelMiddle); mainLayout->addWidget(widgetMiddle); QFrame* widgetBottom = new QFrame(); widgetBottom->setFrameShape(QFrame::StyledPanel); widgetBottom->setFixedHeight(100); QHBoxLayout* layoutBottom = new QHBoxLayout(widgetBottom); QLabel* labelBottom = new QLabel("widget-bottom"); labelBottom->setAlignment(Qt::AlignCenter); layoutBottom->addWidget(labelBottom); auto* anyLayout = new QVBoxLayout(); anyLayout->addWidget(widgetBottom); Spoiler* spoiler = new Spoiler("I'm buggy", 100); spoiler->setContentLayout(*anyLayout); mainLayout->addWidget(spoiler); // 显示主窗口 widget->show(); return a.exec();
尝试过直接调用adjustSize(),但与原方案的QPropertyAnimation存在兼容性问题,无法正常生效。
解决方案
1. 修正Spoiler组件的尺寸提示
重写Spoiler类的sizeHint()和minimumSizeHint()方法,确保折叠/展开状态下组件的尺寸计算正确:
QSize Spoiler::sizeHint() const { if (m_collapsed) { // 折叠状态仅返回头部高度 return QSize(QWidget::sizeHint().width(), m_headerHeight); } else { // 展开状态返回头部+内容高度 return QSize(QWidget::sizeHint().width(), m_headerHeight + m_contentHeight); } } QSize Spoiler::minimumSizeHint() const { return sizeHint(); }
2. 动画过程中实时更新布局
在Spoiler类的动画valueChanged信号中,更新组件最小高度并通知布局重新计算:
// 在Spoiler的构造函数或初始化逻辑中添加 connect(m_animation, &QPropertyAnimation::valueChanged, this, [this](const QVariant& value){ setMinimumHeight(value.toInt()); updateGeometry(); // 通知布局尺寸已变更 });
3. 动画结束后触发窗口尺寸调整
在动画完成时,主动通知父布局更新,并让主窗口调整到合适高度:
// 在Spoiler的构造函数或初始化逻辑中添加 connect(m_animation, &QPropertyAnimation::finished, this, [this](){ // 激活父布局,确保所有子组件尺寸正确更新 if (parentWidget() && parentWidget()->layout()) { parentWidget()->layout()->activate(); } // 让主窗口自动调整到合适高度 if (QWidget* mainWindow = window()) { mainWindow->adjustSize(); } });
额外注意
如果主窗口设置了fixedWidth但高度自适应,上述代码就能完美解决空白问题;如果主窗口是完全自适应尺寸,也能确保折叠后窗口高度回到原始状态。
内容的提问来源于stack exchange,提问作者Hippo
相关产品推荐
相关产品推荐

