开篇介绍:
hello 大家,本篇博客我们来学习QLCDNumber常见属性以及QTimer
在 Qt 界面开发中,我们经常会遇到两类非常经典的需求:一类是 "模拟老式计算器 / 电子表的液晶数字显示"(比如倒计时器、数字仪表盘),另一类是 "周期性地修改界面状态"(比如每秒刷新一次时间、每隔几秒检查一次状态)。为了满足这两类需求,Qt 专门为我们提供了两个核心控件 / 工具类:QLCDNumber(液晶数字显示控件) 和 QTimer(定时器类)。
很多新手刚接触 QLCDNumber 时,会觉得它和 QLabel 差不多,都是显示数字,但用起来才发现它的 API 很特殊(比如没有 setValue(),只有 display());刚接触 QTimer 时,会试图用 "循环 + sleep" 或者 "多线程" 来实现周期性任务,结果导致界面卡顿或者程序崩溃。
别担心!这篇文章我会结合 QLCDNumber 的所有核心属性(intValue/value、digitCount、mode、segmentStyle、smallDecimalPoint)和 QTimer 的所有核心属性 / 方法(interval、singleShot、active、start()、stop()、timeout() 信号)进行解析
话不多说,我们正式开始!
第一章 先搞懂基础:QLCDNumber 的定位与核心特点
在讲具体属性之前,我们必须先搞懂 QLCDNumber 的 "身份"------ 也就是它在 Qt 控件体系中的定位和核心特点,这能帮我们理解为什么它的 API 那么特殊,什么时候该用它,什么时候该用 QLabel。
1.1 QLCDNumber 的核心定位
QLCDNumber 是 Qt 中专门用于数字可视化展示的控件,核心特征是模拟 "液晶数码管" 显示效果(也就是我们小时候用的老式计算器、电子表的那种数字风格)。
通俗理解:QLabel 就像 "一张白纸,可以写任何字(文本、数字、符号)";而 QLCDNumber 就像 "一个专门的液晶数码管计算器屏幕,只能显示数字、小数点、负号等少数特殊字符,不能显示普通文本,但显示数字的效果非常逼真、有复古感"。

