跳转到内容
新建笔记

Qt 布局尺寸:QSizePolicy、sizeHint 与伸缩比例

窗口变大时,布局要决定多出来的空间交给谁;窗口变小时,又要决定哪些控件可以收缩。QSizePolicy 表达控件意愿,sizeHint() 提供建议尺寸,最小和最大尺寸给出约束,布局的 stretch 则表达同方向项目之间的相对伸缩权重。

设置回答的问题常见误解
sizeHint()控件认为多大合适?它不保证最终尺寸
minimumSize、maximumSize尺寸不能越过什么边界?Expanding 不会解除固定宽高
QSizePolicy能否伸缩、是否希望利用额外空间?它不是一个像素尺寸
布局 stretch同一布局的主方向上,谁获得更大的份额?权重不是百分比,也不是子控件编号

Qt 的布局管理说明与 QWidget 尺寸文档共同规定这些信息如何参与布局。对于有最小宽度、最大宽度或不同尺寸提示的控件,最终比例还会受边界约束。

2. Expanding 实际表示什么

跳转到“2. Expanding 实际表示什么”

原笔记中的代码:

overallContainer->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);

第一个参数用于水平方向,第二个用于垂直方向。这表示控件能够伸缩,而且能有效利用额外空间,适合图表、文本编辑区等内容区域。它并不命令控件忽略兄弟控件或填满整个窗口。

常见策略可以这样选择:

策略相对尺寸提示的行为典型意图
Fixed不伸不缩尺寸应保持稳定
Minimum可以长大,不希望小于提示尺寸完整显示内容
Maximum可以缩小,不需要超过提示尺寸限制不必要扩张
Preferred可以伸缩,提示尺寸最合适普通控件的默认偏好
Expanding可以伸缩,希望多分空间主要内容区域
MinimumExpanding提示尺寸是下限,希望长大保持最低可用空间
Ignored忽略尺寸提示参与分配仅在明确掌握尺寸约束时使用

这些含义来自 QSizePolicy 的策略定义。实际设计还需检查文本换行、最小尺寸和布局内边距。

3. setStretch(4, 1) 的两个参数

跳转到“3. setStretch(4, 1) 的两个参数”
workspaceLayout->setStretch(4, 1);

对于 QHBoxLayout 或 QVBoxLayout:

  1. 4 是布局项目的零起始索引,指第 5 个项目。
  2. 1 是相对伸缩权重。
  3. 横向布局分配宽度,纵向布局分配高度。
  4. 布局项目可以是控件、子布局或间隔;插入新项目后,数字索引可能改变。

若没有其他正权重,权重为 1 的可扩展项目通常会承担主要剩余空间;其他项目仍须满足自身尺寸约束。若两个无额外限制的区域权重分别为 1 和 3,可用空间充足时会趋近 1:3。不要把任何布局的最终像素宽度都承诺为严格 1:3。

已知控件时可以减少索引误用:

const bool found = workspaceLayout->setStretchFactor(overallContainer, 1);
Q_ASSERT(found);

这只寻找该布局直接包含的项目,不递归查找所有子布局。依据:QBoxLayout 的 stretch 接口。

下面示例适用于 Qt 6 Widgets。左侧导航和右侧编辑区都允许扩展,布局权重分别为 1 与 3。

#include <QApplication>
#include <QHBoxLayout>
#include <QListWidget>
#include <QSizePolicy>
#include <QTextEdit>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
auto *layout = new QHBoxLayout(&window);
auto *navigation = new QListWidget;
auto *editor = new QTextEdit;
navigation->addItems({"Overview", "Measurements", "Notes"});
editor->setPlainText("Resize the window to inspect the layout.");
navigation->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
editor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(navigation, 1);
layout->addWidget(editor, 3);
window.resize(960, 540);
window.show();
return app.exec();
}

保存为 main.cpp,最小 CMakeLists.txt 为:

cmake_minimum_required(VERSION 3.21)
project(LayoutDemo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(layout-demo main.cpp)
target_link_libraries(layout-demo PRIVATE Qt6::Widgets)

构建时让 CMAKE_PREFIX_PATH 指向本机 Qt 开发套件。先拖大、再缩小窗口;到达控件的最小尺寸时观察比例变化,比只在一种窗口尺寸下截图更能检验布局。

5. “设了 Expanding 仍不生效”的检查顺序

跳转到“5. “设了 Expanding 仍不生效”的检查顺序”
  1. 确认控件加入了目标布局,布局也已安装到显示中的父控件。
  2. 查找 setFixedWidth、setFixedHeight、最大尺寸和样式表尺寸限制。
  3. 确认改的是横向还是纵向;检查直接父布局和上层布局各自的约束。
  4. 确认 setStretch 的索引未因插入间隔或嵌套布局而偏移。
  5. 检查 addWidget 的 alignment;指定居中等对齐可能让控件不填满分配给它的单元。

本页把原先两个仅有 TODO 和相同代码行的记录整合为同一问题链:先理解控件尺寸意愿,再理解布局空间分配。