当前位置: 首页 > news >正文

10.QT-显示类控件|LCD Number|ProgressBar|Calendar Widget(C++)

LCD Number

QLCDNumer 是⼀个专⻔⽤来显⽰数字的控件.类似于"⽼式计算器"的效果

属性说明
intValueQLCDNumber 显⽰的数字值(int).
valueQLCDNumber 显⽰的数字值(double).
和intValue是联动的.
例如给value设为1.5,intValue的值就是2.
另外,设置value和intValue的⽅法名字为 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)在界⾯上创建⼀个 QLCDNumber ,初始值设为10.
objectName 为 lcdNumber
![[Pasted image 20250420134015.png]]

2)修改widget.h代码,创建⼀个 QTimer 成员,和⼀个 updateTime 函数
使用QLCDNumber显示一个初始的数值,比如10
每隔一秒钟,数字就-1 一直到0,就停止了.
此处关键要点是要实现“每秒钟-1”这个效果
周期性的执行某个逻辑~~“定时器"
C++标准库中,没有提供定时器的实现.Boost里面提供了对应的功能
Qt中也封装了对应的定时器~~(结合了信号槽机制的) QTimer
通过这个类创建出来的对象,就会产生一个timeout这样的信号
可以通过start方法来开启定时器,并且参数中设定触发timeout信号的周期

#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->lcdNumber->display("10");//创建一个QTimer实例QTimer* timer = new QTimer(this);//把QTimer的timeout信号和自己的槽函数进行连接connect(timer, &QTimer::timeout, this, &Widget::handle);// 启动 QTimer, 并且规定每隔 1000ms 触发⼀次 timeout 信号timer->start(1000);
}Widget::~Widget()
{delete ui;
}void Widget::handle()
{qDebug() << "handle";
}

QTimer 表⽰定时器.通过 start ⽅法启动定时器之后,就会每隔⼀定周期,触发⼀次QTimer::timeout 信号.
使⽤ connect 把 QTimer::timeout 信号和 Widget::handle 连接起来,意味着每次触发 QTimer::timeout 都会执⾏ Widget::handle
![[Pasted image 20250420135546.png]]

每隔一秒钟会执行一个handle

void Widget::handle()
{//先拿到lcdnumber中的数字int value = ui->lcdNumber->intValue();if (value <= 0){//数字减到0了,停止计时器timer->stop();return;}ui->lcdNumber->display(value - 1);
}
  • 通过 intValue 获取到 QLCDNumber 内部的数值.
  • 如果value的值归0了,就停⽌ QTimer .接下来 QTimer 也就不会触发timeout信号了.
    ![[Pasted image 20250420135930.png]]

1)上述代码如果直接在Widget构造函数中,通过⼀个循环+sleep的⽅式是否可以呢?
Sleep=> Windows 的 api,需要包含"Windows.h"头文件才能使用的
C++ 11 标准库中引l入了 sleep 操作. sleep_for

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);int value = ui->lcdNumber->intValue();while (true) {//先休眠一秒std::this_thread::sleep_for(std::chrono::seconds(1));if (value <= 0) {break;}ui->lcdNumber->display(--value);}
}

Widget的构造函数
需要把Widget构造完毕,然后才能执行后续的显示操作~~
![[Pasted image 20250420142528.png]]

循环会使Widget的构造函数⽆法执⾏完毕,此时界⾯是不能正确构造和显⽰的.

2)上述代码如果是在Widget构造函数中,另起⼀个线程,在新线程中完成循环+sleep是否可以呢?

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);std::thread t([this](){int value = this->ui->lcdNumber->intValue();while (true) {std::this_thread::sleep_for(std::chrono::seconds(1));if (value <= 0) {break;}ui->lcdNumber->display(--value);}});
}

![[Pasted image 20250420143719.png]]

这个代码同样是不⾏的.
Qt中规定,任何对于GUI上内容的操作,必须在主线程中完成.像Widget构造函数,以及connect连接的slot函数,都是在主线程中调⽤的.⽽我们⾃⼰创建的线程则不是.
当我们⾃⼰的线程中尝试对界⾯元素进⾏修改时,Qt程序往往会直接崩溃.

