ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Qt 界面开发必会:四大 Layout 布局管理器与 Spacer 弹簧机制详解

Qt 界面开发必会:四大 Layout 布局管理器与 Spacer 弹簧机制详解 个人主页Cx330❄️个人专栏《C语言》《LeetCode刷题集》《数据结构-初阶》《C知识分享》《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔《Git深度解析》:版本管理实战全解 《Qt 极境架构》MySQL 核心技术与实战心向往之行必能Cx330的简介目录前言一、容器类控件Group Box Tab Widget控件分组与切换1.1 Group Box控件分组框1.2 Tab Widget标签页切换控件二、布局管理器界面自适应的核心垂直 / 水平 / 网格 / 表单布局2.1 QVBoxLayout垂直布局2.2 QHBoxLayout水平布局2.3 QGridLayout网格布局2.4 QFormLayout表单布局2.5 QSpacerItem空白控件三、 本章模块避坑指南覆盖所有收尾知识点四、 总结前言在桌面 GUI 开发中界面控件的排版与自适应缩放是极为核心的一环。如果在 Qt 中通过硬编码绝对坐标如setGeometry来放置控件当窗口尺寸改变或在不同分辨率的屏幕上运行时界面极易出现错位、遮挡或空白大面积留白等尴尬情况。为了解决这一问题Qt 提供了强大的Layout Manager布局管理器系统。本文结合课堂板书重点系统梳理 Qt 中的四大核心布局、弹簧机制Spacer以及 Qt 控件的面向对象扩展能力。一、容器类控件Group Box Tab Widget控件分组与切换容器类控件的核心作用是对界面上的控件进行分组管理让界面结构更清晰同时提供分组交互如标签页切换包含QGroupBox分组框和QTabWidget标签页控件两个核心组件。1.1 Group Box控件分组框QGroupBox是基础分组控件通过边框和标题将相关控件归类如 “用户信息”“订单信息” 分组支持 “勾选启用” 功能checkable 属性仅美化界面、优化结构不影响控件功能是界面模块化 的首选。核心属性与 APIsetTitle(const QString title)设置分组框标题setCheckable(bool flag)设置是否支持勾选勾选后分组内控件才可用setChecked(bool checked)设置默认勾选状态setFlat(bool flat)设置是否为扁平模式无边框仅显示标题。实战示例麦当劳点餐分组汉堡 小食 饮料分组将下拉框和微调框按 “汉堡”“小食”“饮料” 分组界面结构更清晰这里直接用ui的模式来实现1.2 Tab Widget标签页切换控件QTabWidget是多页面切换的核心控件通过标签页将不同功能模块的控件分离如 “基本信息”“高级设置” 标签页节省界面空间提升交互效率支持标签页新增、删除、移动是复杂界面的必备组件。核心属性与 API标签页管理addTab(QWidget* page, const QString label)新增标签页page 为标签页对应的控件容器removeTab(int index)删除指定下标从 0 开始的标签页currentIndex()获取当前选中的标签页下标setCurrentIndex(int index)切换到指定下标标签页核心属性setTabsCloseable(bool flag)设置标签页是否支持关闭显示关闭按钮setMovable(bool flag)设置标签页是否可拖动调整顺序核心信号currentChanged(int index)标签页切换时触发返回新标签页下标tabCloseRequested(int index)点击标签页关闭按钮时触发。实战示例标签页新增 / 删除 / 切换实现 “新建标签页”“删除当前标签页” 功能标签页切换时打印下标#include widget.h #include ui_widget.h #include QLabel #include QDebug Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); // 先在每个标签页中添加一个Label QLabel* label1 new QLabel(ui-tab); label1-setText(标签页1); label1-resize(100,50); QLabel* label2 new QLabel(ui-tab_2); label2-setText(标签页2); label2-resize(100,50); } Widget::~Widget() { delete ui; } void Widget::on_pushButton_clicked() { // 使用 addTab 方法来创建新的标签页 // 参数1 要指定一个 QWidget // 参数2 指定这个标签页的标题 text 标题, 此处标题就叫做 Tab 数字 int count ui-tabWidget-count(); // 获取到标签页的数量 QWidget* w new QWidget(); ui-tabWidget-addTab(w,QString(Tab ) QString::number(count 1)); // 添加一个 QLabel 显示内容 QLabel* label new QLabel(w); label-setText(QString(标签页 ) QString::number(count 1)); label-resize(100,50); // 设置新标签页被选中 ui-tabWidget-setCurrentIndex(count); } void Widget::on_pushButton_2_clicked() { // 先获取到当前选中的标签页的下标 int index ui-tabWidget-currentIndex(); // 删除标签页 ui-tabWidget-removeTab(index); } void Widget::on_tabWidget_currentChanged(int index) { qDebug()当前选中的标签页是:index; }二、布局管理器界面自适应的核心垂直 / 水平 / 网格 / 表单布局之前的控件布局依赖 “绝对定位”setGeometry/move存在 “窗口缩放时控件位置不变”“控件重叠” 等问题。Qt 的布局管理器可自动计算控件位置和尺寸实现界面自适应缩放支持 4 种核心布局QVBoxLayout垂直、QHBoxLayout水平、QGridLayout网格、QFormLayout表单且支持布局嵌套。布局管理器核心原则一个 Widget 只能设置一个顶层布局布局内可嵌套其他布局控件添加到布局后会自动填充布局空间无需手动设置位置和尺寸窗口缩放时布局会按规则调整控件大小如垂直布局控件上下排列高度自适应布局的边距margin和控件间距spacing可自定义优化界面美观度。2.1 QVBoxLayout垂直布局控件按垂直方向从上到下排列适用于 “单列控件” 场景如按钮垂直排列、表单垂直分布核心 API 与属性addWidget(QWidget* widget)添加控件到布局addLayout(QLayout* layout)嵌套其他布局setSpacing(int spacing)设置控件之间的垂直间距setContentsMargins(int left, int top, int right, int bottom)设置布局的内边距。实战示例垂直布局管理三个按钮按钮垂直排列窗口缩放时按钮宽度自适应高度按比例分配#include widget.h #include ui_widget.h #include QPushButton #include QVBoxLayout Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); // 创建三个按钮使用垂直布局管理器管理起来 QPushButton* button1 new QPushButton(按钮1); QPushButton* button2 new QPushButton(按钮2); QPushButton* button3 new QPushButton(按钮3); // 创建布局管理器 QVBoxLayout* layout new QVBoxLayout(); layout-addWidget(button1); layout-addWidget(button2); layout-addWidget(button3); // 自定义布局样式 layout-setSpacing(20); // 控件间距20px layout-setContentsMargins(30, 30, 30, 30); // 布局内边距30px // 把布局管理器添加到窗口中 this-setLayout(layout); } Widget::~Widget() { delete ui; }补充直接使用ui也是可以做到的有两种做法、2.2 QHBoxLayout水平布局控件按水平方向从左到右排列适用于 “单行控件” 场景如工具栏按钮、搜索框 按钮API 与垂直布局完全一致仅排列方向不同。实战示例1垂直布局管理三个按钮#include widget.h #include ui_widget.h #include QPushButton #include QHBoxLayout Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); QPushButton* btn1 new QPushButton(按钮1); QPushButton* btn2 new QPushButton(按钮2); QPushButton* btn3 new QPushButton(按钮3); QHBoxLayout* layout new QHBoxLayout(); layout-addWidget(btn1); layout-addWidget(btn2); layout-addWidget(btn3); this-setLayout(layout); } Widget::~Widget() { delete ui; }2.3 QGridLayout网格布局控件按M 行 N 列的网格排列支持控件跨行列适用于复杂界面如计算器键盘、数据表格表单核心 APIaddWidget(QWidget* widget, int row, int column, int rowSpan, int columnSpan)row/column控件所在的行 / 列从 0 开始rowSpan/columnSpan控件跨的行 / 列数默认 1 行 1 列setRowStretch(int row, int stretch)设置行的拉伸系数系数越大窗口缩放时占比越大setColumnStretch(int column, int stretch)设置列的拉伸系数。实战示例初步演示使用#include widget.h #include ui_widget.h #include QPushButton #include QGridLayout Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); QPushButton* btn1 new QPushButton(按钮1); QPushButton* btn2 new QPushButton(按钮2); QPushButton* btn3 new QPushButton(按钮3); QPushButton* btn4 new QPushButton(按钮4); QGridLayout* layout new QGridLayout(); // layout-addWidget(btn1, 0, 0); // layout-addWidget(btn2, 0, 1); // layout-addWidget(btn3, 1, 0); // layout-addWidget(btn4, 1, 1); // 这个写法就相当于水平布局了 // 此时大家的行数一样就可以不一定非得是0 // layout-addWidget(btn1, 0, 0); // layout-addWidget(btn2, 0, 1); // layout-addWidget(btn3, 0, 2); // layout-addWidget(btn4, 0, 3); // 这个写法就相当于是垂直布局了 // layout-addWidget(btn1, 0, 0); // layout-addWidget(btn2, 1, 0); // layout-addWidget(btn3, 2, 0); // layout-addWidget(btn4, 3, 0); // 这个写法是每个按钮独占一行和一列 // 即使这是成 100,100也不搞出很大的空白空间 // 此时设置的行数和列数, 只是用来决定控件之前的相对位置 layout-addWidget(btn1, 0, 0); layout-addWidget(btn2, 1, 1); layout-addWidget(btn3, 2, 2); layout-addWidget(btn4, 3, 3); // layout-addWidget(btn4, 100, 100); this-setLayout(layout); } Widget::~Widget() { delete ui; }实战示例2水平拉伸系数#include widget.h #include ui_widget.h #include QPushButton #include QGridLayout Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); // 创建6个按钮使用网格布局管理器按照2*3方式排列 QPushButton* button1 new QPushButton(按钮1); QPushButton* button2 new QPushButton(按钮2); QPushButton* button3 new QPushButton(按钮3); QPushButton* button4 new QPushButton(按钮4); QPushButton* button5 new QPushButton(按钮5); QPushButton* button6 new QPushButton(按钮6); // 创建网格布局管理器把这些控件添加进去 QGridLayout* layout new QGridLayout(); layout-addWidget(button1,0,0); layout-addWidget(button2,0,1); layout-addWidget(button3,0,2); layout-addWidget(button4,1,0); layout-addWidget(button5,1,1); layout-addWidget(button6,1,2); this-setLayout(layout); // 设置水平拉伸系数 // 012列比例大小为 1:1:2 layout-setColumnStretch(0,1); layout-setColumnStretch(1,1); layout-setColumnStretch(2,2); } Widget::~Widget() { delete ui; }实战示例3垂直拉伸系数(注意关键步骤)#include widget.h #include ui_widget.h #include QPushButton #include QGridLayout Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); // 创建6个按钮按照3行2列的方式进行排列 QPushButton* button1 new QPushButton(按钮1); QPushButton* button2 new QPushButton(按钮2); QPushButton* button3 new QPushButton(按钮3); QPushButton* button4 new QPushButton(按钮4); QPushButton* button5 new QPushButton(按钮5); QPushButton* button6 new QPushButton(按钮6); button1-setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); button2-setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); button3-setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); button4-setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); button5-setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); button6-setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); // 创建layout QGridLayout* layout new QGridLayout(); layout-addWidget(button1,0,0); layout-addWidget(button2,0,1); layout-addWidget(button3,1,0); layout-addWidget(button4,1,1); layout-addWidget(button5,2,0); layout-addWidget(button6,2,1); this-setLayout(layout); // 设置拉伸系数 layout-setRowStretch(0,1); layout-setRowStretch(1,1); layout-setRowStretch(2,2); } Widget::~Widget() { delete ui; }2.4 QFormLayout表单布局专门用于两列表单左侧标签 右侧输入控件适用于用户信息填写、参数配置等场景自动对齐标签和输入框界面整洁规范核心 APIaddRow(const QString labelText, QWidget* fieldWidget)添加一行标签文本 输入控件addRow(QWidget* labelWidget, QWidget* fieldWidget)添加一行标签控件 输入控件setLabelAlignment(Qt::Alignment alignment)设置标签的对齐方式。实战示例用户注册表单#include widget.h #include ui_widget.h #include QFormLayout #include QLabel #include QLineEdit #include QPushButton Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); // 设置成3行2列 QFormLayout* layout new QFormLayout(); this-setLayout(layout); // 创建3个label QLabel* label1 new QLabel(姓名); QLabel* label2 new QLabel(年龄); QLabel* label3 new QLabel(电话); // 创建3个输入框作为第2列 QLineEdit* edit1 new QLineEdit(); QLineEdit* edit2 new QLineEdit(); QLineEdit* edit3 new QLineEdit(); // 把上述控件添加到表单布局中 layout-addRow(label1,edit1); layout-addRow(label2,edit2); layout-addRow(label3,edit3); // 创建一个提交按钮 QPushButton* button new QPushButton(提交); layout-addRow(nullptr,button); } Widget::~Widget() { delete ui; }2.5 QSpacerItem空白控件用于在布局中添加空白区域实现控件的灵活排版如按钮居左 / 居右 / 两端对齐核心属性是 “宽度 / 高度” 和 “拉伸策略”支持水平和垂直两种空白。实战示例按钮之间加上空白部分#include widget.h #include ui_widget.h #include QHBoxLayout #include QPushButton Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); QHBoxLayout* layout new QHBoxLayout(); this-setLayout(layout); QPushButton* button1 new QPushButton(按钮1); QPushButton* button2 new QPushButton(按钮2); // 创建spacer使两个按钮之间存在空白 QSpacerItem* spacer new QSpacerItem(200,20); // 当前是把空白添加到两个按钮之间 layout-addWidget(button1); layout-addSpacerItem(spacer); layout-addWidget(button2); } Widget::~Widget() { delete ui; }三、 本章模块避坑指南覆盖所有收尾知识点Tree Widget节点删除必须区分顶层 / 子节点且手动释放内存否则会内存泄漏多列节点需先设置setColumnCount(int count)再给节点设置对应列文本。容器控件Group Box 的checkable属性为 true 时需通过isChecked()判断分组是否启用再控制子控件可用性Tab Widget 新增标签页时需创建独立的 QWidget 作为容器否则控件会重叠。布局管理器一个 Widget 只能设置一个顶层布局嵌套布局需通过addLayout添加到父布局网格布局的rowSpan/columnSpan参数是 “跨行列数”不是 “结束行列号”避免混淆拉伸系数setRowStretch/setColumnStretch仅对 “未固定尺寸的控件” 生效固定尺寸控件不会拉伸。Spacer 控件水平 Spacer 的QSizePolicy::Expanding作用于水平方向垂直 Spacer 作用于垂直方向需按需选择Spacer 的宽度 / 高度是 “最小空白尺寸”拉伸时会超过该值。四、 总结掌握 Qt 布局系统是编写高质量桌面软件的关键一步选择合适布局简单的单向排版选QHBoxLayout/QVBoxLayout网格式卡片选QGridLayout表单填写选QFormLayout。巧妙利用 Spacer结合QSpacerItem与QSizePolicy掌控界面的空白拉伸。面向对象封装将经常复用的 UI 结构封装成继承自QWidget的自定义子类打造高内聚、低耦合的优雅代码架构。
返回列表