QT_QT布局详解

文章目录

QT_QT布局详解

Qt 的布局管理器(Layout Manager)是 Qt GUI 开发中用于自动管理控件位置和尺寸的核心机制。它能实现窗口缩放自适应、统一间距管理、复杂界面嵌套等功能,避免手动计算坐标的繁琐工作。Qt 提供了多种内置布局管理器,均继承自抽象基类 QLayout。


核心布局类

QHBoxLayout(水平布局)

将控件按从左到右(或从右到左)的顺序水平排列:

cpp 复制代码
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(new QPushButton("One"));
layout->addWidget(new QPushButton("Two"));
layout->addWidget(new QPushButton("Three"));
widget->setLayout(layout);

实例

cpp 复制代码
#include "widget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 1. 创建表单布局(用于用户名和密码)
    QFormLayout *formLayout = new QFormLayout;

    QLineEdit *userEdit = new QLineEdit;
    QLineEdit *pwdEdit = new QLineEdit;
    pwdEdit->setEchoMode(QLineEdit::Password);  // 密码模式

    formLayout->addRow("用户名:", userEdit);
    formLayout->addRow("密  码:", pwdEdit);

    // 2. 创建水平布局(用于按钮)
    QHBoxLayout *btnLayout = new QHBoxLayout;

    QPushButton *loginBtn = new QPushButton("登 录");
    QPushButton *cancelBtn = new QPushButton("取 消");

    // 添加弹簧,让按钮靠右对齐
    btnLayout->addStretch(1);
    btnLayout->addWidget(loginBtn);
    btnLayout->addWidget(cancelBtn);

    // 3. 创建垂直布局(将表单和按钮组合在一起)
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addLayout(formLayout);   // 表单在上面
    mainLayout->addLayout(btnLayout);    // 按钮在下面

    // 4. 将主布局应用到当前窗口
    setLayout(mainLayout);

    // 5. 设置窗口标题
    setWindowTitle("用户登录");
}

Widget::~Widget()
{
}

QVBoxLayout(垂直布局)

将控件按从上到下的顺序垂直排列:

cpp 复制代码
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(new QLabel("Label"));
layout->addWidget(new QPushButton("Button"));
widget->setLayout(layout);

实例

cpp 复制代码
#include "widget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QFrame>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 假设在 Widget 的构造函数中
    QVBoxLayout *mainLayout = new QVBoxLayout;

    // 1. 标题(加大加粗)
    QLabel *titleLabel = new QLabel("⚙️ 系统设置");
    QFont titleFont = titleLabel->font();
    titleFont.setPointSize(16);
    titleFont.setBold(true);
    titleLabel->setFont(titleFont);
    mainLayout->addWidget(titleLabel);

    // 2. 分隔线
    QFrame *line = new QFrame;
    line->setFrameShape(QFrame::HLine);
    mainLayout->addWidget(line);

    // 3. 输入区域(嵌套水平布局)
    QHBoxLayout *inputLayout = new QHBoxLayout;
    inputLayout->addWidget(new QLabel("用户名:"));
    QLineEdit *nameEdit = new QLineEdit;
    nameEdit->setPlaceholderText("请输入用户名");
    inputLayout->addWidget(nameEdit);
    mainLayout->addLayout(inputLayout);

    // 4. 按钮区域(嵌套水平布局,靠右对齐)
    QHBoxLayout *btnLayout = new QHBoxLayout;
    btnLayout->addStretch(1);  // 弹簧把按钮推到右边
    btnLayout->addWidget(new QPushButton("确认"));
    btnLayout->addWidget(new QPushButton("取消"));
    mainLayout->addLayout(btnLayout);

    // 5. 状态提示(底部)
    QLabel *statusLabel = new QLabel("就绪");
    statusLabel->setStyleSheet("color: gray;");
    mainLayout->addWidget(statusLabel);

    // 应用布局
    setLayout(mainLayout);
    setWindowTitle("垂直布局进阶示例");
}

Widget::~Widget()
{
}

效果

QGridLayout(网格布局)

将控件放置在二维网格中,支持跨行跨列:

cpp 复制代码
QGridLayout *layout = new QGridLayout;
layout->addWidget(new QLabel("Label1"), 0, 0);
layout->addWidget(new QLabel("Label2"), 0, 1, 1, 2);  // 跨2列
layout->addWidget(new QPushButton("Button"), 1, 0, 1, 3);  // 跨3列
widget->setLayout(layout);

