You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义折叠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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 02:13:08