这样的约定主要是因为GUI中的状态往往是牵⼀发动全⾝的,修改⼀个地⽅,就需要同步的对其他内容进⾏调整.
⽐如调整了某个元素的尺⼨,就可能影响到内部的⽂字位置,或者其他元素的位置.这⾥⼀连串的修改,都是需要按照⼀定的顺序来完成的.
由于多线程执⾏的顺序⽆法保障,因此Qt从根本上禁⽌了其他线程修改GUI状态,避免后续的⼀系列问题.

综上所述,使⽤定时器,是实现上述功能的最合理⽅案

ProgressBar

使⽤ QProgressBar 表⽰⼀个进度条

属性说明
minimum进度条最⼩值
maximum进度条最⼤值
value进度条当前值
alignment⽂本在进度条中的对⻬⽅式.
• Qt::AlignLeft :左对⻬
• Qt::AlignRight :右对⻬
• Qt::AlignCenter :居中对⻬
• Qt::AlignJustify :两端对⻬
textVisible进度条的数字是否可⻅.
orientation进度条的⽅向是⽔平还是垂直
invertAppearance是否是朝反⽅向增⻓进度
textDirection⽂本的朝向.
format展⽰的数字格式.
• %p :表⽰进度的百分⽐(0-100)
• %v :表⽰进度的数值(0-100)
• %m :表⽰剩余时间(以毫秒为单位)
• %t :表⽰总时间(以毫秒为单位)
代码⽰例:设置进度条按时间增⻓

1)在界⾯上创建进度条, objectName 为 progressBar
![[Pasted image 20250420150204.png]]

其中最⼩值设为0,最⼤值设为100.当前值设为0.
创建一个进度条,
让这个进度条的进度跟随时间增长
(可以假设,每隔100ms,让进度条数值+1)
设置初始值
![[Pasted image 20250420151719.png]]

2)修改widget.h,创建 QTimer 和 updateProgressBar 函数.
widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTimer>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void handle();private:Ui::Widget *ui;QTimer* timer;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &Widget::handle);//启动操作要在槽函数之后timer->start(100);
}Widget::~Widget()
{delete ui;
}void Widget::handle()
{//获取当前数值int value = ui->progressBar->value();if (value >= 100) {//进度条满了,就可以停止计时器timer->stop();return;}ui->progressBar->setValue(value + 1);
}

![[Pasted image 20250420152215.png]]

在实际开发中,进度条的取值,往往是根据当前任务的实际进度来进⾏设置的.
⽐如需要读取⼀个很⼤的⽂件,就可以获取⽂件的总的⼤⼩,和当前读取完毕的⼤⼩,来设置进度条的⽐例.
由于上⾯我们介绍了Qt禁⽌在其他线程修改界⾯,因此进度条的更新往往也是需要搭配定时器来完成的.
通过定时器周期触发信号,主线程调⽤对应的slot函数.再在slot函数中对当前的任务进度进⾏计算,并更新进度条的界⾯效果.

虽然在widget.h中用到了QTimer,但是却没在.h文件中包含<QTimer>头文件
为啥这个代码编译不会出错?
为啥此处的QTimer就不会提示“找不到定义”之类的
上述问题其实是通过Qt内部提供的一个特殊技巧来实现的~~
在Qt中,有一个专门的头文件这个头文件中包含了Qt中所有类的“前置声明
这个头文件,一般不会直接接触到,但是包含其他的Qt的头文件,都会间接的包含到这个头文件
Widget类的前面已经提供了QTimer类的声名的话
此时就可以在Widget中声明QTimer的指针/引I用类型的成员~~ 后续如果要真正使用QTimer(包括创建实例,使用里面的成员…)
仍然需要包含QTimer的头文件(包含了QTimer的详细的类的定义)

Qt为啥要使用上述的技巧,上述技巧能解决什么问题?有啥提升呢?主要解决的是编译速度的问题
C/C++的代码,编译速度在其他语言横向对比中,是非常慢的
对于一个大规模的项目,编译速度可能非常慢!!!俺在华为的时候,我们哪怕只是给代码中添加一个 printf,编译消耗的时间,就是1个小时左右
C++编译速度慢,和 #include 头文件,有直接关系的,由于include关系错综复杂
因此,尽可能减少 include 头文件的个数,就可以有效的减少编译时间
Qt中就使用class前置声明的方式,来尽量减少头文件的包含
通过前置声明的方式,Qt中的头文件,每个头文件包含的其他头文件数量都能得到一定的降低
所以在C++20 标准开始,就引l入了"模块”module 来替代 #include