实例

cpp 复制代码
#include "widget.h"
#include <QLabel>          // 标签控件
#include <QLineEdit>       // 单行输入框
#include <QPushButton>     // 按钮控件
#include <QFormLayout>     // 表单布局
#include <QHBoxLayout>     // 水平布局
#include <QVBoxLayout>     // 垂直布局
#include <QGridLayout>     // 网格布局
#include <QLabel>          // 标签控件(重复包含,可省略)
#include <QFrame>          // 框架控件(用于分隔线等)

Widget::Widget(QWidget *parent)
    : QWidget(parent)      // 调用父类构造函数,parent为父窗口指针
{
    // ============================================================
    // 步骤1:创建主网格布局对象
    // ============================================================
    // QGridLayout 将窗口划分为行和列的网格,每个控件可以占据一个或多个单元格
    QGridLayout *layout = new QGridLayout;

    // ============================================================
    // 步骤2:创建并添加标题标签(第0行)
    // ============================================================
    // addWidget(控件, 起始行, 起始列, 行跨数, 列跨数)
    // 这里占用了第0行的全部4列,实现标题居中
    QLabel *titleLabel = new QLabel("计算器");

    // 获取当前字体,设置字号为14,加粗
    QFont titleFont = titleLabel->font();
    titleFont.setPointSize(14);      // 字体大小14点
    titleFont.setBold(true);         // 加粗
    titleLabel->setFont(titleFont);  // 应用新字体

    // 设置标签文字水平居中
    titleLabel->setAlignment(Qt::AlignCenter);

    // 将标题添加到布局:第0行,第0列开始,占1行,跨4列
    layout->addWidget(titleLabel, 0, 0, 1, 4);

    // ============================================================
    // 步骤3:创建并添加结果显示框(第1行)
    // ============================================================
    // 用于显示输入的数字和计算结果
    QLineEdit *resultEdit = new QLineEdit;

    // setReadOnly(true) 设置为只读模式,用户不能直接编辑
    // 只能通过按钮来输入内容
    resultEdit->setReadOnly(true);

    // 设置文字右对齐,符合计算器的显示习惯
    resultEdit->setAlignment(Qt::AlignRight);

    // 初始显示"0"
    resultEdit->setText("0");

    // setMinimumHeight(40) 设置最小高度为40像素
    // 让显示区域更明显,便于阅读
    resultEdit->setMinimumHeight(40);

    // 添加到布局:第1行,第0列开始,占1行,跨4列
    layout->addWidget(resultEdit, 1, 0, 1, 4);

    // ============================================================
    // 步骤4:第三行 - 功能按钮(第2行)
    // ============================================================
    // 每个按钮单独占一个单元格,不跨列
    // 第2行,第0列:清除按钮
    layout->addWidget(new QPushButton("C"), 2, 0);
    // 第2行,第1列:正负号切换按钮
    layout->addWidget(new QPushButton("±"), 2, 1);
    // 第2行,第2列:百分号按钮
    layout->addWidget(new QPushButton("%"), 2, 2);
    // 第2行,第3列:除法运算符
    layout->addWidget(new QPushButton("÷"), 2, 3);

    // ============================================================
    // 步骤5:第四行 - 数字按钮 7, 8, 9 和乘法(第3行)
    // ============================================================
    layout->addWidget(new QPushButton("7"), 3, 0);  // 第3行第0列
    layout->addWidget(new QPushButton("8"), 3, 1);  // 第3行第1列
    layout->addWidget(new QPushButton("9"), 3, 2);  // 第3行第2列
    layout->addWidget(new QPushButton("×"), 3, 3);  // 第3行第3列:乘法

    // ============================================================
    // 步骤6:第五行 - 数字按钮 4, 5, 6 和减法(第4行)
    // ============================================================
    layout->addWidget(new QPushButton("4"), 4, 0);  // 第4行第0列
    layout->addWidget(new QPushButton("5"), 4, 1);  // 第4行第1列
    layout->addWidget(new QPushButton("6"), 4, 2);  // 第4行第2列
    layout->addWidget(new QPushButton("-"), 4, 3);  // 第4行第3列:减法

    // ============================================================
    // 步骤7:第六行 - 数字按钮 1, 2, 3 和加法(第5行)
    // ============================================================
    layout->addWidget(new QPushButton("1"), 5, 0);  // 第5行第0列
    layout->addWidget(new QPushButton("2"), 5, 1);  // 第5行第1列
    layout->addWidget(new QPushButton("3"), 5, 2);  // 第5行第2列
    layout->addWidget(new QPushButton("+"), 5, 3);  // 第5行第3列:加法

    // ============================================================
    // 步骤8:第七行 - 0, 小数点, 等号(第6行)
    // ============================================================
    // addWidget(控件, 起始行, 起始列, 行跨数, 列跨数)
    // "0" 按钮占2列(第0列和第1列),让它更大更易点击
    layout->addWidget(new QPushButton("0"), 6, 0, 1, 2);

    // 小数点按钮:第6行,第2列,占1行1列(默认)
    layout->addWidget(new QPushButton("."), 6, 2);

    // 等号按钮:第6行,第3列,占1行1列(默认)
    layout->addWidget(new QPushButton("="), 6, 3);

    // ============================================================
    // 步骤9:设置布局的外观参数
    // ============================================================
    // setSpacing(5) 设置控件之间的间距为5像素
    // 让按钮之间有小间隙,视觉上更清晰
    layout->setSpacing(5);

    // setContentsMargins(左, 上, 右, 下)
    // 设置布局内容与窗口边缘的边距为10像素
    // 避免控件紧贴窗口边框
    layout->setContentsMargins(10, 10, 10, 10);

    // ============================================================
    // 步骤10:统一设置所有按钮的高度
    // ============================================================
    // layout->count() 返回布局中控件的总数量
    for (int i = 0; i < layout->count(); ++i) {
        // layout->itemAt(i) 获取第i个布局项
        // ->widget() 将布局项转换为QWidget指针
        QWidget *widget = layout->itemAt(i)->widget();

        // dynamic_cast<QPushButton*>(widget) 尝试将widget转换为QPushButton*
        // 如果转换成功(即widget确实是QPushButton),则条件为真
        // 这样只处理按钮,不处理QLabel和QLineEdit
        if (widget && dynamic_cast<QPushButton*>(widget)) {
            // setFixedHeight(50) 将按钮高度固定为50像素
            // 使所有按钮大小一致,界面更整齐
            widget->setFixedHeight(50);
        }
    }

    // ============================================================
    // 步骤11:将布局应用到窗口
    // ============================================================
    // setLayout() 将创建的布局设置为当前窗口的主布局
    // 窗口会按照布局规则自动排列所有子控件
    setLayout(layout);

    // ============================================================
    // 步骤12:设置窗口属性
    // ============================================================
    // 设置窗口标题栏显示的文字
    setWindowTitle("网格布局 - 计算器");

    // resize(宽度, 高度) 设置窗口初始大小
    // 300像素宽,400像素高
    resize(300, 400);
}