这里有一个非常重要的点需要注意:QLCDNumber 仅支持数字和部分特殊字符(如小数点 .、负号 -、十六进制的 A-F),不支持普通文本(如中文、英文单词)------ 如果你要显示普通文本,还是得用 QLabel;如果你要显示数字,并且想要那种老式计算器的液晶效果,用 QLCDNumber 就对了。
1.2 QLCDNumber 与 QLabel 显示数字的核心区别(必知)
为了让你更清楚地理解什么时候用 QLCDNumber,什么时候用 QLabel,我做了一个对比表格:
表格
| 特性 | QLCDNumber | QLabel |
|---|---|---|
| 核心用途 | 专门显示数字,模拟液晶数码管效果 | 通用展示控件,显示文本 / 图片 / 数字 |
| 支持内容 | 仅数字、小数点、负号、十六进制 A-F | 任意文本、图片、数字 |
| 显示效果 | 复古液晶数码管风格,有立体感 | 普通平面风格,可自定义样式 |
| API 特殊性 | 设置数值用 display(),无 setValue() |
设置文本用 setText(),符合常规 |
| 进制支持 | 内置十进制 / 十六进制 / 二进制 / 八进制切换 | 需手动转换进制后显示为文本 |
| 小数显示 | 仅十进制支持小数,其他进制忽略小数 | 任意进制都可显示小数(需手动处理) |
简单总结:如果你只是要简单显示一个数字,用 QLabel 就行;如果你要模拟老式计算器的液晶效果,或者需要快速切换进制显示,用 QLCDNumber 更合适。
第二章 QLCDNumber 核心属性详解(上):数值相关属性(intValue、value)
QLCDNumber 的核心功能是显示数字,Qt 为它提供了两个数值相关的属性:intValue(整数数值)和 value(浮点数值)。这两个属性是 QLCDNumber 最基础、最常用的属性,但它们的 API 很特殊 ------没有 setValue() 或 setIntValue() 方法,只能用 display() 方法设置数值,我们先从它们讲起。
2.1 属性一:intValue(整数数值)与属性二:value(浮点数值)------ 联动的数值属性
2.1.1 两个属性的核心定义与联动规则
intValue 和 value 是 QLCDNumber 中两个实时联动的数值属性:
- intValue :表示控件以整数形式展示的数字值,数据类型为
int,默认值为 0; - value :表示控件以浮点数形式展示的数字值,数据类型为
double,默认值为 0.0。
它们的联动规则非常重要,必须牢记:
- 当调用
display(int num)设置整数时 :value会自动变为num.0(比如display(10)→intValue=10,value=10.0);intValue就是你设置的整数num,没有四舍五入(因为输入本身是整数)。
- 当调用
display(double num)设置浮点数时 :value会保留你设置的原始浮点值num;intValue会自动对num进行标准数学四舍五入 (比如display(1.5)→intValue=2,display(1.4)→intValue=1,display(2.49)→intValue=2)。
- 读取属性时 :
intValue()始终返回value()四舍五入后的整数;value()始终返回原始设置的浮点值(未做四舍五入)。
这里有一个最特殊的点:QLCDNumber 不遵循 Qt 常规的 setXxx() 命名规则 ------ 设置数值不能用 setValue() 或 setIntValue(),只能用 display() 方法(有两个重载版本:display(int num) 和 display(double num))。这是新手最容易踩的坑之一,一定要记住!
2.1.2 关联 API 详解(逐词逐句,零模糊)
1. 获取整数数值:int intValue () const
函数原型:
int QLCDNumber::intValue() const;
逐词逐句底层解析:
int:返回值类型,返回当前显示的整数数值(value四舍五入后的结果);QLCDNumber:::说明这个函数是QLCDNumber类的成员函数,只能用 QLCDNumber 对象调用;intValue():函数名,很直观,就是 "获取整数值" 的意思;const:说明这个函数是常成员函数 ------ 它只会读取 QLCDNumber 的数值,不会修改任何状态,所以你可以在const的成员函数里调用它。
返回值说明:
- 返回
int类型的整数,是value四舍五入后的结果; - 默认返回 0(未设置数值时)。
调用示例:
// 获取当前显示的整数数值
int currentInt = ui->lcdNumber->intValue();
// 打印出来验证
qDebug() << "当前整数数值:" << currentInt;
2. 获取浮点数值:double value () const
函数原型:
double QLCDNumber::value() const;
逐词逐句底层解析:
double:返回值类型,返回当前显示的原始浮点数值(未四舍五入);QLCDNumber:::成员函数;value():函数名,"获取浮点数值" 的意思;const:常成员函数。
返回值说明:
- 返回
double类型的浮点数,是原始设置的数值(未做四舍五入); - 默认返回 0.0(未设置数值时)。
调用示例:
// 获取当前显示的浮点数值
double currentDouble = ui->lcdNumber->value();
// 打印出来验证
qDebug() << "当前浮点数值:" << currentDouble;
3. 设置整数数值:void display (int num)
函数原型:
void QLCDNumber::display(int num);
逐词逐句底层解析:
void:函数没有返回值,只是执行 "设置数值" 的操作;QLCDNumber:::成员函数;display():函数名,"显示数值" 的意思(注意不是setIntValue()!);int num:入参,num是要显示的整数数值。
参数说明:
num:要显示的整数数值,int类型;- 负数也可以显示(仅十进制模式下显示负号
-,非十进制模式下会转为无符号数)。
生效规则:
- 调用后立即生效,控件会显示对应的整数;
value会同步变为num.0,intValue会同步变为num。
调用示例:
// 设置整数数值 100
ui->lcdNumber->display(100);
// 验证联动关系
qDebug() << "intValue:" << ui->lcdNumber->intValue(); // 输出 100
qDebug() << "value:" << ui->lcdNumber->value(); // 输出 100.0
4. 设置浮点数值:void display (double num)
函数原型:
void QLCDNumber::display(double num);
逐词逐句底层解析:
void:无返回值;QLCDNumber:::成员函数;display():函数名(注意不是setValue()!);double num:入参,num是要显示的浮点数值。
参数说明:
num:要显示的浮点数值,double类型;- 仅在
mode=QLCDNumber::Dec(十进制模式)时,小数点后内容才会显示;非十进制模式下,小数部分会被忽略,仅显示整数部分。
生效规则:
- 调用后立即生效,控件会根据
mode显示对应的数值; value会保留原始浮点值num,intValue会自动四舍五入更新。
调用示例:
// 设置浮点数值 1.5
ui->lcdNumber->display(1.5);
// 验证联动关系
qDebug() << "intValue:" << ui->lcdNumber->intValue(); // 输出 2(四舍五入)
qDebug() << "value:" << ui->lcdNumber->value(); // 输出 1.5(原始值)
// 设置浮点数值 2.49
ui->lcdNumber->display(2.49);
qDebug() << "intValue:" << ui->lcdNumber->intValue(); // 输出 2(四舍五入)
qDebug() << "value:" << ui->lcdNumber->value(); // 输出 2.49(原始值)
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,本文件我们来学习QLCDNumber控件的intValue属性以及value属性
//那么顾名思义,intValue属性就是设置QLCDNumber控件显示的数字值是为int类型的
//而value属性就是设置QLCDNumber控件显示的数字值是为double类型的~~~
//value和 intValue 是联动的.
//例如给 value 设为 1.5, intValue 的值就是 2.
//另外, 设置 value 和 intValue 的方法名字为 display , 而不是 setValue 或者 setIntValue .
//即我们要设置QLCDNumber控件显示的数字值的话,直接就是使用display函数,里面出传入int或者double类型都可以
//获取数值的话,再用属性名函数
/**
* @property QLCDNumber::intValue
* @brief QLCDNumber以整数形式展示的数字值
* @details 该属性表示QLCDNumber控件显示数字的整数版本,与value(浮点型属性)实时联动,默认值为0;
* 当通过浮点值设置控件内容时,intValue会自动对浮点值进行**四舍五入**处理(如value=1.5 → intValue=2,value=1.4 → intValue=1);
* 该属性无直接的setIntValue()方法,必须通过display()系列方法间接修改,这是QLCDNumber与常规Qt控件属性的核心区别。
*
* 【关联API详解】
* 1. int intValue() const
* - 功能:获取当前控件显示的整数数值
* - 返回值:int类型,为value属性四舍五入后的结果
* - 调用示例:
* int currentInt = ui->lcdNumber->intValue(); // 读取当前整数显示值
*
* 2. void display(int num)
* - 功能:设置intValue的核心方法(无setIntValue())
* - 参数:num - 要显示的整数数值
* - 生效逻辑:设置后value属性会同步变为num.0(如display(10) → intValue=10,value=10.0)
* - 调用示例:
* ui->lcdNumber->display(10); // 控件显示10,intValue=10,value=10.0
*
* ---
*
* @property QLCDNumber::value
* @brief QLCDNumber以浮点数形式展示的数字值
* @details 该属性表示QLCDNumber控件显示数字的浮点版本,与intValue(整型属性)实时联动,默认值为0.0;
* 该属性无直接的setValue()方法,必须通过display(double)方法修改;仅当QLCDNumber的显示模式为十进制(Dec)时,小数点后的内容才会显示,非十进制模式下仅保留整数部分;
* 修改该属性后,intValue会自动四舍五入更新(如display(1.5) → value=1.5,intValue=2)。
*
* 【关联API详解】
* 1. double value() const
* - 功能:获取当前控件显示的浮点数值
* - 返回值:double类型,为原始设置的浮点值(未做四舍五入处理)
* - 调用示例:
* double currentDouble = ui->lcdNumber->value(); // 读取当前浮点显示值
*
* 2. void display(double num)
* - 功能:设置value的核心方法(无setValue())
* - 参数:num - 要显示的浮点数值
* - 生效逻辑:设置后intValue会同步四舍五入更新,控件显示内容受显示模式影响
* - 调用示例:
* ui->lcdNumber->display(1.5); // value=1.5,intValue=2(四舍五入)
* ui->lcdNumber->display(2.49); // value=2.49,intValue=2(四舍五入)
*
* 【intValue与value核心联动规则(必知)】
* 1. 当调用display(int num)时:
* → value = num(自动转为浮点型,如num=5 → value=5.0)
* → intValue = num(无四舍五入,因为输入本身是整数)
* 2. 当调用display(double num)时:
* → value = num(保留原始浮点值)
* → intValue = 对num进行四舍五入后的整数(如num=1.5→2,num=3.4→3)
* 3. 读取属性时:
* → value返回原始浮点值,intValue返回四舍五入后的整数,二者始终保持联动同步。
*
* 【关键注意事项】
* 1. 方法命名特殊:QLCDNumber不遵循Qt常规的setXxx()命名规则,设置数值只能用display(int)/display(double),不存在setValue()或setIntValue()方法;
* 2. 显示限制:非十进制模式(如十六进制、二进制)下,value的小数部分会被忽略,仅显示整数部分,intValue仍为四舍五入结果;
* 3. 四舍五入规则:遵循标准数学四舍五入,0.5向上取整,0.4向下取整。
*
* 【典型使用示例】
* // 示例1:设置整数数值
* ui->lcdNumber->display(100); // intValue=100,value=100.0
* qDebug() << "intValue:" << ui->lcdNumber->intValue(); // 输出100
* qDebug() << "value:" << ui->lcdNumber->value(); // 输出100.0
*
* // 示例2:设置浮点数值,验证联动
* ui->lcdNumber->display(1.5); // value=1.5,intValue=2
* qDebug() << "intValue:" << ui->lcdNumber->intValue(); // 输出2
* qDebug() << "value:" << ui->lcdNumber->value(); // 输出1.5
*
* // 示例3:非十进制模式下的浮点值处理
* ui->lcdNumber->setMode(QLCDNumber::Hex); // 切换为十六进制
* ui->lcdNumber->display(15.9); // 小数部分忽略,控件显示F(15的十六进制)
* qDebug() << "intValue:" << ui->lcdNumber->intValue(); // 输出16(15.9四舍五入)
* qDebug() << "value:" << ui->lcdNumber->value(); // 输出15.9
*/
QLCDNumber* lcdnumber=new QLCDNumber(this);
//传入整型
lcdnumber->display(5);
//获取int类型数值
int nubmerint=lcdnumber->intValue();
//传入double类型
lcdnumber->display(5.5);
//获取double类型数值
int nubmerdouble=lcdnumber->value();
}
Widget::~Widget()
{
delete ui;
}
2.1.3 典型代码示例(两个实用场景,一看就懂)
示例一:验证 intValue 与 value 的联动关系
这个场景可以直观地看到两个属性的联动规则:
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 QLCDNumber 控件
QLCDNumber *lcd = new QLCDNumber(this);
lcd->setGeometry(100, 100, 200, 80);
lcd->setMode(QLCDNumber::Dec); // 十进制模式,支持小数
// 1. 设置整数数值,验证联动
lcd->display(10);
qDebug() << "=== 设置整数 10 ===";
qDebug() << "intValue:" << lcd->intValue(); // 输出 10
qDebug() << "value:" << lcd->value(); // 输出 10.0
// 2. 设置浮点数值 1.5,验证四舍五入
lcd->display(1.5);
qDebug() << "=== 设置浮点数 1.5 ===";
qDebug() << "intValue:" << lcd->intValue(); // 输出 2(四舍五入)
qDebug() << "value:" << lcd->value(); // 输出 1.5
// 3. 设置浮点数值 1.4,验证四舍五入
lcd->display(1.4);
qDebug() << "=== 设置浮点数 1.4 ===";
qDebug() << "intValue:" << lcd->intValue(); // 输出 1(四舍五入)
qDebug() << "value:" << lcd->value(); // 输出 1.4
}
Widget::~Widget()
{
delete ui;
}
示例二:非十进制模式下的浮点值处理
这个场景可以看到非十进制模式下小数部分会被忽略:
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLCDNumber *lcd = new QLCDNumber(this);
lcd->setGeometry(100, 100, 200, 80);
lcd->setDigitCount(5); // 最多显示5位
// 1. 十进制模式:显示小数
lcd->setMode(QLCDNumber::Dec);
lcd->display(12.34);
qDebug() << "=== 十进制模式,设置 12.34 ===";
qDebug() << "显示内容:12.34(正常显示小数)";
qDebug() << "intValue:" << lcd->intValue(); // 输出 12(四舍五入)
qDebug() << "value:" << lcd->value(); // 输出 12.34
// 2. 十六进制模式:忽略小数,仅显示整数部分
lcd->setMode(QLCDNumber::Hex);
lcd->display(12.34); // 小数部分 0.34 被忽略,仅显示 12 的十六进制
qDebug() << "=== 十六进制模式,设置 12.34 ===";
qDebug() << "显示内容:C(12 的十六进制,小数被忽略)";
qDebug() << "intValue:" << lcd->intValue(); // 输出 12(四舍五入)
qDebug() << "value:" << lcd->value(); // 输出 12.34(原始值仍保留)
}
Widget::~Widget()
{
delete ui;
}
2.1.4 关键注意事项与新手必踩的坑(100% 避坑指南)
intValue 和 value 看起来简单,但新手很容易踩坑,我把最常见的几个坑列出来:
坑点一:试图用 setValue () 或 setIntValue () 设置数值,编译报错
问题描述 :新手按照 Qt 常规的 setXxx() 命名规则,写了 ui->lcdNumber->setValue(10) 或 ui->lcdNumber->setIntValue(10),结果编译报错,说没有这个函数。
原因分析 :这是 QLCDNumber 最特殊的地方 ------ 它不遵循 Qt 常规的 setXxx() 命名规则,设置数值只能用 display() 方法(display(int) 或 display(double))。
解决方式 :把 setValue() 或 setIntValue() 改成 display(),比如 ui->lcdNumber->display(10)。
坑点二:非十进制模式下,小数部分没有显示,以为是 bug
问题描述 :新手设置了 display(12.34),然后切换到十六进制模式,结果发现只显示了 C(12 的十六进制),小数部分不见了,以为是 Qt 的 bug。
原因分析 :这是正常的!QLCDNumber 的设计逻辑是**"仅十进制模式支持显示小数"** ------ 非十进制模式(十六进制、二进制、八进制)下,小数部分会被自动忽略,仅显示整数部分(但 value() 仍会保留原始浮点值,intValue() 仍会四舍五入)。
解决方式 :如果要显示小数,必须将 mode 设置为 QLCDNumber::Dec(十进制模式)。
坑点三:四舍五入规则理解错误,以为 1.5 会变成 1
问题描述 :新手设置了 display(1.5),结果发现 intValue() 返回 2,以为是四舍五入错了,应该返回 1。
原因分析 :这是正常的!QLCDNumber 遵循标准数学四舍五入规则------0.5 向上取整,0.4 向下取整(1.5 → 2,1.4 → 1,2.5 → 3,2.49 → 2)。
解决方式:记住标准数学四舍五入规则即可,这是正确的行为。
第三章 QLCDNumber 核心属性详解(中):显示位数与进制属性(digitCount、mode)
讲完了数值相关的属性,我们再讲两个控制数字显示形式的属性:digitCount(显示位数)和 mode(进制模式)。这两个属性可以控制 QLCDNumber 最多显示几位数字、用什么进制显示(十进制 / 十六进制 / 二进制 / 八进制),非常实用。
3.1 属性三:digitCount(显示位数)------ 控制数字显示长度的核心
3.1.1 属性的核心定义
digitCount 属性用于设置 QLCDNumber 最多可显示的数字(含小数点、负号)总位数,默认值为 0(自适应位数,无限制)。
通俗理解:digitCount 就像 "液晶数码管的位数限制"------ 比如老式计算器通常只有 8 位数字,如果你输入的数字超过 8 位,就会显示 "溢出"(通常是 ####);如果设置 digitCount=0,数码管会根据数字长度自动调整位数,不会溢出。
这里有一个非常重要的位数统计规则,必须牢记:
- 整数位、小数点、小数位、负号都计入总位数 !
- 比如数值
12.34:总位数为 5(1、2、.、3、4); - 比如数值
-12.3:总位数为 5(-、1、2、.、3); - 比如数值
12345:总位数为 5(1、2、3、4、5)。
- 比如数值
如果要显示的数字总位数超过了设置的 digitCount,QLCDNumber 会显示 ####(溢出提示);如果数值位数小于 digitCount,控件会在左侧补空格(比如 digitCount=5,显示 123 → " 123",左侧补两个空格)。
3.1.2 数据类型
int 类型,非负整数(0 表示自适应位数,无限制;>0 表示指定最大显示位数),默认值为 0。
3.1.3 关联 API 详解(逐词逐句,零模糊)
1. 获取当前显示位数:int digitCount () const
函数原型:
int QLCDNumber::digitCount() const;
逐词逐句底层解析:
int:返回值类型,返回当前设置的最大显示位数;QLCDNumber:::成员函数;digitCount():函数名,"获取显示位数" 的意思;const:常成员函数。
返回值说明:
- 返回
int类型的数值,0 表示自适应(无位数限制),非 0 表示最大显示位数; - 默认返回 0。
调用示例:
int count = ui->lcdNumber->digitCount();
qDebug() << "当前设置的显示位数:" << count;
2. 设置显示位数:void setDigitCount (int numDigits)
函数原型:
void QLCDNumber::setDigitCount(int numDigits);
逐词逐句底层解析:
void:无返回值;QLCDNumber:::成员函数;setDigitCount():函数名,"设置显示位数" 的意思;int numDigits:入参,numDigits是要设置的最大显示位数(非负整数)。
参数说明:
numDigits:非负整数,0 表示自适应位数(无限制),>0 表示指定最大显示位数;- 如果传入负数,会被自动修正为 0。
生效规则:
- 调用后立即生效,当前显示的数值会重新按新位数调整;
- 如果数值位数超过
numDigits,显示####;如果不足,左侧补空格。
调用示例:
// 设置最多显示 5 位
ui->lcdNumber->setDigitCount(5);
ui->lcdNumber->display(12.34); // 总位数 5(1+2+.+3+4),正常显示 "12.34"
ui->lcdNumber->display(123.456); // 总位数 7(超过 5),显示 "#####"(溢出)
// 设置为自适应位数(0)
ui->lcdNumber->setDigitCount(0);
ui->lcdNumber->display(123456.789); // 自适应位数,正常显示,无溢出
3.1.4 典型代码示例(两个实用场景,一看就懂)
示例一:验证位数统计规则与溢出效果
这个场景可以直观地看到位数统计规则和溢出效果:
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLCDNumber *lcd = new QLCDNumber(this);
lcd->setGeometry(100, 100, 300, 80);
lcd->setMode(QLCDNumber::Dec); // 十进制模式
// 1. 设置最多显示 5 位
lcd->setDigitCount(5);
// 测试 1:12.34(总位数 5:1、2、.、3、4)→ 正常显示
lcd->display(12.34);
qDebug() << "测试 1:12.34(总位数 5)→ 正常显示";
// 测试 2:-12.3(总位数 5:-、1、2、.、3)→ 正常显示
lcd->display(-12.3);
qDebug() << "测试 2:-12.3(总位数 5)→ 正常显示";
// 测试 3:123.456(总位数 7:1、2、3、.、4、5、6)→ 溢出,显示 #####
lcd->display(123.456);
qDebug() << "测试 3:123.456(总位数 7)→ 溢出,显示 #####";
// 测试 4:123(总位数 3)→ 左侧补 2 个空格,显示 " 123"
lcd->display(123);
qDebug() << "测试 4:123(总位数 3)→ 左侧补空格,显示 \" 123\"";
}
Widget::~Widget()
{
delete ui;
}
3.2 属性四:mode(进制模式)------ 控制数字显示进制的核心
3.2.1 属性的核心定义
mode 属性用于控制 QLCDNumber 显示数字的进制格式,默认值为 QLCDNumber::Dec(十进制)。
通俗理解:mode 就像 "计算器的进制切换开关"------ 你可以切换到十进制(显示常规数字)、十六进制(显示 0-9、A-F)、二进制(显示 0/1)、八进制(显示 0-7)。
这里有两个非常重要的点需要注意:
- 仅十进制支持小数 :只有
mode=QLCDNumber::Dec(十进制)时,小数点后内容才会显示;非十进制模式(Hex/Bin/Oct)下,小数部分会被自动忽略,仅显示整数部分; - 负数处理 :仅十进制支持显示负号(
-);非十进制模式下,负数会被转为无符号数后显示(比如-1在十六进制下会显示为FFFFFFFF,取决于位数)。
3.2.2 数据类型
QLCDNumber::Mode 枚举类型,这是 Qt 中专门用来定义 QLCDNumber 进制模式的枚举,包含四个常用值:
QLCDNumber::Dec:十进制(默认);QLCDNumber::Hex:十六进制;QLCDNumber::Bin:二进制;QLCDNumber::Oct:八进制。
3.2.3 枚举值详解(通俗版,一目了然)
为了让你更清楚地理解每个枚举值的作用,我做了一个对比表格:
| 枚举值 | 中文名称 | 功能说明 | 示例(输入 vs 输出) |
|---|---|---|---|
| QLCDNumber::Dec | 十进制 | 显示常规十进制数字,支持整数 / 浮点数(含小数点、负号),是唯一支持小数的模式; | 输入 12.34 → 输出 12.34输入 -12 → 输出 -12 |
| QLCDNumber::Hex | 十六进制 | 以十六进制格式显示数字(0-9、A-F),仅支持整数,忽略小数部分; | 输入 255 → 输出 FF输入 12.34 → 输出 C(忽略小数) |
| QLCDNumber::Bin | 二进制 | 以二进制格式显示数字(0/1),仅支持整数,忽略小数部分; | 输入 8 → 输出 1000输入 12.34 → 输出 1100(忽略小数) |
| QLCDNumber::Oct | 八进制 | 以八进制格式显示数字(0-7),仅支持整数,忽略小数部分; | 输入 10 → 输出 12输入 12.34 → 输出 14(忽略小数) |
3.2.4 关联 API 详解(逐词逐句,零模糊)
1. 获取当前进制模式:QLCDNumber::Mode mode () const
函数原型:
QLCDNumber::Mode QLCDNumber::mode() const;
逐词逐句底层解析:
QLCDNumber::Mode:返回值类型,返回当前的进制显示模式;QLCDNumber:::成员函数;mode():函数名,"获取进制模式" 的意思;const:常成员函数。
返回值说明:
- 返回
QLCDNumber::Mode枚举值,默认返回QLCDNumber::Dec。
调用示例:
QLCDNumber::Mode currentMode = ui->lcdNumber->mode();
if (currentMode == QLCDNumber::Dec) {
qDebug() << "当前是十进制模式";
}
2. 设置进制模式:void setMode (QLCDNumber::Mode mode)
函数原型:
void QLCDNumber::setMode(QLCDNumber::Mode mode);
逐词逐句底层解析:
void:无返回值;QLCDNumber:::成员函数;setMode():函数名,"设置进制模式" 的意思;QLCDNumber::Mode mode:入参,mode是进制枚举值(Dec/Hex/Bin/Oct)。
参数说明:
mode:QLCDNumber::Mode枚举值,支持Dec(十进制)、Hex(十六进制)、Bin(二进制)、Oct(八进制)。
生效规则:
- 调用后立即生效,当前显示的数值会自动按新进制转换展示;
digitCount(显示位数)的限制仍生效(比如二进制1100需设置digitCount≥4)。
调用示例:
// 1. 十进制模式(支持小数)
ui->lcdNumber->setMode(QLCDNumber::Dec);
ui->lcdNumber->display(12.34); // 显示 "12.34"
// 2. 十六进制模式(忽略小数)
ui->lcdNumber->setMode(QLCDNumber::Hex);
ui->lcdNumber->display(255); // 显示 "FF"
ui->lcdNumber->display(12.34); // 显示 "C"(忽略小数 0.34)
// 3. 二进制模式(忽略小数)
ui->lcdNumber->setMode(QLCDNumber::Bin);
ui->lcdNumber->display(8); // 显示 "1000"
// 4. 八进制模式(忽略小数)
ui->lcdNumber->setMode(QLCDNumber::Oct);
ui->lcdNumber->display(10); // 显示 "12"
两个属性示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么本文件我们来学习QLCDNumber的mode属性和segment属性
//这两个属性其实也是非常的简单,mode属性就是控制数字的显示模式,十进制、八进制等等
//数字显示形式.
//1. QLCDNumber::Dec :十进制模式,显示常规的十进制数字,默认就是显示十进制
//2. QLCDNumber::Hex :十六进制模式,以十六进制格式显示数字。
//3. QLCDNumber::Bin :二进制模式,以二进制格式显示数字。
//4. QLCDNumber::Oct :八进制模式,以八进制格式显示数字。
//只有十进制的时候才能显示小数点后的内容.
//而segment属性就是设置显示风格,平面、轮廓、填充等等~~~
//设置显示风格.
//1. QLCDNumber::Flat :平面的显示风格,数字呈现在一个平坦的表面上。
//2. QLCDNumber::Outline :轮廓显示风格,数字具有清晰的轮廓和阴影效果。
//3. QLCDNumber::Filled :填充显示风格,数字被填充颜色并与背景区分开。
//还是很简单的
/**
* @property QLCDNumber::mode
* @brief QLCDNumber的数字进制显示模式属性
* @details 该属性用于控制QLCDNumber显示数字的进制格式,默认值为QLCDNumber::Dec(十进制);
* 核心区别在于仅十进制模式支持显示小数点后的浮点内容,其他进制(十六/二/八进制)会自动忽略小数部分,仅显示整数部分(且按对应进制转换)。
*
* 【枚举值详解(QLCDNumber::Mode)】
* | 枚举值 | 中文名称 | 功能说明 |
* |-----------------|------------|--------------------------------------------------------------------------|
* | QLCDNumber::Dec | 十进制 | 显示常规十进制数字,支持整数/浮点数(含小数点),是唯一支持小数的模式; |
* | QLCDNumber::Hex | 十六进制 | 以十六进制格式显示数字(0-9、A-F),仅支持整数,忽略小数部分; |
* | QLCDNumber::Bin | 二进制 | 以二进制格式显示数字(0/1),仅支持整数,忽略小数部分; |
* | QLCDNumber::Oct | 八进制 | 以八进制格式显示数字(0-7),仅支持整数,忽略小数部分; |
*
* 【关联API详解】
* 1. QLCDNumber::Mode mode() const
* - 功能:获取当前的进制显示模式
* - 返回值:QLCDNumber::Mode枚举值,默认返回QLCDNumber::Dec
* - 调用示例:
* QLCDNumber::Mode currentMode = ui->lcdNumber->mode();
*
* 2. void setMode(QLCDNumber::Mode mode)
* - 功能:设置数字的进制显示模式
* - 参数:mode - 进制枚举值,支持Dec/Hex/Bin/Oct
* - 生效规则:设置后立即生效,当前显示的数值会自动按新进制转换展示
* - 调用示例:
* // 十进制模式(支持小数)
* ui->lcdNumber->setMode(QLCDNumber::Dec);
* ui->lcdNumber->display(12.34); // 显示"12.34"
*
* // 十六进制模式(忽略小数,12的十六进制为C)
* ui->lcdNumber->setMode(QLCDNumber::Hex);
* ui->lcdNumber->display(12.34); // 显示"C"
*
* // 二进制模式(12的二进制为1100)
* ui->lcdNumber->setMode(QLCDNumber::Bin);
* ui->lcdNumber->display(12); // 显示"1100"
*
* 【关键注意事项】
* 1. 小数限制:非十进制模式下,即使调用display(double)传入浮点数,也会自动取整(四舍五入前的整数部分)后按对应进制显示;
* 2. 负数处理:仅十进制支持显示负号(-),其他进制会将负数转为无符号数后显示;
* 3. 位数适配:进制切换后,digitCount(显示位数)的限制仍生效(如二进制1100需设置digitCount≥4)。
*
* ---
*
* @property QLCDNumber::segmentStyle
* @brief QLCDNumber的数字显示视觉风格属性
* @details 该属性用于控制QLCDNumber中"液晶数码管"数字的视觉展示风格,默认值为QLCDNumber::Outline;
* 不同风格仅改变数字的视觉效果(平面/轮廓/填充),不影响数字内容和进制显示逻辑,核心适配不同的界面视觉需求。
*
* 【枚举值详解(QLCDNumber::SegmentStyle)】
* | 枚举值 | 中文名称 | 功能说明 |
* |---------------------|------------|--------------------------------------------------------------------------|
* | QLCDNumber::Flat | 平面风格 | 数字无立体感,呈现在平坦的表面上,线条简洁,无阴影/填充效果; |
* | QLCDNumber::Outline | 轮廓风格 | 数字有清晰的轮廓线条,搭配轻微阴影效果,具备基础立体感(默认风格); |
* | QLCDNumber::Filled | 填充风格 | 数字内部被纯色填充,与背景对比强烈,立体感最强,视觉最醒目; |
*
* 【关联API详解】
* 1. QLCDNumber::SegmentStyle segmentStyle() const
* - 功能:获取当前的数字显示风格
* - 返回值:QLCDNumber::SegmentStyle枚举值,默认返回QLCDNumber::Outline
*
* 2. void setSegmentStyle(QLCDNumber::SegmentStyle style)
* - 功能:设置数字的视觉显示风格
* - 参数:style - 风格枚举值,支持Flat/Outline/Filled
* - 调用示例:
* // 填充风格(最醒目,适配老式计算器效果)
* ui->lcdNumber->setSegmentStyle(QLCDNumber::Filled);
*
* // 平面风格(简约,适配现代界面)
* ui->lcdNumber->setSegmentStyle(QLCDNumber::Flat);
*
* 【关键注意事项】
* 1. 风格全局生效:设置后所有数字(无论进制)均采用该风格显示;
* 2. 颜色适配:填充风格的数字颜色受控件的foregroundRole(前景色)控制,可通过setStyleSheet修改;
* 3. 性能影响:三种风格的渲染性能无明显差异,可根据界面设计自由选择。
*
* 【典型组合示例】
* // 需求:二进制显示、6位数字、填充风格、显示数值18
* ui->lcdNumber->setMode(QLCDNumber::Bin); // 二进制模式
* ui->lcdNumber->setDigitCount(6); // 最多显示6位
* ui->lcdNumber->setSegmentStyle(QLCDNumber::Filled); // 填充风格
* ui->lcdNumber->display(18); // 18的二进制为10010,显示" 10010"(6位补空格)
*/
QLCDNumber* lcdnumber=new QLCDNumber(this);
lcdnumber->display(55.5);
lcdnumber->setMode(QLCDNumber::Dec);
lcdnumber->setSegmentStyle(QLCDNumber::Outline);
lcdnumber->setSegmentStyle(QLCDNumber::Filled);
}
Widget::~Widget()
{
delete ui;
}
3.2.5 典型代码示例(两个实用场景,一看就懂)
示例一:快速切换进制显示
这个场景可以直观地看到不同进制的显示效果:
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
#include <QPushButton>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建垂直布局
QVBoxLayout *layout = new QVBoxLayout(this);
// 创建 QLCDNumber
QLCDNumber *lcd = new QLCDNumber(this);
lcd->setDigitCount(8); // 最多显示 8 位
lcd->display(255); // 初始显示 255
layout->addWidget(lcd);
// 创建进制切换按钮
QPushButton *btnDec = new QPushButton("十进制", this);
QPushButton *btnHex = new QPushButton("十六进制", this);
QPushButton *btnBin = new QPushButton("二进制", this);
QPushButton *btnOct = new QPushButton("八进制", this);
layout->addWidget(btnDec);
layout->addWidget(btnHex);
layout->addWidget(btnBin);
layout->addWidget(btnOct);
// 关联按钮点击信号,切换进制
connect(btnDec, &QPushButton::clicked, this, [=]() {
lcd->setMode(QLCDNumber::Dec);
lcd->display(255.5); // 十进制显示小数
});
connect(btnHex, &QPushButton::clicked, this, [=]() {
lcd->setMode(QLCDNumber::Hex);
lcd->display(255.5); // 十六进制忽略小数,显示 FF
});
connect(btnBin, &QPushButton::clicked, this, [=]() {
lcd->setMode(QLCDNumber::Bin);
lcd->display(255); // 二进制显示 11111111
});
connect(btnOct, &QPushButton::clicked, this, [=]() {
lcd->setMode(QLCDNumber::Oct);
lcd->display(255); // 八进制显示 377
});
}
Widget::~Widget()
{
delete ui;
}
第四章 QLCDNumber 核心属性详解(下):显示风格与小数点属性(segmentStyle、smallDecimalPoint)
最后,我们讲 QLCDNumber 的两个视觉效果属性:segmentStyle(显示风格)和 smallDecimalPoint(小小数点)。这两个属性可以控制液晶数字的视觉风格(平面 / 轮廓 / 填充)和小数点的尺寸,让显示效果更符合你的界面设计。
4.1 属性五:segmentStyle(显示风格)------ 控制数字视觉效果的核心
4.1.1 属性的核心定义
segmentStyle 属性用于控制 QLCDNumber 中 "液晶数码管" 数字的视觉展示风格,默认值为 QLCDNumber::Outline。
通俗理解:segmentStyle 就像 "液晶数码管的显示效果开关"------ 你可以选择 "平面风格"(数字平平的,没有立体感)、"轮廓风格"(数字有轮廓和轻微阴影,有基础立体感,默认)、"填充风格"(数字被纯色填充,立体感最强,最醒目)。
这里有一个点需要注意:不同风格仅改变数字的视觉效果,不影响数字内容和进制显示逻辑------ 你可以根据界面设计自由选择,三种风格的渲染性能无明显差异。
4.1.2 数据类型
QLCDNumber::SegmentStyle 枚举类型,这是 Qt 中专门用来定义 QLCDNumber 显示风格的枚举,包含三个常用值:
QLCDNumber::Flat:平面风格;QLCDNumber::Outline:轮廓风格(默认);QLCDNumber::Filled:填充风格。
4.1.3 枚举值详解(通俗版,一目了然)
为了让你更清楚地理解每个枚举值的作用,我做了一个对比表格:
| 枚举值 | 中文名称 | 功能说明 | 适用场景 |
|---|---|---|---|
| QLCDNumber::Flat | 平面风格 | 数字无立体感,呈现在平坦的表面上,线条简洁,无阴影 / 填充效果; | 现代简约界面 |
| QLCDNumber::Outline | 轮廓风格 | 数字有清晰的轮廓线条,搭配轻微阴影效果,具备基础立体感(默认风格); | 通用场景,复古电子表效果 |
| QLCDNumber::Filled | 填充风格 | 数字内部被纯色填充,与背景对比强烈,立体感最强,视觉最醒目; | 老式计算器效果,需要醒目显示 |
4.1.4 关联 API 详解(逐词逐句,零模糊)
1. 获取当前显示风格:QLCDNumber::SegmentStyle segmentStyle () const
函数原型:
QLCDNumber::SegmentStyle QLCDNumber::segmentStyle() const;
逐词逐句底层解析:
QLCDNumber::SegmentStyle:返回值类型,返回当前的数字显示风格;QLCDNumber:::成员函数;segmentStyle():函数名,"获取显示风格" 的意思;const:常成员函数。
返回值说明:
- 返回
QLCDNumber::SegmentStyle枚举值,默认返回QLCDNumber::Outline。
调用示例:
QLCDNumber::SegmentStyle currentStyle = ui->lcdNumber->segmentStyle();
if (currentStyle == QLCDNumber::Filled) {
qDebug() << "当前是填充风格";
}
2. 设置显示风格:void setSegmentStyle (QLCDNumber::SegmentStyle style)
函数原型:
void QLCDNumber::setSegmentStyle(QLCDNumber::SegmentStyle style);
逐词逐句底层解析:
void:无返回值;QLCDNumber:::成员函数;setSegmentStyle():函数名,"设置显示风格" 的意思;QLCDNumber::SegmentStyle style:入参,style是风格枚举值(Flat/Outline/Filled)。
参数说明:
style:QLCDNumber::SegmentStyle枚举值,支持Flat(平面)、Outline(轮廓)、Filled(填充)。
生效规则:
- 调用后立即生效,所有数字(无论进制)均采用该风格显示;
- 填充风格的数字颜色受控件的
foregroundRole(前景色)控制,可通过setStyleSheet()修改。
调用示例:
// 1. 填充风格(最醒目,适配老式计算器效果)
ui->lcdNumber->setSegmentStyle(QLCDNumber::Filled);
// 2. 平面风格(简约,适配现代界面)
ui->lcdNumber->setSegmentStyle(QLCDNumber::Flat);
// 3. 轮廓风格(默认,通用场景)
ui->lcdNumber->setSegmentStyle(QLCDNumber::Outline);
4.2 属性六:smallDecimalPoint(小小数点)------ 控制小数点尺寸的属性
4.2.1 属性的核心定义
smallDecimalPoint 属性用于设置 QLCDNumber 显示小数点时的尺寸大小,默认值为 false(常规尺寸小数点)。
通俗理解:smallDecimalPoint 就像 "小数点的大小开关"------ 如果开启(true),小数点会显示为更小的样式,视觉上更贴近老式液晶计算器的显示效果;如果关闭(false),小数点是常规尺寸。
这里有两个非常重要的点需要注意:
- 生效前提 :必须将显示模式设置为 十进制(QLCDNumber::Dec)------ 非十进制模式下无小数点,设置此属性无任何效果;
- 位数计算 :小小数点仅改变视觉尺寸,不影响
digitCount(数字位数)的统计------ 小数点仍占用 1 位。
4.2.2 数据类型
bool 类型,true 表示启用小小数点(尺寸更小),false 表示禁用(常规尺寸,默认)。
4.2.3 关联 API 详解(逐词逐句,零模糊)
1. 获取是否启用小小数点:bool smallDecimalPoint () const
函数原型:
bool QLCDNumber::smallDecimalPoint() const;
逐词逐句底层解析:
bool:返回值类型,返回是否启用小小数点模式;QLCDNumber:::成员函数;smallDecimalPoint():函数名,"获取是否启用小小数点" 的意思;const:常成员函数。
返回值说明:
true表示启用(小数点更小),false表示禁用(常规尺寸小数点);- 默认返回
false。
调用示例:
bool isSmallPoint = ui->lcdNumber->smallDecimalPoint();
qDebug() << "是否启用小小数点:" << isSmallPoint;
2. 设置是否启用小小数点:void setSmallDecimalPoint (bool small)
函数原型:
void QLCDNumber::setSmallDecimalPoint(bool small);
逐词逐句底层解析:
void:无返回值;QLCDNumber:::成员函数;setSmallDecimalPoint():函数名,"设置小小数点模式" 的意思;bool small:入参,small是true启用小小数点,false恢复常规尺寸。
参数说明:
small:true启用小小数点,false恢复常规尺寸;- 必须先将
mode设置为QLCDNumber::Dec(十进制),此属性才会生效。
生效规则:
- 调用后立即生效,仅在十进制模式下改变小数点的视觉尺寸;
- 小数点的显示位置不变,仍与数字对齐。
调用示例:
// 先切换到十进制(生效前提)
ui->lcdNumber->setMode(QLCDNumber::Dec);
// 启用小小数点
ui->lcdNumber->setSmallDecimalPoint(true);
// 显示带小数点的数值
ui->lcdNumber->display(3.14); // 显示带小尺寸小数点的 "3.14"
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,本文件我们来学习QLCDNumber的超级简单的两个属性
//digitCount属性和 smallDecimalPoint属性
//digitCount 显示几位数字.
//smallDecimalPoint 设置比较小的 小数点.
/**
* @property QLCDNumber::smallDecimalPoint
* @brief QLCDNumber的小数点尺寸控制属性
* @details 该属性用于设置QLCDNumber显示小数点时的尺寸大小,默认值为false(常规尺寸小数点);
* 设为true时,小数点会以更小的样式显示,视觉上更贴近老式液晶计算器的显示效果;
* 该属性仅在QLCDNumber的显示模式为**十进制(QLCDNumber::Dec)** 时生效,非十进制模式(Hex/Bin/Oct)无小数点,设置此属性无任何效果。
*
* 【关联API详解】
* 1. bool smallDecimalPoint() const
* - 功能:获取当前是否启用小小数点模式
* - 返回值:true表示启用(小数点更小),false表示禁用(常规尺寸小数点)
* - 调用示例:
* bool isSmallPoint = ui->lcdNumber->smallDecimalPoint();
*
* 2. void setSmallDecimalPoint(bool small)
* - 功能:开启/关闭小小数点显示模式
* - 参数:small - true启用小小数点,false恢复常规尺寸
* - 调用示例:
* ui->lcdNumber->setMode(QLCDNumber::Dec); // 先切换到十进制(生效前提)
* ui->lcdNumber->setSmallDecimalPoint(true); // 启用小小数点
* ui->lcdNumber->display(3.14); // 显示带小尺寸小数点的"3.14"
*
* 【关键注意事项】
* 1. 生效前提:必须将显示模式设置为十进制,非十进制模式下小数点不显示,此属性无效;
* 2. 位数计算:小小数点仅改变视觉尺寸,不影响digitCount(数字位数)的统计(小数点仍占用1位);
* 3. 视觉差异:小小数点仅缩小尺寸,不会改变小数点的显示位置,仍与数字对齐。
*
* ---
*
* @property QLCDNumber::digitCount
* @brief QLCDNumber的数字显示总位数属性
* @details 该属性用于设置QLCDNumber最多可显示的数字(含小数点)总位数,默认值为0(自适应位数,无限制);
* 若要显示的数字位数(含整数位、小数点、小数位)超过设置的digitCount,控件会显示"####"(溢出提示),需根据实际显示数值范围合理配置;
* 位数统计规则:整数位、小数点、小数位均计入总位数(如数值12.34,总位数为5:1、2、.、3、4)。
*
* 【关联API详解】
* 1. int digitCount() const
* - 功能:获取当前设置的最大显示位数
* - 返回值:int类型,0表示自适应(无位数限制),非0表示最大显示位数
* - 调用示例:
* int count = ui->lcdNumber->digitCount(); // 读取当前设置的显示位数
*
* 2. void setDigitCount(int numDigits)
* - 功能:设置最大显示位数
* - 参数:numDigits - 非负整数(0=自适应,>0=指定最大位数)
* - 调用示例:
* ui->lcdNumber->setDigitCount(5); // 设置最多显示5位
* ui->lcdNumber->display(12.34); // 总位数5(1+2+.+3+4),正常显示"12.34"
* ui->lcdNumber->display(123.456); // 总位数7(超过5),显示"#####"(溢出)
*
* 【关键注意事项】
* 1. 位数统计:小数点占用1位,负号(-)也占用1位(如-12.3的总位数为5:-、1、2、.、3);
* 2. 自适应模式:digitCount=0时,控件会根据数值自动调整显示宽度,不会出现溢出;
* 3. 进制适配:非十进制模式下(Hex/Bin/Oct),仅统计整数位(无小数点),超过位数仍显示"####";
* 4. 不足补位:若数值位数小于digitCount,控件会在左侧补空格(如digitCount=5,显示123 → " 123")。
*
* 【典型组合示例】
* // 需求:十进制显示、最多6位、小小数点、显示123.45
* ui->lcdNumber->setMode(QLCDNumber::Dec); // 十进制模式
* ui->lcdNumber->setDigitCount(6); // 最多6位
* ui->lcdNumber->setSmallDecimalPoint(true); // 小小数点
* ui->lcdNumber->display(123.45); // 总位数6(1+2+3+.+4+5),正常显示"123.45"
*
* // 测试溢出场景
* ui->lcdNumber->display(1234.567); // 总位数8(超过6),显示"######"
*/
//这个还是很简单的
QLCDNumber* lcdnumber = new QLCDNumber(this);
lcdnumber->setGeometry(100, 100, 200, 80); // 手动设置位置和大小,或用布局
lcdnumber->display(55.55);
lcdnumber->setDigitCount(5); // 至少 5 位才能完整显示 55.55
lcdnumber->setSmallDecimalPoint(true);
}
Widget::~Widget()
{
delete ui;
}
第五章 前置知识:为什么不能用循环和多线程实现周期性任务?
在讲 QTimer 之前,我们必须先搞懂一个非常重要的问题:为什么实现 "周期性修改界面状态"(比如每秒刷新一次倒计时),不能用 "循环 + sleep",也不能用 "多线程 + 循环 + sleep",必须用 QTimer?
这个问题是新手最容易踩的坑之一,几乎每个学 Qt 的人都试过用循环做倒计时,结果导致界面卡死,我们必须彻底搞懂原因,才能理解 QTimer 的重要性。
5.1 错误做法一:在构造函数中用 "循环 + sleep"
5.1.1 错误代码示例
很多新手会写这样的代码来实现倒计时:
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
#include <chrono>
#include <thread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLCDNumber *lcd = new QLCDNumber(this);
lcd->setGeometry(100, 100, 200, 80);
lcd->display(10);
// 错误做法:循环 + sleep
int value = 10;
while (true) {
// 休眠 1 秒
std::this_thread::sleep_for(std::chrono::seconds(1));
if (value <= 0) {
break;
}
value--;
lcd->display(value);
}
}
Widget::~Widget()
{
delete ui;
}
5.1.2 为什么这个代码不行?
这个代码看起来逻辑很对:初始值 10,每秒减 1,直到 0。但如果你运行这个代码,会发现界面根本不会显示,程序直接卡死,直到循环结束后界面才会一闪而过。
原因非常简单:Qt 的界面显示和事件处理依赖于 "事件循环"(Event Loop)。
通俗理解:Qt 的主线程就像一个 "餐厅服务员",它需要不停地循环处理各种事件(比如 "绘制界面""鼠标点击""键盘输入")------ 如果服务员一直在厨房等水开(执行 sleep),不出来处理客人的点餐(绘制界面),餐厅就会瘫痪(界面卡死)。
在上面的错误代码中,Widget 的构造函数是在主线程 中执行的,构造函数里的 while 循环和 sleep 会阻塞主线程的事件循环------ 在循环执行完之前,主线程根本没有机会去 "绘制界面",所以界面一直是空白的,程序看起来像 "卡死了" 一样。
5.2 错误做法二:在构造函数中另起一个线程,在新线程中用 "循环 + sleep"
5.2.1 错误代码示例
有些新手会想:"既然主线程不能阻塞,那我另起一个线程,在新线程里循环 + sleep,总行了吧?" 于是写了这样的代码:
#include "widget.h"
#include "ui_widget.h"
#include <QLCDNumber>
#include <chrono>
#include <thread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLCDNumber *lcd = new QLCDNumber(this);
lcd->setGeometry(100, 100, 200, 80);
lcd->display(10);
// 错误做法:另起线程,在新线程中修改 GUI
std::thread t([this, lcd]() {
int value = 10;
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
if (value <= 0) {
break;
}
value--;
// 错误:在子线程中修改 GUI 元素!
lcd->display(value);
}
});
t.detach(); // 分离线程,避免析构报错
}
Widget::~Widget()
{
delete ui;
}
5.2.2 为什么这个代码不行?
这个代码看起来解决了 "阻塞主线程" 的问题,但如果你运行这个代码,程序大概率会直接崩溃,或者出现奇怪的界面显示问题。
原因是 Qt 中有一个铁的规定 :任何对于 GUI 上内容的操作,必须在主线程中完成!
通俗理解:GUI 就像 "客厅的电视",主线程是 "客厅的主人",子线程是 "厨房的帮厨"------ 帮厨可以在厨房做饭(处理耗时任务),但不能直接跑到客厅改电视的频道(修改 GUI),否则会把客厅搞得一团糟(程序崩溃)。
为什么 Qt 要这么规定?因为 GUI 中的状态往往是 "牵一发动全身" 的 ------ 比如调整了某个元素的尺寸,就可能影响到内部的文字位置,或者其他元素的位置,这一连串的修改都需要按照一定的顺序来完成。而多线程的执行顺序是无法保障的,如果多个线程同时修改 GUI,就会导致状态混乱,程序崩溃。
因此,Qt 从根本上禁止了其他线程修改 GUI 状态,避免后续的一系列问题。
5.3 正确做法:使用 QTimer(定时器)
既然 "循环 + sleep" 和 "多线程" 都不行,那该怎么做呢?答案就是使用 QTimer(定时器)。
QTimer 是 Qt 基于事件循环 实现的定时器工具类,它完全非阻塞,不会占用主线程 ------ 你可以设置一个时间间隔(比如 1000 毫秒),QTimer 会每隔这么长时间,在主线程中触发一个 timeout() 信号,你只需要把 "修改界面" 的逻辑绑定到这个信号上,就能实现 "周期性修改界面状态" 的需求了。
通俗理解:QTimer 就像 "一个闹钟"------ 你把闹钟调到 "每 10 分钟响一次",闹钟响的时候(触发 timeout() 信号),你就去做一件事(比如刷新界面);在闹钟没响的时候,你可以继续做其他事(主线程继续处理事件循环,界面不会卡死)。
接下来,我们就详细讲解 QTimer 的所有核心属性、方法和信号。
第六章 QTimer 核心属性、方法与信号详解
QTimer 是 Qt 中实现定时触发逻辑的核心非阻塞定时器类,继承自 QObject,核心作用是在指定时间间隔后触发自定义逻辑(如周期性刷新界面、定时检测状态、延迟执行任务)。它支持 "周期性触发" 和 "单次触发" 两种模式,全程非阻塞,是 Qt 界面开发中最常用的定时工具。
6.1 QTimer 的核心特性(通俗版)
在讲具体属性之前,我们先快速了解一下 QTimer 的核心特性:
- 非阻塞:定时器运行时不阻塞主线程 / 事件循环,界面仍可正常交互;
- 灵活触发:支持 "周期性触发"(反复执行)和 "单次触发"(执行一次后停止);
- 线程适配 :可在任意线程使用(需该线程有事件循环),
timeout信号在定时器所在线程触发; - 精度限制 :定时器精度受系统调度影响,无法达到微秒级(高精度计时需用
QElapsedTimer)。
6.2 QTimer 的核心属性 / 枚举详解
6.2.1 属性一:interval(定时间隔,毫秒)
1. 属性的核心定义
interval 属性用于定义两次 timeout() 信号触发的时间间隔,单位是毫秒(1 秒 = 1000 毫秒),默认值为 1000ms(1 秒)。
通俗理解:interval 就像 "闹钟的间隔时间"------ 你设置 1000 毫秒,闹钟就每 1 秒响一次;设置 500 毫秒,就每 0.5 秒响一次。
这里有一个点需要注意:间隔设置需为非负整数 ------0 表示 "尽可能快触发",但不推荐(易占用大量 CPU 资源);设置后需重启定时器(start())才会生效。
2. 数据类型
int 类型,非负整数(单位:毫秒),默认值为 1000。
3. 关联 API 详解
// 获取当前定时间隔(毫秒)
int interval() const;
// 设置定时间隔(msec≥0,单位:毫秒)
void setInterval(int msec);
调用示例:
// 设置间隔为 500 毫秒(0.5 秒)
ui->timer->setInterval(500);
// 获取当前间隔
int currentInterval = ui->timer->interval();
qDebug() << "当前定时间隔:" << currentInterval << "毫秒";
6.2.2 属性二:singleShot(单次触发模式)
1. 属性的核心定义
singleShot 属性用于控制定时器是 "单次触发" 还是 "周期性触发",默认值为 false(周期性触发)。
通俗理解:singleShot 就像 "闹钟的模式开关"------ 如果设为 true(单次触发),闹钟只响一次就自动停止;如果设为 false(周期性触发),闹钟会按间隔持续响,直到你手动停止它。
一般来说,我们做倒计时、定时刷新界面这类 "周期性任务" 时,都设为 false(默认);做 "延迟执行一次任务" 时,设为 true,或者用 QTimer 的静态 singleShot 方法(更便捷)。
2. 数据类型
bool 类型,true 表示单次触发,false 表示周期性触发(默认)。
3. 关联 API 详解
// 获取是否为单次触发模式
bool isSingleShot() const;
// 设置触发模式(true=单次,false=周期性)
void setSingleShot(bool singleShot);
调用示例:
// 设为单次触发,触发一次后自动停止
ui->timer->setSingleShot(true);
// 获取当前模式
bool isSingle = ui->timer->isSingleShot();
qDebug() << "是否为单次触发:" << isSingle;
6.2.3 属性三:active(运行状态,只读)
1. 属性的核心定义
active 属性表示定时器是否处于 "运行中" 状态,默认值为 false(未启动)。
通俗理解:active 就像 "闹钟的开关状态"------true 表示闹钟开着(正在运行),false 表示闹钟关着(未启动)。
这个属性是只读 的 ------ 你不能直接设置它,只能通过 start()(启动)和 stop()(停止)方法控制它,用 isActive() 方法读取它。
2. 数据类型
bool 类型,true 表示正在运行,false 表示未启动(默认)。
3. 关联 API 详解
// 判断定时器是否正在运行
bool isActive() const;
调用示例:
if (ui->timer->isActive()) {
qDebug() << "定时器正在运行";
} else {
qDebug() << "定时器未启动";
}
6.2.4 枚举:TimerType(精度类型)
1. 枚举的核心定义
TimerType 枚举用于控制定时器的时间精度(受系统限制),不同精度适用于不同场景,精度越高,系统开销略大,默认值为 Qt::CoarseTimer。
通俗理解:TimerType 就像 "闹钟的精度"------ 有的闹钟精度高(误差 ±1 毫秒),有的精度低(误差 ±5%),你可以根据需求选择。
2. 枚举值详解(通俗版,一目了然)
| 枚举值 | 精度特点 | 适用场景 |
|---|---|---|
Qt::PreciseTimer |
高精度(误差 ±1ms) | 对时间精度要求高的场景(如定时采样) |
Qt::CoarseTimer |
粗精度(误差 ±5%) | 常规场景(如界面刷新,默认) |
Qt::VeryCoarseTimer |
极低精度(误差 ±1 秒) | 低精度需求(如定时保存数据) |
3. 关联 API 详解
// 获取当前精度类型
QTimer::TimerType timerType() const;
// 设置精度类型
void setTimerType(QTimer::TimerType atype);
6.3 QTimer 的核心方法详解
6.3.1 方法一:start (int msec = 0)------ 启动定时器的核心方法
1. 方法的核心定义
start() 是启动定时器的核心方法 ------ 调用后定时器进入 "运行中" 状态(isActive() 返回 true),开始按 interval 间隔触发 timeout() 信号。
通俗理解:start() 就像 "按下闹钟的启动按钮"------ 按下后,闹钟开始按设定的间隔响铃。
这里有两个点需要注意:
- 如果指定了
msec参数,会临时覆盖interval属性(仅本次启动生效); - 如果定时器已运行,调用
start()会先停止再重新启动(重置计时)。
2. 函数原型
void QTimer::start(int msec = 0);
逐词逐句底层解析:
void:无返回值;QTimer:::成员函数;start():函数名,"启动定时器" 的意思;int msec = 0:可选参数,临时间隔(毫秒),0 表示使用已设置的interval。
调用示例:
// 示例1:用已设置的 interval 启动
ui->timer->setInterval(1000); // 先设置间隔 1000ms
ui->timer->start(); // 启动,每 1000ms 触发一次
// 示例2:临时用 2000ms 间隔启动(仅本次生效)
ui->timer->start(2000); // 临时用 2000ms 间隔,不修改 interval 属性
6.3.2 方法二:stop ()------ 停止定时器的核心方法
1. 方法的核心定义
stop() 是停止定时器的核心方法 ------ 调用后定时器进入 "非活跃状态"(isActive() 返回 false),不再触发 timeout() 信号。
通俗理解:stop() 就像 "按下闹钟的停止按钮"------ 按下后,闹钟不再响铃。
这里有一个点需要注意:界面关闭前需调用 stop() 停止定时器,避免悬空信号导致程序崩溃。
2. 函数原型
void QTimer::stop();
调用示例:
// 如果定时器正在运行,就停止它
if (ui->timer->isActive()) {
ui->timer->stop();
qDebug() << "定时器已停止";
}
6.3.3 方法三:静态 singleShot ()------ 一次性定时器的便捷方法
1. 方法的核心定义
静态 singleShot() 是 QTimer 提供的一个静态便捷方法------ 它可以创建一个 "一次性定时器",无需手动实例化 QTimer,一行代码就能实现 "延迟执行一次任务"。
通俗理解:静态 singleShot() 就像 "一个只响一次的闹钟"------ 你设置延迟时间,到时间后它自动执行一次任务,然后自动销毁,非常方便。
这个方法非常常用,比如 "按钮点击后延迟 2 秒隐藏""延迟 3 秒显示提示语",都可以用它实现。
2. 函数原型(Qt5+ Lambda 写法)
// 静态便捷方法:创建一次性定时器
static void QTimer::singleShot(int msec, QObject *receiver, const char *member);
// Qt5+ 支持 Lambda 写法(更便捷)
static void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor);
参数说明(Qt5+ Lambda 写法):
msec:延迟时间(毫秒);context:上下文对象(通常传this,用于生命周期管理);functor:要执行的任务(可以是 Lambda 表达式、槽函数等)。
调用示例:
// 示例1:延迟 3 秒执行 Lambda 表达式
QTimer::singleShot(3000, this, [](){
qDebug() << "3 秒后执行";
});
// 示例2:按钮点击后延迟 2 秒隐藏按钮
connect(ui->btnHide, &QPushButton::clicked, this, [=](){
QTimer::singleShot(2000, ui->btnHide, &QPushButton::hide);
});
6.4 QTimer 的核心信号详解:timeout ()
6.4.1 信号的核心定义
timeout() 是 QTimer 唯一的核心信号 ------ 定时器运行时,每到 interval 设置的间隔就会触发该信号,需绑定槽函数处理具体业务逻辑。
通俗理解:timeout() 就像 "闹钟的响铃信号"------ 每到设定的间隔,闹钟就响一次(触发 timeout()),你听到铃声就去做一件事(执行槽函数)。
这里有两个点需要注意:
- 单次触发模式:仅触发一次该信号后定时器自动停止;
- 周期性模式 :持续触发该信号,直到调用
stop()停止。
6.4.2 信号绑定示例(Qt5+ Lambda)
// 创建 QTimer 实例
QTimer *timer = new QTimer(this);
// 设置间隔 1000ms(1 秒)
timer->setInterval(1000);
// 设置为周期性触发(默认,可省略)
timer->setSingleShot(false);
// 绑定 timeout 信号到 Lambda 表达式
connect(timer, &QTimer::timeout, this, [](){
qDebug() << "每秒触发一次";
});
// 启动定时器
timer->start();
6.5 QTimer 的关键注意事项(必知)
QTimer 虽然好用,但也有一些注意事项,新手很容易踩坑:
- 事件循环依赖 :QTimer 必须在有
QEventLoop(事件循环)的线程中使用 ------ 主线程默认有事件循环,子线程需手动调用exec()启动事件循环,否则timeout信号不会触发; - 精度限制 :不要依赖 QTimer 做高精度计时(如微秒级),高精度计时用
QElapsedTimer; - 内存管理 :QTimer 实例需指定父对象(如
this),避免内存泄漏; - 停止时机 :界面关闭前需调用
stop()停止定时器,避免悬空信号导致崩溃; - 间隔为 0 :
setInterval(0)表示 "尽可能快触发",但会占用大量 CPU,仅在特殊场景使用。
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
#include <QLCDNumber>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么本文件我们来实现一个倒计时的程序
//那么时间的显示就是借助QLCDNumber控件了~~~
//但是又要怎么让QLCDNumber显示的数值减少呢?尤其是要达到一秒钟减一次
//其实也是比较简单的,结合我们学习的qt中信号与槽的机制,我们完全可以通过一秒钟就触发一次的信号来进行设置
//每当这个信号触发一次,我们就在这个信号对应的槽函数中去将QLCDNumber显示的数值减一即可~~~
//那么每一秒中就触发一次的信号我们要从哪里获取呢???
//答案就是qt提供的一个经典的定时器:QTimer了~~~
/**
* @class QTimer
* @brief Qt中实现定时触发逻辑的核心非阻塞定时器类
* @details QTimer是Qt基于**事件循环**实现的定时器工具类,继承自QObject,核心作用是在指定时间间隔后触发自定义逻辑(如周期性刷新界面、定时检测状态、延迟执行任务);
* 支持"周期性触发"和"单次触发"两种模式,通过timeout()信号关联业务逻辑,全程非阻塞(不占用主线程),是Qt界面开发中最常用的定时工具;
* 区别于传统的阻塞式延时(如sleep()),QTimer完全基于Qt事件循环机制,不会导致界面卡顿,是定时任务的首选方案。
*
* 【核心特性(通俗版)】
* 1. 非阻塞:定时器运行时不阻塞主线程/事件循环,界面仍可正常交互;
* 2. 灵活触发:支持"周期性触发"(反复执行)和"单次触发"(执行一次后停止);
* 3. 线程适配:可在任意线程使用(需该线程有事件循环),timeout信号在定时器所在线程触发;
* 4. 精度限制:定时器精度受系统调度影响,无法达到微秒级(高精度计时需用QElapsedTimer)。
*
* 【核心属性/枚举详解】
*
* ===================================== 属性1:interval =====================================
* @property QTimer::interval
* @brief QTimer的定时间隔属性(毫秒)
* @details 该属性定义两次timeout()信号触发的时间间隔,默认值为1000ms(1秒);
* 间隔设置需为非负整数(0表示"尽可能快触发",但不推荐,易占用资源),设置后需重启定时器(start())才会生效。
*
* 【关联API】
* 1. int interval() const → 获取当前定时间隔(毫秒);
* 2. void setInterval(int msec) → 设置定时间隔(msec≥0,单位:毫秒);
* 这个是关键所在~~~
*
* 示例:
* ui->timer->setInterval(500); // 设置间隔为500毫秒(0.5秒)
*
* ===================================== 属性2:singleShot =====================================
* @property QTimer::singleShot
* @brief QTimer的单次触发模式属性
* @details 该属性控制定时器是"单次触发"还是"周期性触发",默认值为false(周期性触发);
* 设为true时,定时器启动后仅触发一次timeout()信号就自动停止;设为false时,会按interval间隔持续触发,一般来说我们都是设置为false的
*
* 【关联API】
* 1. bool isSingleShot() const → 获取是否为单次触发模式;
* 2. void setSingleShot(bool singleShot) → 设置触发模式(true=单次,false=周期性);
*
* 示例:
* ui->timer->setSingleShot(true); // 设为单次触发,触发一次后自动停止
*
* ===================================== 属性3:active =====================================
* @property QTimer::active
* @brief QTimer的运行状态属性(只读)
* @details 该属性表示定时器是否处于"运行中"状态,默认值为false(未启动);
* 无法直接设置,需通过start()/stop()方法控制,isActive()返回true表示定时器正在运行。
*
* 【关联API】
* bool isActive() const → 判断定时器是否正在运行;
*
* 示例:
* if (ui->timer->isActive()) {
* qDebug() << "定时器正在运行";
* }
*
* ===================================== 枚举:TimerType =====================================
* @enum QTimer::TimerType
* @brief QTimer的精度类型枚举,控制定时器的时间精度(受系统限制)
* @details 不同精度适用于不同场景,精度越高,系统开销略大,默认值为Qt::CoarseTimer。
*
* 【枚举值详解】
* | 枚举值 | 精度特点 | 适用场景 |
* |-------------------------|-----------------------------------|------------------------------|
* | Qt::PreciseTimer | 高精度(误差±1ms)| 对时间精度要求高的场景(如定时采样) |
* | Qt::CoarseTimer | 粗精度(误差±5%)| 常规场景(如界面刷新,默认)|
* | Qt::VeryCoarseTimer | 极低精度(误差±1秒)| 低精度需求(如定时保存数据)|
*
* 【关联API】
* 1. QTimer::TimerType timerType() const → 获取当前精度类型;
* 2. void setTimerType(QTimer::TimerType atype) → 设置精度类型;
*
* ===================================== 核心方法 =====================================
* 1. void start(int msec = 0)
* - 功能:启动定时器,若指定msec则临时覆盖interval属性(本次生效);
* - 参数:msec - 可选,临时间隔(毫秒),0表示使用已设置的interval;
* - 注意:若定时器已运行,调用start()会先停止再重新启动;
* - 示例:
* ui->timer->start(); // 用已设置的interval启动
* ui->timer->start(2000); // 临时用2000ms间隔启动
* 这个是重中之重,start了之后,定时器才会才是启动,信号才会开始触发~~~
*
* 2. void stop()
* - 功能:停止定时器,定时器进入非活跃状态(isActive()返回false);
* - 示例:
* if (ui->timer->isActive()) {
* ui->timer->stop(); // 停止运行中的定时器
* }
*
* 3. static void singleShot(int msec, QObject *receiver, const char *member)
* - 功能:静态便捷方法,创建"一次性定时器"(无需手动实例化QTimer);
* - 参数:
* - msec:延迟时间(毫秒);
* - receiver:接收信号的对象;
* - member:槽函数(需符合信号槽语法);
* - 优势:无需创建QTimer实例,一行代码实现延迟执行;
* - 示例:
* // 延迟3秒执行mySlot()槽函数
* QTimer::singleShot(3000, this, SLOT(mySlot()));
* // Qt5+ Lambda写法(更便捷)
* QTimer::singleShot(3000, this, [](){
* qDebug() << "3秒后执行";
* });
*
* 这个我们以后也会经常碰到~~~
*
* ===================================== 核心信号 =====================================
* @signal void QTimer::timeout()
* @brief 定时器到达指定间隔时触发的核心信号
* @details 定时器运行时,每到interval设置的间隔就会触发该信号,需绑定槽函数处理具体业务逻辑;
* 单次触发模式下,仅触发一次该信号后定时器自动停止;周期性模式下持续触发。
* 这个信号就是我们要使用的核心所在了
*
* 【信号绑定示例(Qt5+ Lambda)】
* QTimer *timer = new QTimer(this);
* timer->setInterval(1000); // 1秒间隔
* timer->setSingleShot(false); // 周期性触发
* connect(timer, &QTimer::timeout, this, [](){
* qDebug() << "每秒触发一次";
* });
* timer->start();
*
* 【关键注意事项(必知)】
* 1. 事件循环依赖:QTimer必须在有QEventLoop的线程中使用(主线程默认有,子线程需手动调用exec());
* → 子线程使用QTimer:需先启动线程的事件循环(thread->exec()),否则timeout信号不触发;
* 2. 精度限制:不要依赖QTimer做高精度计时(如微秒级),高精度计时用QElapsedTimer;
* 3. 内存管理:QTimer实例需指定父对象(如this),避免内存泄漏;
* 4. 停止时机:界面关闭前需调用stop()停止定时器,避免悬空信号导致崩溃;
* 5. 间隔为0:setInterval(0)表示"尽可能快触发",但会占用大量CPU,仅在特殊场景使用。
*
* 【典型使用场景示例】
* ===================================== 场景1:周期性刷新界面(如倒计时) =====================================
* QTimer *countdownTimer = new QTimer(this);
* int count = 10;
* countdownTimer->setInterval(1000); // 1秒间隔
* connect(countdownTimer, &QTimer::timeout, this, [&](){
* count--;
* ui->label->setText(QString::number(count));
* if (count == 0) {
* countdownTimer->stop(); // 倒计时结束停止定时器
* ui->label->setText("倒计时结束");
* }
* });
* countdownTimer->start();
*
* ===================================== 场景2:延迟执行任务(单次触发) =====================================
* // 按钮点击后延迟2秒隐藏
* connect(ui->btnHide, &QPushButton::clicked, this, [=](){
* QTimer::singleShot(2000, ui->btnHide, &QPushButton::hide);
* });
*/
//创建QLCDNumber控件
//因为要在槽函数中使用,所以我们要在头文件中申明,作为成员变量
lcdnumber=new QLCDNumber(this);
//设置初始值为10秒
lcdnumber->display(10);
//设置位置和大小
lcdnumber->setGeometry(300,300,200,200);
lcdnumber->setSegmentStyle(QLCDNumber::Filled); // 设置为实心段码,颜色效果更好
lcdnumber->setStyleSheet(R"(
QLCDNumber {
background-color: #1a1a1a;
border: 2px solid #333;
border-radius: 8px;
color: #00ffcc;
font-weight: bold;
}
)");
//创建QTimer对象~~~
//因为要在槽函数中使用,所以我们要在头文件中申明,作为成员变量
timer=new QTimer(this);
//设置间隔为1000ms,也就是1s
timer->setInterval(1000);
//绑定QTimer的timeout信号与我们创建的槽函数
connect(timer,&QTimer::timeout,this,&Widget::countdown);
// 启动 QTimer, 并且规定每隔 1000ms 触发一次 timeout 信号.
timer->start(1000);
}
//槽函数的实现
//void Widget::countdown()
//{
// qDebug() << "updateTime";
// int value = this->lcdnumber->intValue();
// if (value <= 0)
// {
// // 如果时间到, 停止定时器.
// timer->stop();
// return;
// }
// this->lcdnumber->display(value - 1);
//}
void Widget::countdown()
{
qDebug() << "updateTime";
int value = this->lcdnumber->intValue();
// 最后3秒变红闪烁逻辑
if (value <= 3 && value > 0) {
this->lcdnumber->setStyleSheet(R"(
QLCDNumber {
background-color: #2b0000;
border: 2px solid #ff0000;
border-radius: 8px;
color: #ff0000;
}
)");
} else if (value == 0) {
timer->stop();
// 时间到,变成红色常亮或特定样式
this->lcdnumber->setStyleSheet(R"(
QLCDNumber {
background-color: #000000;
border: 2px solid #ff0000;
border-radius: 8px;
color: #ff0000;
}
)");
return;
}
this->lcdnumber->display(value - 1);
}
Widget::~Widget()
{
delete ui;
}
第七章 综合实战:QLCDNumber + QTimer 实现倒计时程序
现在,我们把 QLCDNumber 和 QTimer 结合起来,实现一个完整的倒计时程序 ------ 需求是:10 秒倒计时,最后 3 秒数字变红闪烁(或者变红常亮),时间到停止定时器。
这个实战会覆盖我们之前讲的所有核心内容:QLCDNumber 的 display()、intValue()、setSegmentStyle()、setStyleSheet(),QTimer 的 setInterval()、start()、stop()、timeout() 信号,非常适合巩固学习。
7.1 需求分析
我们的需求很明确:
- 界面上有一个 QLCDNumber,初始显示 10;
- 用 QTimer 实现每秒减 1;
- 最后 3 秒(3、2、1)时,QLCDNumber 变成红色背景和红色数字;
- 时间到(0)时,停止定时器,保持红色样式。

