📚 博主的专栏
🐧 Linux | 🖥️ C++ | 📊 数据结构| 💡C++ 算法 | 🅒 C 语言 | 🌐 计算机网络 |🗃️ mysql
**本文摘要:**本文介绍了Qt框架中常用控件与布局管理器的核心功能与应用方法。首先阐述了Qt中的信号与槽机制,重点讲解了lambda表达式在槽函数中的使用技巧和变量捕获机制。随后详细说明了按钮类控件(QPushButton、QRadioButton、QCheckBox)的属性配置与事件处理,以及显示类控件(QLabel、QLCDNumber、QProgressBar)的数据展示方式。在输入类控件部分,涵盖了QLineEdit、QTextEdit、QComboBox等交互元素的使用场景和信号处理。对于多元素控件,重点介绍了QListWidget、QTableWidget和QTreeWidget的数据组织与操作方式。最后深入讲解了布局管理器(QVBoxLayout、QHBoxLayout、QGridLayout、QFormLayout)的原理与应用,包括Spacer的使用技巧和尺寸策略设置方法,为Qt界面开发提供了全面的技术参考。
目录
[Window Frame 的影响](#Window Frame 的影响)
[Push Button-按钮](#Push Button-按钮)
[Radio Buttion-单选按钮](#Radio Buttion-单选按钮)
[Check Box-复选按钮](#Check Box-复选按钮)
[LCD Number-显示数字](#LCD Number-显示数字)
C++ 编译速度慢。和#include头文件,是有直接关系的
[Calendar Widget-日历控件](#Calendar Widget-日历控件)
[Line Edit-单行输入框](#Line Edit-单行输入框)
[Text Edit-多行输入框](#Text Edit-多行输入框)
[Combo Box-下拉框(直观效果)、组合框](#Combo Box-下拉框(直观效果)、组合框)
[Spin Box-微调框带有按钮的输入框](#Spin Box-微调框带有按钮的输入框)
[Date Edit-日期微调框 & Time Edit-时间微调框-QDateTimeEdit 时间日期微调](#Date Edit-日期微调框 & Time Edit-时间微调框-QDateTimeEdit 时间日期微调)
[List Widget-列表组件编辑](#List Widget-列表组件编辑)
[Table Widget-表格控件](#Table Widget-表格控件)
[Tree Widget-树形控件](#Tree Widget-树形控件)
[Group Box-带有标题的分组框](#Group Box-带有标题的分组框)
[Tab Widget-带有标签页的控件](#Tab Widget-带有标签页的控件)
一、QT概述
qt中的connect与linux计算机网络当中的connect不同,就如同,数据结构中的堆栈、与操作系统中的堆栈不同一般:
小总结1:
二、信号与槽
按钮的创造方式:代码与图形化
坐标系
使用lambda表达式的变量捕获
cppconnect(button, &QPushButton::clicked, this, [](){ qDebug() << "lambda 被执行了"; // button->move(); 找不到定义,这是因为lambda,本质是一个回调函数,这个函数,无法直接获取到上层作用域的变量 });
lambda表达式:找不到定义,这是因为lambda,本质是一个回调函数,这个函数,无法直接获取到上层作用域的变量,为了解决上述问题,引入变量捕获,获取到外层作用域中的变量
cppconnect(button, &QPushButton::clicked, this, [button](){ qDebug() << "lambda 被执行了"; // button->move(); 找不到定义,这是因为lambda,本质是一个回调函数,这个函数,无法直接获取到上层作用域的变量 button->move(300, 300); });
捕获多个变量:
cppconnect(button, &QPushButton::clicked, this, [button, this](){ qDebug() << "lambda 被执行了"; // button->move(); 找不到定义,这是因为lambda,本质是一个回调函数,这个函数,无法直接获取到上层作用域的变量 button->move(300, 300); this->move(100, 100); });
如果当前lambda里边想使用更多的外层变量咋办?
捕获方式写成[=],该写法的含义就是把上层作用域中的所有变量名都给捕获
一般我们对应的槽函数比较简单,而且是一次性使用的,就经常写做这种lambda的形式。
不能在lambda中捕获已经释放掉的对象,因此,关于对象生命周期的管理,很重要!!!
注意:
小总结2:
注意低耦合,高内聚
三、常用控件
enabled-控件可用状态
|-------------|-----------------------------------|
| API | 说明 |
| isEnabled() | 获取到控件的可⽤状态. |
| setEnabled | 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤. |"禁用"状态表示控件无法接收任何用户输入事件,同时其外观通常会呈现为灰色显示。需要注意的是: • 当某个widget被禁用时,其包含的所有子元素也会自动继承禁用状态。
geometry-几何
以左上角为点,进行target大小形状改变:
cppvoid MyWidget::on_pushButton_up_clicked() { //获取到target本身的geometry QRect rect = ui->pushButton_target->geometry(); qDebug() << rect; rect.setY(rect.y() - 5);//向上移动 ui->pushButton_target->setGeometry(rect); } void MyWidget::on_pushButton_left_clicked() { QRect rect = ui->pushButton_target->geometry(); qDebug() << rect; rect.setX(rect.x() - 5);//向左移动 ui->pushButton_target->setGeometry(rect); } void MyWidget::on_pushButton_right_clicked() { QRect rect = ui->pushButton_target->geometry(); qDebug() << rect; rect.setX(rect.x() + 5);//向右移动 ui->pushButton_target->setGeometry(rect); } void MyWidget::on_pushButton_down_clicked() { //获取到target本身的geometry QRect rect = ui->pushButton_target->geometry(); qDebug() << rect; rect.setY(rect.y() + 5);//向下移动 ui->pushButton_target->setGeometry(rect); }
现在平移target:按照类似的进行调整
cppvoid MyWidget::on_pushButton_up_clicked() { //获取到target本身的geometry QRect rect = ui->pushButton_target->geometry(); qDebug() << rect; // rect.setY(rect.y() - 5);//向上移动 // ui->pushButton_target->setGeometry(rect); ui->pushButton_target->setGeometry(rect.x(), rect.y() - 5, rect.width(), rect.height()); }
有趣的程序:
cpp#include "mywidget.h" #include "ui_mywidget.h" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::MyWidget) { ui->setupUi(this); //设置随机种子,使用时间戳作为随机种子 srand(time(0)); } MyWidget::~MyWidget() { delete ui; } void MyWidget::on_pushButton_agree_clicked() { ui->label->setText("吃什么?"); } void MyWidget::on_pushButton_reject_pressed() { ui->label->setText("必须一起吃饭!!!"); // 把这个按钮挪走,点不到 //可以通过生成随机数的方式,确定按钮新位置 //先获取到当前程序窗口的尺寸 int width = this->geometry().width(); int height = this->geometry().height(); //重新生成随机整数 int x = rand() % width; int y = rand() % height; //移动按钮位置,rand函数在使用之前,需要设置随机种子 ui->pushButton_reject->move(x, y); }
Window Frame 的影响
当 widget 作为窗口(带有标题栏、最小化、最大化、关闭按钮)时,计算尺寸和坐标存在两种计算方式:包含 window frame 和不包含 window frame。
计算方式说明:
- 包含 window frame 的方法:
x()
,y()
,frameGeometry()
,pos()
,move()
- 不包含 window frame 的方法:
geometry()
,width()
,height()
,rect()
,size()
注意:对于非窗口形式的 widget,这两种计算方式得到的结果是一致的。

示例:
当前代码是放到构造函数当中,此时这个Widget对象正在构造,还未被加入到window frame中,此时还看不到window frame的影响:
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //此处直接针对widget对象来使用geometry和frameGeometry,观察区别 QRect rect1 = this->geometry(); QRect rect2 = this->frameGeometry(); qDebug() << rect1; qDebug() << rect2; QPushButton* button = new QPushButton(this); button->setText("按钮"); button->move(100, 100); connect(button, &QPushButton::clicked, this, &Widget::handle); } Widget::~Widget() { delete ui; }
使用信号槽:利用一个按钮
cpp#include "widget.h" #include "ui_widget.h" #include <QDebug> #include <QPushButton> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); QPushButton* button = new QPushButton(this); button->setText("按钮"); button->move(100, 100); connect(button, &QPushButton::clicked, this, &Widget::handle); } Widget::~Widget() { delete ui; } void Widget::handle() { //此处直接针对widget对象来使用geometry和frameGeometry,观察区别 QRect rect1 = this->geometry(); QRect rect2 = this->frameGeometry(); qDebug() << rect1; qDebug() << rect2; }
windowTitle-控件窗口标题
|---------------------------------------|-------------|
| API | 说明 |
| windowTitle() | 获取到控件的窗⼝标题. |
| setWindowTitle(const QString& title) | 设置控件的窗⼝标题. |
windowIcon-窗口图标
注意:C++11中引入了raw string 解决上述问题,字符串中,不包含任意转义字符,写图片路径时,注意/
qrc机制
(缺点:无法导入太大的资源文件,比如几个GB的视频,qrc就无能为力)
使用方法:
1.在项目中创建qrc文件
2.把图片导入到qrc文件中
1)先创建一个前缀:Prefix(虚拟目录,不在电脑上真实存在,是qt抽象出的)
windowOpacity-控件的不透明度
代码:
cpp#include "widget.h" #include "ui_widget.h" #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Widget::on_pushButton_add_clicked() { float opacity = this->windowOpacity(); if(opacity >= 1.0){ //可以不写判断 return; } qDebug() << opacity; opacity+=0.1; this->setWindowOpacity(opacity); } void Widget::on_pushButton_sub_clicked() { float opacity = this->windowOpacity(); if(opacity <= 0.0){ return; } qDebug() << opacity; opacity-=0.1; this->setWindowOpacity(opacity); }
注意浮点数的使用!!!
《代码大全》进行了详细的讨论(防御性编程)
cursor-修改鼠标光标样式

转圈等待
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); QCursor cursor(Qt::WaitCursor); ui->pushButton->setCursor(cursor); }
qt也允许自定义设置光标,允许用自己的图片来设置图标
先准备一个图片,仍然通哟qrc来管理:
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); QPixmap pixmap(":/image.jpeg"); pixmap = pixmap.scaled(50, 50);//针对图片进行缩放 //构造光标对象 QCursor cursor(pixmap);//相当于,图片的左上角在点击 // QCursor cursor(pixmap, 10, 10); //以左上角为0,0远点,找到10,10这个位置作为点击位置 this->setCursor(cursor); }
font-和字体相关的一系列的内容
在图形化界面中:实时预览(Qt Designer)
toolTip-鼠标悬停提示
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //设置两按钮的toolTips ui->pushButton_yes->setToolTip("这是一个 yes 按钮"); ui->pushButton_yes->setToolTipDuration(3000);//显示3s ui->pushButton_no->setToolTip("这是一个 no 按钮"); ui->pushButton_no->setToolTipDuration(3000);//显示3s }
focusPolicy-获取焦点
设置控件获取焦点的策略,例如决定控件是否支持鼠标选中或通过Tab键切换选中。
所谓"焦点",指的是元素被选中后成为操作目标。后续的键盘操作都将作用于该焦点元素,这对输入框、单选框、复选框等控件尤为重要。
这个概念类似《魔兽争霸3》或《星际争霸2》中的操作逻辑:先选中单位,再执行命令。
代码示例:理解不同的 focusPolicy
- 在界面上创建四个单行输入框(Line Edit)
通过属性框中的focusPolicy,可以对每个lineEdit进行一个修改
styleSheet-设置属性样式
使用CSS自定义widget样式
🎨 CSS(层叠样式表)是一种前端网页技术,专门用于定义界面元素的视觉呈现效果。通过CSS,我们可以灵活控制元素的大小、位置、颜色、间距、字体、背景、边框等各种样式属性。
现代网页之所以能够呈现丰富多彩的视觉效果,很大程度上依赖于CSS的运用。虽然Qt主要用于GUI开发,但其界面设计理念与网页前端存在诸多共通之处。为此,Qt特别添加了对CSS的支持功能,使开发者能够像设计网页一样来美化Qt界面。
CSS提供了丰富的样式属性选项。Qt支持其中部分属性,称为QSS(Qt Style Sheet)。具体支持哪些属性,可查阅Qt文档中的"Qt Style Sheets Reference"章节。
编辑右侧的styleSheet属性,设置样式通过代码。设置样式,实现一个"夜间模式"功能
按钮类控件
**Push Button-**按钮
QPushButton 代表一个按钮控件,这是我们最常用的控件之一。它继承自抽象类 QAbstractButton,后者是所有按钮控件的基类。
在Qt Designer中同样可以查看此处的继承关系。
在
QA``bstractButton
中,与QPushButton
密切相关的属性|--------------------|-------------------------------------------------------------------------------------------------------|
| 属性 | 说明 |
| text | 按钮中的⽂本 |
| icon | 按钮中的图标 |
| iconSize | 按钮中图标的尺⼨ |
| shortCut | 按钮对应的快捷键 |
| autoRepeat | 按钮是否会重复触发. 当⿏标左键按住不放时, 如果设为 true, 则会持续产⽣⿏标点击事件; 如果设为 false,则必须释放⿏标,再次按下⿏标时才能产⽣点击事件. (相当于游戏⼿柄上的"连发"效果) |
| autoRepeatDelay | 重复触发的延时时间.按住按钮多久之后, 开始重复触发. |
| autoRepeatInterval | 重复触发的周期. |🌰 1. 作为 QWidget 的子类,QAbstractButton 自然继承了 QWidget 的所有属性。前文介绍的 QWidget 属性用法同样适用于 QAbstractButton,因此表格中仅列出 QAbstractButton 特有的属性。
- Qt 的 API 设计风格非常清晰。所有列出的属性都支持获取和设置操作。例如:通过 text() 方法获取按钮文本,使用 setText() 方法设置文本。
给按钮设置图标
给按钮设置快捷键
设置方向键的槽函数
设置快捷键:也能移动
也需要在Widget的构造函数中完成,程序一启动,快捷键就有效
还可以通过按键的枚举来设置快捷键
组合键
键盘的连发默认支持,开启鼠标点击的连发功能:autoRepeat(true)
Radio Buttion-单选按钮
QRadioButton 是单选按钮控件,允许用户在多个选项中选择一个。
作为 QAbstractButton 和 QWidget 的子类,前面介绍的属性和方法同样适用于 QRadioButton。
以下是 QAbstractButton 中与 QRadioButton 密切相关的属性:
|---------------|----------------------------------------------------------------------------------|
| 属性 | 说明 |
| checkable | 是否能选中 |
| checked | 是否已经被选中. checkable 是 checked 的前提条件. |
| autoExclusive | 是否排他.(取消前一个选中的按钮) 选中⼀个按钮之后是否会取消其他按钮的选中. 对于 QRadioButton 来说默认就是排他的(默认是只能选中一个) |示例:
使用setEnabled(false) / setDisabled(true)禁用选项
Radio Buttion 每个信号的使用
基于QRadioButton 实现一个简单的模拟点餐的功能
直接添加后,由于RadioButton默认是排他的,一旦界面上需要存在多组"单选按钮",希望组和组之间不要有影响
QButtonGroup类,可以针对单选按钮进行分组
Check Box-复选按钮
QCheckBox 表示复选框控件,支持多选功能。
它继承自 QAbstractButton 类,主要具有 checkable 和 checked 两个属性。此外,QCheckBox 还提供 tristate 属性用于实现"三态复选框"功能,不过这个功能较为冷门。
显示类控件:
Label-显示文本和图片
QLabel 可用于显示文本和图片,主要功能特性包括:
示例1:不同文本格式
示例2:显示图片
此时由于QLabel是固定大小的,所以当我们展开整个窗口时,图片大小不会与窗口同步变化
展开后:
cppui->label->setGeometry(0, 0, rect.width(), rect.height());
上面的代码是在构造函数里,进行这样的尺寸设置,这个设置相当于是"一次性的",一旦程序运行起来后,QLabel的尺寸就固定下来了,窗口发生变化,此时,QLabel是不会变化的
使用事件,来解决:
用户的操作会对应一些信号,Qt中,表示用户的操作,有两类概念,一个是信号,另一个是事件
当用户拖拽修改窗口大小的时候,会触发resize事件(resizeEvent),像resize这样的事件,是连续变化的,把窗口尺寸从A拖到B的这个过程中,会触发一系列的resizeEvent。
思路:
借助resizeEvent来完成上述的功能,可以让Widget窗口类,重写父类(QWidget 的 resizeEvent 虚函数),在鼠标拖动窗口尺寸的过程中,resizeEvent这个函数就会被反复调用执行,每次触发一个resizeEvent事件,都会调用一次对应的虚函数
由于此处进行了函数重写,调用父类虚函数就会实际调用到子类对应的函数(多态)
1.重写函数,观看event参数效果
实时改变label大小:
cppui->label->setGeometry(0, 0, event->size().width(), event->size().height());
示例:文本对齐 自动换行 缩进 边距
在QFrame中,可以设置,给Label添加边框
效果示例:
设置伙伴-setBuddy
Qt中,QLabel中写的文本,是可以指定"快捷键"的,此处快捷键的规则功能要比QPushButton弱很多,是在文本中使用 & 跟上一个字符来表示快捷键,比如 &A通过键盘上的ALT + A 触发这个快捷键,&B通过键盘上的ALT + B 触发这个快捷键,绑定了伙伴关系,就可以选中对应的单选框
LCD Number-显示数字
QLCDNumber 是一个专门用于显示数字的控件,能够呈现类似"老式计算器"的视觉效果。
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| intValue | 显示整数值 (int) 的 QLCDNumbe |
| value | QLCDNumber 显示的数字值为 double 类型。 其 intValue 值与显示值存在联动关系: * 当设置 value 为 1.5 时,intValue 会自动取整为 2 注意:设置数值的方法名为 display,而非 setValue 或 setIntValue。 |
| digitCount | 显示几位数 |
| mode | 数字显示模式: 1. QLCDNumber::Dec:十进制模式,显示标准十进制数字 2. QLCDNumber::Hex:十六进制模式,显示十六进制数字 3. QLCDNumber::Bin:二进制模式,显示二进制数字 4. QLCDNumber::Oct:八进制模式,显示八进制数字 注意:仅十进制模式支持显示小数点后的内容 |
| segmentStyle | 设置显示风格 1. QLCDNumber::Flat:平面显示风格,数字以扁平化方式呈现在背景表面。 2. QLCDNumber::Outline:轮廓显示风格,数字带有清晰的轮廓和阴影效果。 3. QLCDNumber::Filled:填充显示风格,数字使用实心填充,与背景形成鲜明对比。 |
| smallDecimalPoint | 设置较小的数值精 |
实现一个倒计时
此处关键要点是要实现,每秒钟-1,周期性的执行某个组件,"定时器" C++标准库中,没有提供定时器的实现,Boost里面提供了对应的功能,QT中也封装了对应的定时器,结合了信号和槽机制
QTimer-产生timeout信号
效果示例:从10 9 8 7 依次变化到0
Sleep 是 Windows 的 api,需要包含"Windows.h"头文件才能使用
在C++11标准库中,就引入了 sleep操作:sleep_for
sleep_for-延时
这导致,10s 过后,窗口显示,并且已经为0
解决办法:
在构造函数中,另外创建一个线程,在新的线程中,执行上述循环+更新操作
线程操作本身是 操作系统 提供的api,Windows api 可以参阅MSDN windows的文档,标准库,就可以通过一些"条件编译"的方式 来兼容不同的系统
示例:当前进程终止,出现了异常
在Qt中,界面维护和更新由专门的线程(即主线程,也就是main函数所在的线程)负责处理。由于GUI内部包含众多隐藏状态,为了确保修改界面时的线程安全性,Qt禁止其他线程直接修改界面元素。
而我们这里的代码:就是在其他线程修改界面元素
cpp
ui->lcdNumber->display(value);
因此Qt为了确保线程安全,直接要求所有的对界面的修改操作,必须在主线程中完成,对于Qt的槽函数来说,默认情况下,槽函数都是由主线程调用的,在槽函数中修改界面是没有任何问题的
✍ 这种约定主要是因为 GUI 中的状态往往牵一发而动全身,修改一处就需要同步调整其他内容。例如调整某个元素的尺寸,就可能影响内部文本位置或其他元素的布局。这一连串的修改必须按照特定顺序执行。由于多线程的执行顺序无法保证,Qt 从根本上禁止了其他线程修改 GUI 状态,从而避免由此引发的一系列问题。
ProgressBar-进度条
使用
QProgressBar
来显示进度条。注意:不要将
ProgressBar
拼写为ProcessBar
!在QtDesigner中添加进度条
进度条的基本使用:
注意:
C++ 编译速度慢。和#include头文件,是有直接关系的
由于include关系错综复杂,因此尽可能减少include头文件个数,就可以有效减少编译时间,Qt中使用class前置声明的方式,来减少头文件 的包含,通过前置声明的方式,Qt中的头文件,每个头文件包含其他头文件数量都能得到一定的降低
但是在实际开发中,还是该包含就包含。与其通过特殊技巧来缩短编译时间、不如引入更好的硬件资源。来更搞笑的编译,一些互联网大厂,都有专门的"编译集群"(分布式编译)
因此在C++ 20标准开始,就引入了"模块"module来替代#include
将绿色进度条改为粉红色-使用stylesheet
使用选择器的方式:
qt的bug: 这里需要自己设置回去,就和我图中一样了
进度条具体的进度如何设置,一般都是根据实际的任务类型来灵活设置的
例如:要读取一个很大的文件,就可以先获取到文件的总大小,每读取一部分数据(计算出读了多少数据),更新一次进度条 的数值。设置进度条的过程,往往需要搭配定时器
Calendar Widget-日历控件
QCalendarWidget 表示一个日历控件

|------------------------|-----------------------|
| 属性 | 说明 |
| selectDate | 当前选中的⽇期 |
| minimumDate | 最⼩⽇期 |
| maximumDate | 最⼤⽇期 |
| firstDayOfWeek | 每周的第⼀天(也就是⽇历的第⼀列)是周⼏. |
| gridVisible | 是否显⽰表格的边框 |
| selectionMode | 是否允许选择⽇期 |
| navigationBarVisible | ⽇历上⽅标题是否显⽰ |
| horizontalHeaderFormat | ⽇历上⽅标题显⽰的⽇期格式 |
| verticalHeaderFormat | ⽇历第⼀列显⽰的内容格式 |
| dateEditEnabled | 是否允许⽇期被编辑 |
重要信号

使用示例:

输入类控件
Line Edit-单行输入框
QLineEdit 用于实现单行文本输入框,支持输入文本内容但不允许换行。
核心信号:
示例:如图:
如图:
注意:
如图:通过提交,我们获取填入的内容(在实际开发中,提交 一般是客户端提交给服务器)
代码示例:使用正则表达式验证输入框数据
要求:在输入框中输入一个合法的电话号码(1开头,11位,全为数字)。验证不通过时,确定按钮将保持禁用状态。
关于正则表达式
正则表达式是一种利用特殊字符描述字符串特征的匹配机制,在计算机领域应用广泛。它能够高效完成字符串匹配任务,但语法较为复杂,通常使用时查阅文档即可,无需刻意记忆。
在线正则表达式工具:https://regextester.buyaocha.com/
**示例:**初始状态是禁用状态,此处的规则是,输入框要检查输入的内容是否是合法的手机号码,如果是,则按钮设置为可用状态,如果不是则按钮设为禁用状态
注意:
检验两次密码是否一致
警示符号,可以忽略,但是在有些公司中警示符号会无法编译通过
解决办法:
绕过编译器的检查,类型转换,对于我们代码的实际逻辑是没有任何影响的,可以骗过编译器
针对密码,可以切换"显示密码"状态

Text Edit-多行输入框
QTextEdit是一个多功能的多行输入框,既支持富文本编辑,也能作为 Markdown 编辑器使用。当内容超出编辑区域时,它会自动显示滚动条以便浏览。
|-------------------------|---------------------------------------------------------------------------------------------------|
| 属性 | 说明 |
| markdown | 输入框支持Markdown格式内容,并自动将其渲染为HTML显示 |
| html | 输⼊框内持有的内容.可以⽀持⼤部分html标签.包括img和table等. |
| placeHolderText | 输入框为空时的提示内容 |
| readOnly | 是否是只读的 |
| undoRedoEnable | 是否开启undo/redo功能. 按下ctrl+z触发 undo 按下ctrl+y触发redo |
| autoFormating | 开启⾃动格式化. |
| tabstopWidth | 按下缩进占多少空间 |
| overwriteMode | 是否开启覆盖写 模式,写的字符覆盖光标后的字符 |
| acceptRichText | 是否接收富⽂本内容 |
| verticalScrollBarPolicy | 垂直滚动条的显示策略: * **Qt::ScrollBarAsNeeded:**根据内容自动判断是否显示滚动条(默认选项) * **Qt::ScrollBarAlwaysOff:**始终隐藏滚动 |

示例:
QTextEdit 的几个信号
cppvoid Widget::on_textEdit_textChanged() { qDebug() << "textChanged:" << ui->textEdit->toPlainText(); } //表示当前光标选择的空间 void Widget::on_textEdit_selectionChanged() { QTextCursor cursor = ui->textEdit->textCursor(); qDebug() << "selectionChanged:" << cursor.selectedText(); } //光标位置发生改变触发信号,光标移动字符数 void Widget::on_textEdit_cursorPositionChanged() { QTextCursor cursor = ui->textEdit->textCursor(); qDebug() << "cursorPositionChanged:" << cursor.position(); } //一编辑内容,就触发,ctrl + z就撤回、undoAvailable为false void Widget::on_textEdit_undoAvailable(bool b) { qDebug() << "undoAvailable:" << b; } //ctrl + y void Widget::on_textEdit_redoAvailable(bool b) { qDebug() << "redoAvailable:" << b; } //选中 void Widget::on_textEdit_copyAvailable(bool b) { qDebug() << "copyAvailable:" << b; }
Combo Box-下拉框(直观效果)、组合框
QComboBox 表示下拉菜单控件。
activated ->下拉框展开、鼠标停留在某个选项上方、选项高亮、被激活的状态
示例:模拟麦当劳点餐
在实际开发中,下拉框中的内容不是在代码中写死的,而是通过文件、网络加载数据得到的
此处我们演示通过文件进行加载
文件中:config.txt
代码以及演示:
Spin Box-微调框带有按钮的输入框
使用 QSpinBox 或 QDoubleSpinBox 表示"微调框",这是一种带有增减按钮的数值输入控件。可用于输入整数(QSpinBox)或浮点数(QDoubleSpinBox),通过点击按钮即可调整数值大小。
由于 QSpinBox 和 QDoubleSpinBox 的使用方法基本一致,本文将重点介绍 QSpinBox 的用法。"Spin"在英文中本意为"旋转",在此处引申为"微调"。
实际上,许多术语的翻译不必拘泥于字面直译,更应追求"信达雅"的境界。
例如,地铁中的"Priority Seat"通常译为"爱心专座",而非直译为"优先座位"。
示例:通过下拉框,选择每个食物种类,再通过微调框,选择每个食物的数量
针对QSpinBox设置数值范围:
Date Edit-日期微调框 & Time Edit-时间微调框-QDateTimeEdit
时间日期微调
使用 QDateEdit 作为日期微调框。
使用 QTimeEdit 作为时间选择器
使用
QDateTimeEdit
作为日期时间的微调控件。这些控件的使用方法非常相似,下面以 QDateTimeEdit 为例进行详细说明。
|-----------------|----------------------------------------------------------------------------------------------------------------------------|
| 属性 | 说明 |
| dateTime | 时间⽇期的值.形如 2000/1/1 0:00:00 |
| date | 单纯⽇期的值.形如 2001/1/1 |
| time | 单纯时间的值.形如 0:00:00 |
| displayFormat | 日期时间格式说明: 格式示例:yyyy/M/d H:mm 各符号含义: y:年份 M:月份 d:日期 H:小时(24小时制) m:分钟 s:秒 注意事项: 不同编程语言/库的日期格式符号可能存在差异 使用时请查阅具体文档,不建议死记硬背 |
| minimumDateTime | 最小日期时间 |
| maximumDateTime | 最大日期时间 |
| timeSpec | • Qt::LocalTime:显示本地时间 • Qt::UTC:显示协调世界时(UTC时间) • Qt::OffsetFromUTC:显示与UTC时间的时差 |

时间计算器:计算两个时间中间的间隔是多少天、多少小时

有问题:需解决


解决办法:使用int的向下取整

Dial-旋钮
使用 QDial 控件表示旋钮。
某些程序只需通过鼠标拖动旋钮旋转,就能完成相关设置。
|----------------|----------------------------------------------|
| 属性 | 说明 |
| value | 持有的数值. |
| minimum | 最⼩值 |
| maximum | 最⼤值 |
| singleStep | 按下⽅向键的时候改变的步⻓. |
| pageStep | 按下pageUp/pageDown的时候改变的步⻓. |
| sliderPosition | 界⾯上旋钮显⽰的初始位置 |
| tracking | 外观是否会跟踪数值变化. 默认值为true.⼀般不需要修改. |
| wrapping | 是否允许循环调整. 即数值如果超过最⼤值,是否允许回到最⼩值. (调整过程能否"套圈") |
| notchesVisible | 是否显⽰刻度线 |
| notchTarget | 刻度线之间的相对位置. 数字越⼤,刻度线越稀疏. |编写代码,通过旋钮控制窗口不透明度(opacity)
Slider-滑动条
使用 QSlider 控件实现滑动条功能
QSlider 和 QDial 都继承自 QAbstractSlider,因此它们的用法基本一致。
在窗口上放两个滑动条、一个是水平、一个垂直
滑动这两个滑动条,就能调整窗口的大小、高度和宽度

快捷键的设置!!
使用快捷键:QShortCut类、需要用到两个快捷键、-进行减少、+/= 进行增加
多元素控件



xxWidget 使用比较方便、功能比较有限
xxView使用起来更加麻烦一些、但是可以根据情况自由diy,实现更复杂的功能
List Widget-列表组件

使用 QListWidget 可以显示一个纵向排列的列表,例如:
核心方法
|----------------------------------------------------------------------------|
||
增加删除以及感知选中的变化
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //往这里添加一些元素-字符串的方式进行添加 // ui->listWidget->addItem("c++"); // ui->listWidget->addItem("java"); // ui->listWidget->addItem("c#"); //往这里添加一些元素-创建对象的方式进行添加,在QListWidgetItem // 中可以设置字体属性、设置图标、设置文字大小、设置是否被选中等状态 ui->listWidget->addItem(new QListWidgetItem("c++")); ui->listWidget->addItem(new QListWidgetItem("java")); ui->listWidget->addItem(new QListWidgetItem("c#")); } Widget::~Widget() { delete ui; } void Widget::on_pushButton_insert_clicked() { //添加新元素 // 1、先获取到输入框中的内容 const QString& text = ui->lineEdit->text(); // 2、添加到QListWidget中 ui->listWidget->addItem(text); } void Widget::on_pushButton_delete_2_clicked() { //1、先获取到被选中的元素 int row = ui->listWidget->currentRow(); if(row < 0){ return; } ui->listWidget->takeItem(row); } void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) { //通过这个槽函数来感知到变化 if(current){ qDebug() << "当前选中的元素" << current->text(); } if(previous){ qDebug() << "上次选中的元素" << previous->text(); } }
Table Widget-表格控件
使用 QTableWidget 控件来显示表格数据。每个表格由多行组成,每行又包含若干列。表格中的每个单元格都是一个 QTableWidgetItem 对象。
准备好
编码:其实编码较为简单,只是看起来多
cpp#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this);\ // 初始化 // 1、创建3行 ui->tableWidget->insertRow(0); ui->tableWidget->insertRow(1); ui->tableWidget->insertRow(2); //2、创建3列 ui->tableWidget->insertColumn(0); ui->tableWidget->insertColumn(1); ui->tableWidget->insertColumn(2); // 3、给3个列设置列名(设置水平方向的表头 ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("学号")); ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("姓名")); ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("年龄")); // 4、给表格中添加数据 ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001")); ui->tableWidget->setItem(0, 1, new QTableWidgetItem("粥小欣")); ui->tableWidget->setItem(0, 2, new QTableWidgetItem("20")); ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002")); ui->tableWidget->setItem(1, 1, new QTableWidgetItem("粥小芋")); ui->tableWidget->setItem(1, 2, new QTableWidgetItem("21")); ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003")); ui->tableWidget->setItem(2, 1, new QTableWidgetItem("粥噗噗")); ui->tableWidget->setItem(2, 2, new QTableWidgetItem("22")); } Widget::~Widget() { delete ui; } void Widget::on_pushButton_insertRow_clicked() { //需要知道当前一共有多少行 int rowCount = ui->tableWidget->rowCount(); // 再在最后一行后新增一行 ui->tableWidget->insertRow(rowCount); } void Widget::on_pushButton_DeleteRow_clicked() { //获取选中行 int currentRow = ui->tableWidget->currentRow(); //删除这一行 ui->tableWidget->removeRow(currentRow); } void Widget::on_pushButton_InsertColumn_clicked() { //获取一共多少列 int columnCount = ui->tableWidget->columnCount(); // 在对应位置新增这一列 ui->tableWidget->insertColumn(columnCount); // 设置列名(从输入框获取) const QString& text = ui->lineEdit->text(); ui->tableWidget->setHorizontalHeaderItem(columnCount, new QTableWidgetItem(text)); } void Widget::on_pushButton_DeleteColumn_clicked() { int currentColumn = ui->tableWidget->currentColumn(); ui->tableWidget->removeColumn(currentColumn); }
增删行、列,列添加列名再增加
Tree Widget-树形控件
使用 QTreeWidget 可以创建一个树形控件,其中的每个元素都是一个 QTreeWidgetItem。每个 QTreeWidgetItem 可以包含多列数据,每列可以显示文本或图标。
通过为 QTreeWidget 设置多个顶层节点,并在这些顶层节点下添加子节点,就能构建出完整的树形结构。
cpp#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //设置根节点名字 ui->treeWidget->setHeaderLabel("动物种类"); //新增顶层节点 QTreeWidgetItem* item1 = new QTreeWidgetItem(); item1->setText(0, "猫"); //添加到顶层节点中 ui->treeWidget->addTopLevelItem(item1); //新增顶层节点 QTreeWidgetItem* item2 = new QTreeWidgetItem(); item2->setText(0, "狗"); //添加到顶层节点中 ui->treeWidget->addTopLevelItem(item2); //新增顶层节点 QTreeWidgetItem* item3 = new QTreeWidgetItem(); item3->setText(0, "鸟"); //添加到顶层节点中 ui->treeWidget->addTopLevelItem(item3); //添加子节点: QTreeWidgetItem* item4 = new QTreeWidgetItem(); item4->setText(0, "中华田园猫"); item1->addChild(item4); QTreeWidgetItem* item5 = new QTreeWidgetItem(); item5->setText(0, "暹罗猫"); item1->addChild(item5); QTreeWidgetItem* item6 = new QTreeWidgetItem(); item6->setText(0, "中华田园犬"); item2->addChild(item6); } Widget::~Widget() { delete ui; } //添加到顶层节点中 void Widget::on_pushButton_insertTopLevelItem_clicked() { //先获取到输入框的内容 const QString& text = ui->lineEdit->text(); //构造一个QTreeWidgetItem QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0, text); // 添加到顶层节点中 ui->treeWidget->addTopLevelItem(item); } void Widget::on_pushButton_insertItem_clicked() { QTreeWidgetItem* currentItem = ui->treeWidget->currentItem(); if(currentItem == nullptr){ return ; } //先获取到输入框的内容 const QString& text = ui->lineEdit->text(); //构造一个QTreeWidgetItem QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0, text); //添加到选中节点中 currentItem->addChild(item); } void Widget::on_pushButton_deleteItem_clicked() { QTreeWidgetItem* currentItem = ui->treeWidget->currentItem(); if(currentItem == nullptr){ return ; } //需要获取到父元素,通过父元素来删除 QTreeWidgetItem* parentItem = currentItem->parent(); if(parentItem == nullptr){ //说明是顶层元素 // 需要获取到是第几个顶层元素及其下标 int index = ui->treeWidget->indexOfTopLevelItem(currentItem); ui->treeWidget->takeTopLevelItem(index); }else{ //普通元素 parentItem->removeChild(currentItem); } }
容器类控件
Group Box-带有标题的分组框
使用 QGroupBox 可以创建一个带标题的分组框,方便将相关控件组织在一起,使界面更加美观整洁。
需要注意的是,QGroupBox 与 QButtonGroup 功能不同(后者在介绍 QRadioButton 时已提及)。

只是为了让界面看起来更好看、当一个界面比较复杂的时候,包含了很多控件的时候,分组框就可以把具有关联的控件,组织到一起

麦当劳点餐
示例:注意现在的父子类关系


Tab Widget-带有标签页的控件
使用 QTabWidget 实现一个带标签页的控件,可以向其中添加多个 widget,通过切换标签页来显示不同内容。
需要实现:
代码:
cpp#include "widget.h" #include "ui_widget.h" #include <QLabel> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //现在每个标签页中,添加一个label QLabel* label1 = new QLabel(ui->tab_1); 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; } //想要创建标签页,需要使用到addTab方法,参数1指定QWidget、参数2要指定标签页的text(标题 void Widget::on_pushButton_clicked() { // 此处标题就叫做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); }
还能获取到当前选中页的下标
cppvoid Widget::on_tabWidget_currentChanged(int index) { qDebug() << "当前选中的标签页是:" << index; }
布局管理器-尺寸和位置自动计算、geometry失效
在Qt界面设计中,之前创建的控件都采用"绝对定位"方式布局。这意味着每个控件的位置都需要手动计算坐标,最终通过setGeometry或move方法来设置。
这种设定方式确实不够便捷。特别是在界面内容较多的情况下,难以精确计算位置。况且窗口大小通常可以自由调整,采用绝对定位的方式无法实现自适应布局。
🦄 为此,Qt引入了"布局管理器"(Layout)机制来解决这些问题。
值得一提的是,布局管理器并非Qt独有,其他GUI开发框架如Android、前端等也都采用了类似的解决方案。
垂直布局
使用 QVBoxLayout 实现垂直排列的布局管理器。其中 V 代表 vertical(垂直)的缩写。


通过 Qt Designer 创建的布局管理器,实际上是先创建了一个 widget 并设置了 geometry 属性,再将这个 layout 应用到该 widget 中。
需要注意的是,一个 widget 只能包含一个 layout。通过查看 ui 文件的原始 xml 结构,可以清楚地观察到这一点。
ui的这种设置方式下,layout 不会作为窗口 widget 的布局管理器,因此不会随窗口大小变化而自动调整。


把选中的给套上布局方式

水平布局

同垂直布局
布局管理器之间能进行嵌套
实现:
网格布局
Qt提供了QGridLayout来实现网格布局效果,能够创建M×N的网格结构。
核心特性
与QVBoxLayout和QHBoxLayout类似,但在设置spacing时需要分别指定水平和垂直方向的间距。示例:
示例:
代码:
cpp#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); // 设置水平拉伸系数 layout->setColumnStretch(0, 1); layout->setColumnStretch(1, 1); layout->setColumnStretch(2, 2); }
拉伸系数设为0,意思是不参与拉伸,不再受拉伸窗口而调整了,固定的
修改代码
cppbutton1->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);
此时就达到预期:
表单布局
这种表单布局常用于用户填写信息的场景,左侧为提示文字,右侧为输入框。
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置成3行两列
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
//创建三个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);
}

Spacer-控件之间,添加⼀段空白
使用布局管理器时,若需在控件间添加空白区域,可通过 QSpacerItem 来实现。
核心属性
cppWidget::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); }
示例:
ui中也可以设置
结语:
随着这篇博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。
在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。
你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容。