// ============================================================
// 析构函数
// ============================================================
// Qt的对象树机制会自动删除子控件,所以析构函数通常为空
// 不需要手动delete,Qt会帮我们管理内存
Widget::~Widget()
{
}

效果

QFormLayout(表单布局)

专为标签-输入框形式的表单设计,自动对齐:

cpp 复制代码
QFormLayout *layout = new QFormLayout;
layout->addRow(new QLabel("Name:"), new QLineEdit);
layout->addRow(new QLabel("Age:"), new QSpinBox);
widget->setLayout(layout);

示例

cpp 复制代码
#include "widget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QFrame>
#include <QSpinBox>          // 数字输入框
#include <QComboBox>         // 下拉选择框
#include <QDateEdit>         // 日期选择框
#include <QTextEdit>         // 多行文本输入框

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // ============================================================
    // 步骤1:创建表单布局
    // ============================================================
    // QFormLayout 以两列形式排列:左列是标签,右列是输入控件
    // 自动处理标签和输入框的对齐
    QFormLayout *formLayout = new QFormLayout;

    // ============================================================
    // 步骤2:添加各种类型的输入行
    // ============================================================

    // 2.1 单行文本输入(姓名)
    // addRow(标签文本, 输入控件)
    QLineEdit *nameEdit = new QLineEdit;
    nameEdit->setPlaceholderText("请输入姓名");  // 灰色提示文字
    formLayout->addRow("姓名:", nameEdit);

    // 2.2 数字输入(年龄)
    QSpinBox *ageSpin = new QSpinBox;
    ageSpin->setRange(1, 150);        // 设置范围 1-150
    ageSpin->setValue(18);            // 默认值18
    ageSpin->setSuffix(" 岁");        // 显示单位
    formLayout->addRow("年龄:", ageSpin);

    // 2.3 下拉选择(性别)
    QComboBox *genderCombo = new QComboBox;
    genderCombo->addItem("男");       // 添加选项
    genderCombo->addItem("女");
    genderCombo->addItem("保密");
    formLayout->addRow("性别:", genderCombo);

    // 2.4 日期选择(出生日期)
    QDateEdit *birthEdit = new QDateEdit;
    birthEdit->setDisplayFormat("yyyy-MM-dd");  // 日期显示格式
    birthEdit->setCalendarPopup(true);          // 允许弹出日历选择
    formLayout->addRow("出生日期:", birthEdit);

    // 2.5 下拉选择(学历)
    QComboBox *eduCombo = new QComboBox;
    eduCombo->addItem("博士");
    eduCombo->addItem("硕士");
    eduCombo->addItem("本科");
    eduCombo->addItem("专科");
    eduCombo->addItem("高中");
    eduCombo->addItem("初中及以下");
    formLayout->addRow("学历:", eduCombo);

    // 2.6 多行文本输入(个人简介)
    QTextEdit *introEdit = new QTextEdit;
    introEdit->setPlaceholderText("请输入个人简介...");
    introEdit->setMaximumHeight(80);   // 限制高度,避免占用太多空间
    formLayout->addRow("个人简介:", introEdit);

    // ============================================================
    // 步骤3:添加分割线(视觉分隔)
    // ============================================================
    QFrame *line = new QFrame;
    line->setFrameShape(QFrame::HLine);  // 水平分割线
    line->setFrameShadow(QFrame::Sunken);
    formLayout->addRow(line);            // 占一整行

    // ============================================================
    // 步骤4:添加按钮行(使用水平布局嵌套)
    // ============================================================
    // 创建水平布局来放置两个按钮
    QHBoxLayout *btnLayout = new QHBoxLayout;

    QPushButton *submitBtn = new QPushButton("提交");
    QPushButton *clearBtn = new QPushButton("清空");
    QPushButton *cancelBtn = new QPushButton("取消");

    // 添加弹簧,让按钮靠右对齐
    btnLayout->addStretch(1);
    btnLayout->addWidget(submitBtn);
    btnLayout->addWidget(clearBtn);
    btnLayout->addWidget(cancelBtn);

    // 将水平布局作为一行添加到表单(占两列)
    // addRow(布局) 可以让布局占满整行
    formLayout->addRow(btnLayout);

    // ============================================================
    // 步骤5:设置表单布局的外观参数
    // ============================================================
    // 设置标签和输入框之间的间距
    formLayout->setSpacing(10);

    // 设置表单的整体边距(左,上,右,下)
    formLayout->setContentsMargins(20, 20, 20, 20);

    // 设置标签的宽度策略(让标签右对齐)
    formLayout->setLabelAlignment(Qt::AlignRight);

    // 设置表单行之间的垂直间距
    formLayout->setVerticalSpacing(10);

    // ============================================================
    // 步骤6:应用布局到窗口
    // ============================================================
    setLayout(formLayout);

    // ============================================================
    // 步骤7:设置窗口属性
    // ============================================================
    setWindowTitle("个人信息登记表");
    resize(400, 450);  // 宽度400,高度450

    // ============================================================
    // 步骤8:连接信号与槽(按钮功能)
    // ============================================================
    // 提交按钮点击事件
    connect(submitBtn, &QPushButton::clicked, this, [=]() {
        // 收集所有输入数据
        QString name = nameEdit->text();
        int age = ageSpin->value();
        QString gender = genderCombo->currentText();
        QString birth = birthEdit->text();
        QString edu = eduCombo->currentText();
        QString intro = introEdit->toPlainText();

        // 简单验证
        if (name.isEmpty()) {
            // 可以弹出提示框,这里简单显示在标题栏
            setWindowTitle(" 请输入姓名!");
            return;
        }

        // 显示提交成功
        setWindowTitle(QString(" 提交成功!姓名:%1,年龄:%2")
                      .arg(name).arg(age));
    });

    // 清空按钮点击事件
    connect(clearBtn, &QPushButton::clicked, this, [=]() {
        nameEdit->clear();              // 清空姓名
        ageSpin->setValue(18);          // 年龄重置为18
        genderCombo->setCurrentIndex(0); // 性别选第一个
        birthEdit->setDate(QDate::currentDate()); // 日期设为今天
        eduCombo->setCurrentIndex(2);   // 学历选"本科"
        introEdit->clear();             // 清空简介
        setWindowTitle("个人信息登记表"); // 恢复标题
    });

    // 取消按钮点击事件
    connect(cancelBtn, &QPushButton::clicked, this, [=]() {
        close();  // 关闭窗口
    });
}