代码⽰例:创建⼀个红⾊的进度条

QProgressBar 同样也是 QWidget 的⼦类,因此我们可以使⽤ styleSheet 通过样式来修改进度条的颜⾊.
![[Pasted image 20250420160038.png]]

QProgressBar::chunk {background-color: red;}

QProgressBar::chunk:选择器,设置的样式要针对哪个控件生效
chunk就是原绿色的部分
点击ok,变为红色
![[Pasted image 20250420160357.png]]

同时把 QProcessBar 的 alignment 属性设置为垂直⽔平居中.
![[Pasted image 20250420160617.png]]

此处如果不设置 alignment ,进度条中的数字会跑到左上⻆.这个怀疑是Qt本⾝的bug,暂时只能先使⽤alignment来⼿动调整下.
![[Pasted image 20250420160712.png]]

Calendar Widget

QCalendarWidget 表⽰⼀个"⽇历",形如
![[Pasted image 20250420161602.png]]

属性说明
selectDate当前选中的⽇期
minimumDate最⼩⽇期
maximumDate最⼤⽇期
firstDayOfWeek每周的第⼀天(也就是⽇历的第⼀列)是周⼏.
gridVisible是否显⽰表格的边框
selectionMode是否允许选择⽇期
navigationBarVisible⽇历上⽅标题是否显⽰
horizontalHeaderFormat⽇历上⽅标题显⽰的⽇期格式
verticalHeaderFormat⽇历第⼀列显⽰的内容格式
dateEditEnabled是否允许⽇期被编辑
信号说明
selectionChanged(const QDate&)当选中的⽇期发⽣改变时发出
activated(const QDate&)当双击⼀个有效的⽇期或者按下回⻋键时发出,形参是⼀个QDate类型,保存了选中的⽇期
currentPageChanged(int, int)当年份⽉份改变时发出,形参表⽰改变后的新年份和⽉份
代码示例:获取选中的⽇期

1)在界⾯上创建⼀个 QCalendarWidget 和⼀个label
objectName 为 calendarWidget , label
![[Pasted image 20250420162916.png]]

2)给 QCalendarWidget 添加slot函数
![[Pasted image 20250420162845.png]]

void Widget::on_calendarWidget_selectionChanged()
{QDate date = ui->calendarWidget->selectedDate();qDebug() << date;
}

![[Pasted image 20250420163114.png]]

void Widget::on_calendarWidget_selectionChanged()
{QDate date = ui->calendarWidget->selectedDate();qDebug() << date;ui->label->setText(date.toString());
}

![[Pasted image 20250420163222.png]]

相关文章:

  • [论文阅读]Making Retrieval-Augmented Language Models Robust to Irrelevant Context
  • 论文阅读:2024 arxiv DeepInception: Hypnotize Large Language Model to Be Jailbreaker
  • Pandas高级功能
  • C++入门篇(下)
  • 【支付】支付宝支付
  • go+mysql+cocos实现游戏搭建
  • centos停服 迁移centos7.3系统到新搭建的openEuler
  • HTMLCSS实现网页轮播图
  • max31865典型电路
  • 经典算法 表达式求值
  • DEA-Net:基于细节增强卷积和内容引导注意力的单图像去雾
  • 基础理论学习参考
  • 在 Debian 10.x 安装和配置 Samba
  • 论文笔记(七十八)Do generative video models understand physical principles?
  • 2024新版仿蓝奏云网盘源码,已修复已知BUG,样式风格美化,可正常运营生产
  • LeetCode第158题_用Read4读取N个字符 II
  • C语言之机房机位预约系统
  • AIGC(生成式AI)试用 30 -- AI做软件程序测试 1
  • Day58 | 179. 最大数、316. 去除重复字母、334. 递增的三元子序列
  • 插叙的作用
  • GDP增长6.0%,一季度浙江经济数据出炉
  • 从板凳席到指挥台,横扫广东男篮的少帅潘江究竟有何神奇
  • 多元布局、抱团取暖……上海这个区和外向型企业坐到一起聊了什么
  • 美国国务卿:乌克兰问题谈判不能一直停滞不前
  • 上海警方:男子拍摄女性视频后在网上配发诱导他人违法犯罪文字,被行拘
  • 广西旱情如何?农业厅:近半数农田墒情不足至干旱,本月降雨将渐增