一、栅格布局的核心机制与基础应用
1.1 什么是QGridLayout
QGridLayout是Qt中的网格布局管理器,它将界面划分为行(row)和列(column)组成的二维矩阵。每个组件被放置在由行号和列号确定的单元格(cell)中,支持组件跨越多行或多列(通过rowSpan和columnSpan参数实现)。
核心特点:
动态调整:窗口缩放时自动按比例分配单元格空间
对齐控制:通过Qt::Alignment指定组件的对齐方式(如Qt::AlignCenter)
间距控制:setHorizontalSpacing()和setVerticalSpacing()精确控制间距。
1.2 基础代码示例
以3×3按钮网格举例
// 创建网格布局和父窗口
QWidget *window = new QWidget;
QGridLayout *grid = new QGridLayout(window);
// 添加按钮到网格
for(int row=0; row<3; row++) {
for(int col=0; col<3; col++) {
QPushButton *btn = new QPushButton(
QString("R%1 C%2").arg(row).arg(col)
);
// 关键:指定行和列
grid->addWidget(btn, row, col);
}
}
window->show();
此时界面呈现规整的3×3网格(如图:R代表行,C代表列)
1.3 实现复杂布局:跨行/跨列
// 添加跨两列的按钮
grid->addWidget(new QPushButton("跨列按钮"), 0, 0, 1, 2);
// 添加跨两行的标签
grid->addWidget(new QLabel("纵向标签"), 1, 2, 2, 1);
此时界面呈现规如下图的网格效果
二、动态布局控制:隐藏元素与空间重分配
2.1 默认隐藏行为的问题
当直接调用上面按钮btn->hide()时,Qt默认会回收该部件所占空间,导致相邻组件移动(如图示)
代码示例
QGridLayout *grid = new QGridLayout(ui->widgetTest);
// 添加按钮到网格
for(int row=0; row<3; row++) {
for(int col=0; col<3; col++) {
QPushButton *btn = new QPushButton(
QString("R%1 C%2").arg(row).arg(col), ui->widgetTest
);
//按钮点击隐藏
connect(btn, &QPushButton::clicked, [this, btn](){
btn->hide();
});
grid->addWidget(btn, row, col); // 关键:指定行和列
}
}
grid->setColumnStretch(0, 6);
// 设置第2行不拉伸
grid->setRowStretch(2, 0);
ui->widgetTest->show();
2.2 保持布局稳定的关键技术
通过修改组件的尺寸策略,使其隐藏时保留占位空间:
// 正确保留空间的隐藏方法
void hideWidgetKeepSpace(QWidget *widget) {
widget->hide(); // 1. 先隐藏组件
QSizePolicy sp = widget->sizePolicy();
sp.setRetainSizeWhenHidden(true); // 2. 关键:设置保留空间
widget->setSizePolicy(sp); // 3. 应用新策略
}
2.3 网格布局中的具体实践
// 隐藏第2行第1列的按钮但不影响布局
QPushButton *btn = qobject_cast<QPushButton*>(
grid->itemAtPosition(1,0)->widget()
);
hideWidgetKeepSpace(btn);
此时布局保持不变:
三、高级空间分配技巧
3.1 拉伸因子(Stretch Factor)动态控制
// 设置第0列的拉伸因子为2(其他列默认为1)
grid->setColumnStretch(0, 2);
// 设置第2行不拉伸
grid->setRowStretch(2, 0);
拉伸因子决定空间分配优先级:当窗口扩大时,因子值更大的行列获得更多额外空间.
3.2 使用Spacer填充空白区域
当需要让某个组件占据空白区域时:
grid->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding),2, 2 );
四、案例:动态配置界面
4.1 动态隐藏,但保留空间
构建一个设备控制面板:包含启动/停止按钮、参数配置区和实时数据图表。要求根据用户权限动态隐藏高级参数区。
// 初始化布局
QGridLayout *mainGrid = new QGridLayout(this);
mainGrid->addWidget(titleLabel, 0, 0, 1, 3); // 跨3列
// 添加权限敏感区域
QGroupBox *advancedSettings = new QGroupBox("高级参数");
mainGrid->addWidget(advancedSettings, 2, 0, 1, 3);
// 权限变更时处理隐藏
void onPermissionChanged(bool isAdmin) {
if(!isAdmin) {
QSizePolicy sp = advancedSettings->sizePolicy();
sp.setRetainSizeWhenHidden(true);
advancedSettings->setSizePolicy(sp);
advancedSettings->hide(); // 隐藏但保留空间
} else {
advancedSettings->show();
}
}
4.2 动态隐藏,不保留空间
构建一个窗体,里边包含8个按钮,这8个按钮在窗体设计器上已经实现栅格布局,当因为某种需要隐藏其中部分按钮时,实现其他按钮能填补空缺,并且重新布局。
void MainWindow::setLayout()
{
// 获取栅格布局
QGridLayout* gridLayout = qobject_cast<QGridLayout*>(ui->scrollAreaWidgetContents->layout());
QLayoutItem *item;
while ((item = gridLayout->takeAt(0)) != nullptr) {
delete item;
}
int nCol = 0;
int nRow = 0;
for(int n=0; n<8; n++)
{
QString strName = QString("bt") + QString::number(n+1);
QPushButton *cbFind = this->findChild<QPushButton*>(strName);
if(cbFind != nullptr)
{
if(!cbFind->isHidden())
{
gridLayout->addWidget(cbFind, nCol, nRow);
if(nRow >= 1)
{
nCol++;
nRow = 0;
}
else {
nRow++;
}
}
else {
//
}
}
}
ui->scrollAreaWidgetContents->setLayout(gridLayout);
update();
}
当所有按钮都显示的时候,正常栅格布局,当部分按钮隐藏时,其他按钮填补空缺,重新调用布局刷新如下
以上就是栅格布局在一些特殊场景下的应用