Widget::~Widget()
{
}

效果

QStackedLayout(堆叠布局)

多个控件/布局叠在一起,每次只显示一个,适合页面切换场景:

cpp 复制代码
QStackedLayout *stacked = new QStackedLayout;
stacked->addWidget(page1);
stacked->addWidget(page2);
stacked->setCurrentIndex(0);  // 切换到指定页面

示例

cpp 复制代码
#include "widget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QFrame>
#include <QStackedLayout>    // 堆叠布局
#include <QComboBox>         // 下拉选择框
#include <QSpinBox>          // 数字输入框
#include <QTextEdit>         // 多行文本
#include <QRadioButton>      // 单选按钮
#include <QButtonGroup>      // 按钮组
#include <QDateEdit> // 日期选择
#include <QCheckBox>         // 复选框

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // ============================================================
    // 步骤1:创建三个页面(每个页面是一个QWidget)
    // ============================================================
    // 页面1:欢迎页
    QWidget *page1 = new QWidget;
    // 页面2:设置页
    QWidget *page2 = new QWidget;
    // 页面3:完成页
    QWidget *page3 = new QWidget;

    // ============================================================
    // 步骤2:创建堆叠布局并添加页面
    // ============================================================
    // QStackedLayout 只显示一个页面,其他页面隐藏
    // 通过 setCurrentIndex() 切换显示
    QStackedLayout *stackedLayout = new QStackedLayout;
    stackedLayout->addWidget(page1);  // 索引0
    stackedLayout->addWidget(page2);  // 索引1
    stackedLayout->addWidget(page3);  // 索引2
    stackedLayout->setCurrentIndex(0); // 默认显示第1页(索引0)

    // ============================================================
    // 步骤3:创建导航按钮(上一页/下一页)
    // ============================================================
    QPushButton *prevBtn = new QPushButton("上一页");
    QPushButton *nextBtn = new QPushButton("下一页 ➡");
    QPushButton *finishBtn = new QPushButton("完成");

    // 默认禁用"上一页"(因为当前在第1页)
    prevBtn->setEnabled(false);
    // 默认隐藏"完成"按钮(最后才显示)
    finishBtn->setVisible(false);

    // ============================================================
    // 步骤4:创建底部导航栏的水平布局
    // ============================================================
    QHBoxLayout *navLayout = new QHBoxLayout;
    navLayout->addStretch(1);          // 左侧弹簧,把按钮推到右边
    navLayout->addWidget(prevBtn);
    navLayout->addWidget(nextBtn);
    navLayout->addWidget(finishBtn);

    // ============================================================
    // 步骤5:创建主布局(垂直布局,堆叠布局在上,导航栏在下)
    // ============================================================
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addLayout(stackedLayout, 1);  // 堆叠布局占主要空间(拉伸因子1)
    mainLayout->addLayout(navLayout);         // 导航栏在底部
    setLayout(mainLayout);

    // ============================================================
    // 步骤6:填充页面1 - 欢迎页
    // ============================================================
    QVBoxLayout *page1Layout = new QVBoxLayout(page1);

    // 欢迎标题
    QLabel *welcomeLabel = new QLabel("欢迎使用设置向导");
    QFont welcomeFont = welcomeLabel->font();
    welcomeFont.setPointSize(20);
    welcomeFont.setBold(true);
    welcomeLabel->setFont(welcomeFont);
    welcomeLabel->setAlignment(Qt::AlignCenter);

    // 欢迎描述
    QLabel *descLabel = new QLabel(
        "本向导将帮助您完成基本设置。\n\n"
        "点击「下一页」开始配置您的个人信息。"
    );
    descLabel->setAlignment(Qt::AlignCenter);
    descLabel->setWordWrap(true);  // 自动换行

    // 添加弹簧让内容垂直居中
    page1Layout->addStretch(1);
    page1Layout->addWidget(welcomeLabel);
    page1Layout->addWidget(descLabel);
    page1Layout->addStretch(1);

    // ============================================================
    // 步骤7:填充页面2 - 设置页(个人信息表单)
    // ============================================================
    QFormLayout *page2Layout = new QFormLayout(page2);
    page2Layout->setSpacing(15);
    page2Layout->setContentsMargins(30, 30, 30, 30);

    // 表单标题
    QLabel *formTitle = new QLabel("个人信息设置");
    QFont formFont = formTitle->font();
    formFont.setPointSize(14);
    formFont.setBold(true);
    formTitle->setFont(formFont);
    page2Layout->addRow(formTitle);

    // 添加分割线
    QFrame *line = new QFrame;
    line->setFrameShape(QFrame::HLine);
    page2Layout->addRow(line);

    // 姓名输入
    QLineEdit *nameEdit = new QLineEdit;
    nameEdit->setPlaceholderText("请输入您的姓名");
    page2Layout->addRow("姓名:", nameEdit);

    // 年龄输入
    QSpinBox *ageSpin = new QSpinBox;
    ageSpin->setRange(1, 150);
    ageSpin->setValue(25);
    ageSpin->setSuffix(" 岁");
    page2Layout->addRow("年龄:", ageSpin);

    // 性别选择
    QComboBox *genderCombo = new QComboBox;
    genderCombo->addItem("男");
    genderCombo->addItem("女");
    genderCombo->addItem("保密");
    page2Layout->addRow("性别:", genderCombo);

    // 兴趣爱好(多选,使用水平布局)
    QHBoxLayout *hobbyLayout = new QHBoxLayout;
    QCheckBox *hobby1 = new QCheckBox("阅读");
    QCheckBox *hobby2 = new QCheckBox("音乐");
    QCheckBox *hobby3 = new QCheckBox("运动");
    QCheckBox *hobby4 = new QCheckBox("旅行");
    hobbyLayout->addWidget(hobby1);
    hobbyLayout->addWidget(hobby2);
    hobbyLayout->addWidget(hobby3);
    hobbyLayout->addWidget(hobby4);
    hobbyLayout->addStretch(1);
    page2Layout->addRow("爱好:", hobbyLayout);

    // 个人简介
    QTextEdit *introEdit = new QTextEdit;
    introEdit->setPlaceholderText("请简单介绍一下自己...");
    introEdit->setMaximumHeight(80);
    page2Layout->addRow("简介:", introEdit);

    // ============================================================
    // 步骤8:填充页面3 - 完成页
    // ============================================================
    QVBoxLayout *page3Layout = new QVBoxLayout(page3);

    // 完成图标
    QLabel *doneLabel = new QLabel("设置完成!");
    QFont doneFont = doneLabel->font();
    doneFont.setPointSize(22);
    doneFont.setBold(true);
    doneLabel->setFont(doneFont);
    doneLabel->setAlignment(Qt::AlignCenter);

    // 完成描述
    QLabel *doneDescLabel = new QLabel(
        "您的设置已成功保存。\n\n"
        "点击「完成」按钮关闭向导。"
    );
    doneDescLabel->setAlignment(Qt::AlignCenter);
    doneDescLabel->setWordWrap(true);

    // 显示用户输入摘要
    QLabel *summaryLabel = new QLabel;
    summaryLabel->setAlignment(Qt::AlignCenter);
    summaryLabel->setStyleSheet("color: #666; background-color: #f5f5f5; padding: 10px;");
    summaryLabel->setWordWrap(true);

    page3Layout->addStretch(1);
    page3Layout->addWidget(doneLabel);
    page3Layout->addWidget(doneDescLabel);
    page3Layout->addWidget(summaryLabel);
    page3Layout->addStretch(1);

    // ============================================================
    // 步骤9:连接信号与槽 - 实现页面切换逻辑
    // ============================================================

    // 9.1 "下一页"按钮:切换到下一个页面
    connect(nextBtn, &QPushButton::clicked, this, [=]() {
        int currentIndex = stackedLayout->currentIndex();
        int totalPages = stackedLayout->count();

        // 如果当前不是最后一页,切换到下一页
        if (currentIndex < totalPages - 1) {
            stackedLayout->setCurrentIndex(currentIndex + 1);

            // 更新按钮状态
            prevBtn->setEnabled(true);

            // 如果到达最后一页
            if (currentIndex + 1 == totalPages - 1) {
                // 最后一页:隐藏"下一页",显示"完成"
                nextBtn->setVisible(false);
                finishBtn->setVisible(true);

                // 更新摘要信息(收集用户输入)
                QString name = nameEdit->text().isEmpty() ? "未填写" : nameEdit->text();
                QString age = QString::number(ageSpin->value());
                QString gender = genderCombo->currentText();

                // 获取选中的爱好
                QStringList hobbies;
                if (hobby1->isChecked()) hobbies << "阅读";
                if (hobby2->isChecked()) hobbies << "音乐";
                if (hobby3->isChecked()) hobbies << "运动";
                if (hobby4->isChecked()) hobbies << "旅行";
                QString hobbyStr = hobbies.isEmpty() ? "未选择" : hobbies.join("、");

                // 更新摘要标签
                summaryLabel->setText(
                    QString("📋 您的信息摘要:\n\n"
                            "姓名:%1\n"
                            "年龄:%2 岁\n"
                            "性别:%3\n"
                            "爱好:%4")
                    .arg(name).arg(age).arg(gender).arg(hobbyStr)
                );
            }
        }
    });

    // 9.2 "上一页"按钮:切换到上一个页面
    connect(prevBtn, &QPushButton::clicked, this, [=]() {
        int currentIndex = stackedLayout->currentIndex();

        if (currentIndex > 0) {
            stackedLayout->setCurrentIndex(currentIndex - 1);

            // 更新按钮状态
            if (currentIndex - 1 == 0) {
                prevBtn->setEnabled(false);  // 第一页禁用"上一页"
            }

            // 如果从最后一页返回,恢复"下一页"按钮
            if (currentIndex == stackedLayout->count() - 1) {
                nextBtn->setVisible(true);
                finishBtn->setVisible(false);
            }
        }
    });

    // 9.3 "完成"按钮:关闭窗口
    connect(finishBtn, &QPushButton::clicked, this, [=]() {
        // 可以在这里添加保存数据到文件的逻辑
        // 然后关闭窗口
        close();
    });

    // ============================================================
    // 步骤10:设置窗口属性
    // ============================================================
    setWindowTitle("QStackedLayout - 设置向导");
    resize(500, 450);
}