7.2 代码实现
7.2.1 头文件(widget.h)
首先,我们需要在头文件中声明成员变量和槽函数:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QLCDNumber>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
// 声明槽函数:处理倒计时
private slots:
void countdown();
private:
Ui::Widget *ui;
// 成员变量:QLCDNumber 和 QTimer,方便在槽函数中访问
QLCDNumber *lcdnumber;
QTimer *timer;
};
#endif // WIDGET_H
7.2.2 源文件(widget.cpp)
然后,我们在源文件中实现构造函数和槽函数:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// ==========================================
// 1. 初始化 QLCDNumber
// ==========================================
lcdnumber = new QLCDNumber(this);
// 设置初始值为 10
lcdnumber->display(10);
// 设置位置和大小
lcdnumber->setGeometry(300, 300, 200, 200);
// 设置显示风格为填充风格(最醒目)
lcdnumber->setSegmentStyle(QLCDNumber::Filled);
// 设置初始样式表:深色背景,青绿色数字
lcdnumber->setStyleSheet(R"(
QLCDNumber {
background-color: #1a1a1a;
border: 2px solid #333;
border-radius: 8px;
color: #00ffcc;
font-weight: bold;
}
)");
// ==========================================
// 2. 初始化 QTimer
// ==========================================
timer = new QTimer(this);
// 设置间隔为 1000ms(1 秒)
timer->setInterval(1000);
// 绑定 timeout 信号与 countdown 槽函数
connect(timer, &QTimer::timeout, this, &Widget::countdown);
// 启动定时器
timer->start(1000);
}
// ==========================================
// 3. 实现 countdown 槽函数
// ==========================================
void Widget::countdown()
{
qDebug() << "updateTime";
// 获取当前显示的整数数值
int value = lcdnumber->intValue();
// 最后 3 秒变红逻辑
if (value <= 3 && value > 0) {
// 切换为红色样式
lcdnumber->setStyleSheet(R"(
QLCDNumber {
background-color: #2b0000;
border: 2px solid #ff0000;
border-radius: 8px;
color: #ff0000;
}
)");
} else if (value == 0) {
// 时间到,停止定时器
timer->stop();
// 保持红色样式
lcdnumber->setStyleSheet(R"(
QLCDNumber {
background-color: #000000;
border: 2px solid #ff0000;
border-radius: 8px;
color: #ff0000;
}
)");
return;
}
// 更新显示:数值减 1
lcdnumber->display(value - 1);
}
Widget::~Widget()
{
// 析构时停止定时器(虽然父对象销毁时会自动处理,但显式停止更安全)
if (timer->isActive()) {
timer->stop();
}
delete ui;
}
7.3 代码详解
我们来逐部分解释代码:
- 初始化 QLCDNumber :
- 创建 QLCDNumber 对象,设置初始值 10;
- 设置位置和大小,让它在界面中间;
- 设置显示风格为
Filled(填充风格,最醒目); - 设置初始样式表:深色背景,青绿色数字,看起来像老式计算器。
- 初始化 QTimer :
- 创建 QTimer 对象,设置间隔 1000ms(1 秒);
- 绑定
timeout信号到countdown槽函数 ------ 每 1 秒触发一次countdown(); - 启动定时器。
- 实现
countdown()槽函数 :- 获取当前 QLCDNumber 的整数值;
- 如果是最后 3 秒(3、2、1),切换样式表为红色背景和红色数字;
- 如果是 0,停止定时器,保持红色样式;
- 否则,数值减 1,更新显示。
完整示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么接下来我们来学习QLCDNumber控件
//这个控件比较简单,就是模拟老式计算器/液晶显示屏效果的数字专用显示控件,额,一般般吧
//我们简单学习即可~~~
/**
* @class QLCDNumber
* @brief Qt中模拟老式计算器/液晶显示屏效果的数字专用显示控件
* @details QLCDNumber是专门用于数字可视化展示的控件,核心特征是模拟"液晶数码管"显示效果(老式计算器/电子表风格);
* 支持整数/浮点数显示、多进制切换(十进制/十六进制/二进制/八进制)、显示风格自定义,是数值可视化展示的专用控件;
* 区别于QLabel显示数字,QLCDNumber对数字显示做了专属优化,仅支持数字/部分特殊字符(如小数点、负号),不支持文本。
*
* 【核心属性详解】
* QLCDNumber的数字显示逻辑由以下核心属性控制,需注意其值设置方法为display()(而非常规的setXxx()):
*
* ===================================== 属性1:intValue =====================================
* @property QLCDNumber::intValue
* @brief QLCDNumber显示的整数数值属性
* @details 该属性表示控件以整数形式展示的数字值,与value属性(浮点型)实时联动,默认值为0;
* 当设置value为浮点数时,intValue会自动四舍五入为整数(如value=1.5 → intValue=2,value=1.4 → intValue=1);
* 该属性无直接的setIntValue()方法,需通过display(int)或display(double)间接修改。
*
* 【关联API详解】
* 1. int intValue() const
* - 功能:获取当前显示的整数数值
* - 返回值:int类型,四舍五入后的整数结果
* - 示例:
* int currentInt = ui->lcdNumber->intValue(); // 读取整数数值
*
* 2. void display(int num)
* - 功能:设置intValue(核心方法,无setIntValue())
* - 参数:num - 待显示的整数
* - 示例:
* ui->lcdNumber->display(100); // intValue=100,value=100.0
*
* ===================================== 属性2:value =====================================
* @property QLCDNumber::value
* @brief QLCDNumber显示的浮点数值属性
* @details 该属性表示控件以浮点数形式展示的数字值,与intValue实时联动,默认值为0.0;
* 设置该属性需通过display(double)方法(无setValue()),仅在mode=Dec(十进制)时,小数点后内容才会显示;
* 若mode为非十进制(Hex/Bin/Oct),小数点后内容会被忽略,仅显示整数部分。
*
* 【关联API详解】
* 1. double value() const
* - 功能:获取当前显示的浮点数值
* - 返回值:double类型,原始浮点值(未四舍五入)
* - 示例:
* double currentDouble = ui->lcdNumber->value(); // 读取浮点数值
*
* 2. void display(double num)
* - 功能:设置value(核心方法,无setValue())
* - 参数:num - 待显示的浮点数
* - 示例:
* ui->lcdNumber->display(1.5); // value=1.5,intValue=2(四舍五入)
* ui->lcdNumber->setMode(QLCDNumber::Dec); // 十进制模式下显示"1.5"
* ui->lcdNumber->setMode(QLCDNumber::Hex); // 十六进制模式下仅显示"2"(忽略小数)
*
* 【intValue与value联动规则】
* - 设置display(int n) → value = n.0,intValue = n;
* - 设置display(double d) → value = d,intValue = 四舍五入后的整数;
* - 读取时intValue始终是value的四舍五入结果。
*
* ===================================== 属性3:digitCount =====================================
* @property QLCDNumber::digitCount
* @brief QLCDNumber的数字显示位数属性
* @details 该属性控制控件最多显示的数字位数(包含整数位+小数位),默认值为0(自适应位数);
* 若数字位数超过digitCount,控件会显示"####"(溢出提示),需根据显示数值范围合理设置。
*
* 【关联API详解】
* 1. int digitCount() const
* - 功能:获取当前设置的显示位数
* - 返回值:int类型,位数(默认0)
*
* 2. void setDigitCount(int numDigits)
* - 功能:设置显示的数字位数
* - 参数:numDigits - 位数(非负整数,0表示自适应)
* - 示例:
* ui->lcdNumber->setDigitCount(5); // 设置最多显示5位数字
* ui->lcdNumber->display(12345); // 正常显示"12345"
* ui->lcdNumber->display(123456); // 位数超限,显示"######"(溢出)
*
* ===================================== 属性4:mode =====================================
* @property QLCDNumber::mode
* @brief QLCDNumber的数字进制显示模式属性
* @details 该属性控制数字的显示进制格式,默认值为QLCDNumber::Dec(十进制);
* 仅十进制模式支持显示小数点后内容,其他进制仅显示整数部分(小数会被忽略)。
*
* 【枚举值详解(QLCDNumber::Mode)】
* | 枚举值 | 功能说明 |
* |-----------------|--------------------------------------------------------------------------|
* | QLCDNumber::Dec | 十进制模式:显示常规十进制数字,支持整数/浮点数(含小数点); |
* | QLCDNumber::Hex | 十六进制模式:以十六进制格式显示数字(0-9, A-F),仅支持整数; |
* | QLCDNumber::Bin | 二进制模式:以二进制格式显示数字(0/1),仅支持整数; |
* | QLCDNumber::Oct | 八进制模式:以八进制格式显示数字(0-7),仅支持整数; |
*
* 【关联API详解】
* 1. QLCDNumber::Mode mode() const
* - 功能:获取当前进制模式
* - 返回值:QLCDNumber::Mode枚举值
*
* 2. void setMode(QLCDNumber::Mode mode)
* - 功能:设置数字显示进制
* - 参数:mode - 进制枚举值
* - 示例:
* ui->lcdNumber->setMode(QLCDNumber::Hex); // 切换为十六进制
* ui->lcdNumber->display(255); // 显示"FF"
* ui->lcdNumber->setMode(QLCDNumber::Bin); // 切换为二进制
* ui->lcdNumber->display(8); // 显示"1000"
*
* 【关键注意事项】
* - 非十进制模式下,display(double)传入的浮点数会自动取整(如display(1.9) → 显示1的对应进制);
* - 进制切换后,digitCount的位数限制仍生效(如十六进制显示FF需设置digitCount≥2)。
*
* ===================================== 属性5:segmentStyle =====================================
* @property QLCDNumber::segmentStyle
* @brief QLCDNumber的数字显示风格属性
* @details 该属性控制液晶数字的视觉显示风格,默认值为QLCDNumber::Outline,核心影响数字的立体感/填充效果。
*
* 【枚举值详解(QLCDNumber::SegmentStyle)】
* | 枚举值 | 功能说明 |
* |---------------------|--------------------------------------------------------------------------|
* | QLCDNumber::Flat | 平面风格:数字无立体感,呈现在平坦的表面上,风格简约; |
* | QLCDNumber::Outline | 轮廓风格:数字有清晰的轮廓和轻微阴影,具备基础立体感(默认); |
* | QLCDNumber::Filled | 填充风格:数字被纯色填充,与背景对比强烈,立体感最强; |
*
* 【关联API详解】
* 1. QLCDNumber::SegmentStyle segmentStyle() const
* - 功能:获取当前显示风格
* - 返回值:QLCDNumber::SegmentStyle枚举值
*
* 2. void setSegmentStyle(QLCDNumber::SegmentStyle style)
* - 功能:设置数字显示风格
* - 参数:style - 风格枚举值
* - 示例:
* ui->lcdNumber->setSegmentStyle(QLCDNumber::Filled); // 填充风格显示
*
* ===================================== 属性6:smallDecimalPoint =====================================
* @property QLCDNumber::smallDecimalPoint
* @brief QLCDNumber的小数点尺寸属性
* @details 该属性控制小数点的显示尺寸,默认值为false(常规大小小数点);
* 设为true时,小数点会显示为更小的样式,仅在十进制模式下生效(非十进制无小数点)。
*
* 【关联API详解】
* 1. bool smallDecimalPoint() const
* - 功能:获取小数点是否为小尺寸
* - 返回值:true为小尺寸,false为常规尺寸
*
* 2. void setSmallDecimalPoint(bool small)
* - 功能:设置小数点显示尺寸
* - 参数:small - true启用小小数点,false禁用
* - 示例:
* ui->lcdNumber->setMode(QLCDNumber::Dec); // 十进制模式
* ui->lcdNumber->setSmallDecimalPoint(true); // 小尺寸小数点
* ui->lcdNumber->display(3.1415); // 显示带小小数点的数值
*
* 【典型使用示例】
* // 需求:模拟计算器显示,十进制、5位数字、填充风格、小小数点
* QLCDNumber* lcd = new QLCDNumber(this);
* lcd->setDigitCount(5); // 最多显示5位
* lcd->setMode(QLCDNumber::Dec); // 十进制
* lcd->setSegmentStyle(QLCDNumber::Filled); // 填充风格
* lcd->setSmallDecimalPoint(true); // 小小数点
* lcd->display(12.34); // 显示"12.34"(5位:1、2、.、3、4)
*
* // 切换为十六进制显示
* lcd->setMode(QLCDNumber::Hex);
* lcd->display(255); // 显示"FF"(5位不足补空格,显示" FF")
*/
}
Widget::~Widget()
{
delete ui;
}
第八章 全文总结与学习建议
恭喜你!终于看完了这篇 QLCDNumber 与 QTimer 常见属性详细解析!
如果你跟着文章一步步敲了代码,做了练习,那么现在你已经完全掌握了这两个工具的核心内容:
- 你会用 QLCDNumber 的
display()显示整数和浮点数,知道intValue和value的联动规则; - 你会用
digitCount控制显示位数,用mode切换进制,用segmentStyle改变显示风格,用smallDecimalPoint改变小数点尺寸; - 你知道了为什么不能用 "循环 + sleep" 和 "多线程" 实现周期性任务,必须用 QTimer;
- 你会用 QTimer 的
setInterval()、start()、stop(),会绑定timeout()信号,会用静态singleShot()实现延迟执行; - 你还完成了一个综合实战:用 QLCDNumber 和 QTimer 实现倒计时程序,包括最后 3 秒变红的逻辑。
毫不夸张地说,掌握了这些内容,你就掌握了 QLCDNumber 和 QTimer 开发的 90% 以上的需求!接下来,你可以用这些内容,实现各种你想要的数字显示和定时功能。
8.1 核心要点回顾
在结束之前,我们最后再回顾一下这篇文章的核心要点:
- QLCDNumber 核心要点 :
- 专门显示数字,模拟液晶数码管效果,仅支持数字 / 特殊字符;
- 设置数值用
display(int)或display(double),没有setValue()或setIntValue(); intValue和value实时联动,intValue是value四舍五入后的整数;- 仅十进制(
Dec)支持小数,非十进制忽略小数; digitCount控制显示位数,超限显示####,小数点、负号都占 1 位;segmentStyle控制显示风格(Flat/Outline/Filled),smallDecimalPoint控制小数点尺寸(仅十进制生效)。
- QTimer 核心要点 :
- 基于事件循环的非阻塞定时器,不能用循环 + sleep 或多线程修改 GUI;
interval控制定时间隔(毫秒),singleShot控制单次 / 周期性触发;start()启动定时器,stop()停止定时器,isActive()判断是否运行;- 核心信号是
timeout(),需绑定槽函数处理业务逻辑; - 静态
singleShot()是一次性定时器的便捷方法,无需实例化 QTimer; - 必须在有事件循环的线程中使用,高精度计时用
QElapsedTimer。
8.3 最后的话
编程学习没有捷径,唯手熟尔。QLCDNumber 和 QTimer 的属性虽然看起来很多,但只要你多敲代码、多做练习、多踩坑、多排查,很快就能熟练掌握。
这篇文章虽然很长,但我相信,如果你认真看完了,跟着敲了代码,你一定会对 QLCDNumber 和 QTimer 有一个极其深刻的理解,再也不会为数字显示和定时任务发愁。
感谢你阅读这篇文章,希望它能帮到你。我们下一篇 Qt 教程再见!