Widget::~Widget()
{
}

效果

总结

各布局核心特性对比

布局 排列方式 核心特性 适用场景
QHBoxLayout 水平一行 从左到右排列 工具栏、按钮组
QVBoxLayout 垂直一列 从上到下排列 侧边栏、主结构
QGridLayout 二维网格 支持跨行跨列 计算器、表格
QFormLayout 两列表单 标签+输入配对 登录、设置界面
QStackedLayout 堆叠 每次只显示一个 向导、标签页

通用方法与属性(所有布局共有)

添加元素

方法 说明
addWidget(QWidget*) 添加控件
addLayout(QLayout*) 添加子布局(嵌套)
insertWidget(int, QWidget*) 在指定位置插入控件
insertLayout(int, QLayout*) 在指定位置插入子布局
addStretch(int) 添加弹性空间(仅 QBoxLayout 子类)

移除元素

方法 说明
removeWidget(QWidget*) 移除控件(不删除对象)
takeAt(int) 取出并移除指定位置的布局项
clear() 清空所有布局项(不删除对象)

遍历与查找

方法 说明
count() 获取布局项总数
itemAt(int) 获取指定位置的布局项
indexOf(QWidget*) 获取控件的索引位置
parentWidget() 获取布局所属的父窗口

空间与间距

方法/属性 说明
setSpacing(int) 设置控件之间的间距
spacing() 获取当前间距
setContentsMargins(int, int, int, int) 设置边距(左,上,右,下)
contentsMargins() 获取边距信息
setContentsMargins(QMargins) QMargins 对象形式设置边距

大小策略

属性/方法 说明
setSizeConstraint(QLayout::SizeConstraint) 设置布局大小约束
setMenuBar(QMenuBar*) 为布局设置菜单栏

SizeConstraint 枚举值:

说明
QLayout::SetDefaultConstraint 默认,最小尺寸为首选尺寸
QLayout::SetFixedSize 窗口固定为布局首选大小(不可调整)
QLayout::SetMinimumSize 窗口最小尺寸为布局首选尺寸
QLayout::SetMaximumSize 窗口最大尺寸为布局首选尺寸
QLayout::SetMinAndMaxSize 最小和最大都设置为布局首选尺寸
QLayout::SetNoConstraint 无约束,可任意调整

特有属性

QGridLayout 特有方法

方法 说明
addWidget(QWidget*, int row, int col) 添加到指定单元格
addWidget(QWidget*, int row, int col, int rowSpan, int colSpan) 跨行跨列添加
addLayout(QLayout*, int row, int col) 添加子布局到指定位置
setRowStretch(int row, int stretch) 设置行的拉伸因子
setColumnStretch(int col, int stretch) 设置列的拉伸因子
rowCount() 获取行数
columnCount() 获取列数
cellRect(int row, int col) 获取单元格矩形区域

QFormLayout 特有方法

方法 说明
addRow(QWidget*) 添加一个占两列的控件
addRow(QLayout*) 添加一个占两列的子布局
addRow(const QString&, QWidget*) 添加标签+控件对
addRow(QLabel*, QWidget*) 添加标签+控件对(标签可自定义)
insertRow(int, ...) 在指定位置插入行
removeRow(int) 移除指定行
setLabelAlignment(Qt::Alignment) 设置标签对齐方式
labelAlignment() 获取标签对齐方式
setFormAlignment(Qt::Alignment) 设置表单整体对齐方式
setVerticalSpacing(int) 设置行间距
setHorizontalSpacing(int) 设置列间距
labelForField(QWidget*) 获取某个输入控件对应的标签
getLayoutPosition() 获取布局位置信息

QStackedLayout 特有方法

方法 说明
addWidget(QWidget*) 添加页面(返回索引)
insertWidget(int, QWidget*) 在指定位置插入页面
removeWidget(QWidget*) 移除指定页面
setCurrentIndex(int) 切换到指定索引的页面
setCurrentWidget(QWidget*) 切换到指定控件页面
currentIndex() 获取当前页面索引
currentWidget() 获取当前页面控件指针
count() 获取页面总数
setStackingMode(QStackedLayout::StackingMode) 设置堆叠模式

StackingMode 枚举值:

说明
QStackedLayout::StackOne 只显示当前页面(默认)
QStackedLayout::StackAll 所有页面都显示(用于动画效果)

Qt 对齐方式速查

枚举值 说明
Qt::AlignLeft 左对齐
Qt::AlignRight 右对齐
Qt::AlignHCenter 水平居中
Qt::AlignTop 顶部对齐
Qt::AlignBottom 底部对齐
Qt::AlignVCenter 垂直居中
Qt::AlignCenter 完全居中
Qt::AlignJustify 两端对齐
Qt::AlignAbsolute 绝对对齐

组合使用示例:

cpp 复制代码
Qt::AlignTop | Qt::AlignRight       // 右上角
Qt::AlignBottom | Qt::AlignHCenter  // 底部居中

end

相关推荐
ximen502_2 小时前
Python 语言知识总结
开发语言·python
m0_738120722 小时前
PHP代码审计基础——超全局变量(三)
开发语言·安全·网络安全·php
烟锁池塘柳02 小时前
【C/C++】解决C++控制台输出中文乱码问题
c语言·开发语言·c++
可乐ea3 小时前
【Redis八股|第8篇】Redis 分布式锁原理与 Redisson 使用
数据库·redis·分布式·面试题·redis八股
C+-C资深大佬3 小时前
Java 变量:从入门到精通
java·开发语言·python
辞旧 lekkk3 小时前
【Qt系统相关】鼠标事件
linux·开发语言·qt·学习·计算机外设·萌新
chouchuang3 小时前
day-027-面向对象-下
开发语言·python
誰能久伴不乏3 小时前
C++11 随机数生成——告别 rand()
开发语言·c++
海清河晏1113 小时前
数据结构 | 二叉平衡搜索树
开发语言·数据结构·visual studio