对于Qt:QLCDNumber常见属性以及QTimer的解析

开篇介绍:

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。

它们的联动规则非常重要,必须牢记:

  1. 当调用 display(int num) 设置整数时 :
    • value 会自动变为 num.0(比如 display(10) → intValue=10,value=10.0);
    • intValue 就是你设置的整数 num,没有四舍五入(因为输入本身是整数)。
  2. 当调用 display(double num) 设置浮点数时 :
    • value 会保留你设置的原始浮点值 num;
    • intValue 会自动对 num 进行标准数学四舍五入 (比如 display(1.5) → intValue=2,display(1.4) → intValue=1,display(2.49) → intValue=2)。
  3. 读取属性时 :
    • 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)。

这里有两个非常重要的点需要注意:

  1. 仅十进制支持小数 :只有 mode=QLCDNumber::Dec(十进制)时,小数点后内容才会显示;非十进制模式(Hex/Bin/Oct)下,小数部分会被自动忽略,仅显示整数部分;
  2. 负数处理 :仅十进制支持显示负号(-);非十进制模式下,负数会被转为无符号数后显示(比如 -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),小数点是常规尺寸。

这里有两个非常重要的点需要注意:

  1. 生效前提 :必须将显示模式设置为 十进制(QLCDNumber::Dec)------ 非十进制模式下无小数点,设置此属性无任何效果;
  2. 位数计算 :小小数点仅改变视觉尺寸,不影响 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 的核心特性:

  1. 非阻塞:定时器运行时不阻塞主线程 / 事件循环,界面仍可正常交互;
  2. 灵活触发:支持 "周期性触发"(反复执行)和 "单次触发"(执行一次后停止);
  3. 线程适配 :可在任意线程使用(需该线程有事件循环),timeout 信号在定时器所在线程触发;
  4. 精度限制 :定时器精度受系统调度影响,无法达到微秒级(高精度计时需用 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 虽然好用,但也有一些注意事项,新手很容易踩坑:

  1. 事件循环依赖 :QTimer 必须在有 QEventLoop(事件循环)的线程中使用 ------ 主线程默认有事件循环,子线程需手动调用 exec() 启动事件循环,否则 timeout 信号不会触发;
  2. 精度限制 :不要依赖 QTimer 做高精度计时(如微秒级),高精度计时用 QElapsedTimer;
  3. 内存管理 :QTimer 实例需指定父对象(如 this),避免内存泄漏;
  4. 停止时机 :界面关闭前需调用 stop() 停止定时器,避免悬空信号导致崩溃;
  5. 间隔为 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 需求分析

我们的需求很明确:

  1. 界面上有一个 QLCDNumber,初始显示 10;
  2. 用 QTimer 实现每秒减 1;
  3. 最后 3 秒(3、2、1)时,QLCDNumber 变成红色背景和红色数字;
  4. 时间到(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 代码详解

我们来逐部分解释代码:

  1. 初始化 QLCDNumber :
    • 创建 QLCDNumber 对象,设置初始值 10;
    • 设置位置和大小,让它在界面中间;
    • 设置显示风格为 Filled(填充风格,最醒目);
    • 设置初始样式表:深色背景,青绿色数字,看起来像老式计算器。
  2. 初始化 QTimer :
    • 创建 QTimer 对象,设置间隔 1000ms(1 秒);
    • 绑定 timeout 信号到 countdown 槽函数 ------ 每 1 秒触发一次 countdown();
    • 启动定时器。
  3. 实现 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 核心要点回顾

在结束之前,我们最后再回顾一下这篇文章的核心要点:

  1. QLCDNumber 核心要点 :
    • 专门显示数字,模拟液晶数码管效果,仅支持数字 / 特殊字符;
    • 设置数值用 display(int) 或 display(double),没有 setValue() 或 setIntValue();
    • intValue 和 value 实时联动,intValue 是 value 四舍五入后的整数;
    • 仅十进制(Dec)支持小数,非十进制忽略小数;
    • digitCount 控制显示位数,超限显示 ####,小数点、负号都占 1 位;
    • segmentStyle 控制显示风格(Flat/Outline/Filled),smallDecimalPoint 控制小数点尺寸(仅十进制生效)。
  2. QTimer 核心要点 :
    • 基于事件循环的非阻塞定时器,不能用循环 + sleep 或多线程修改 GUI;
    • interval 控制定时间隔(毫秒),singleShot 控制单次 / 周期性触发;
    • start() 启动定时器,stop() 停止定时器,isActive() 判断是否运行;
    • 核心信号是 timeout(),需绑定槽函数处理业务逻辑;
    • 静态 singleShot() 是一次性定时器的便捷方法,无需实例化 QTimer;
    • 必须在有事件循环的线程中使用,高精度计时用 QElapsedTimer。

8.3 最后的话

编程学习没有捷径,唯手熟尔。QLCDNumber 和 QTimer 的属性虽然看起来很多,但只要你多敲代码、多做练习、多踩坑、多排查,很快就能熟练掌握。

这篇文章虽然很长,但我相信,如果你认真看完了,跟着敲了代码,你一定会对 QLCDNumber 和 QTimer 有一个极其深刻的理解,再也不会为数字显示和定时任务发愁。

感谢你阅读这篇文章,希望它能帮到你。我们下一篇 Qt 教程再见!

相关推荐
xiaoye-duck1 小时前
《C++ 工具库实战》C++ 解析利器 JsonCpp:从基础使用到封装简易 JSON 工具
c++·json·第三方库
SEO-狼术1 小时前
Aspose.Email for .NET 26 Crack
运维·服务器
dialect_9 小时前
KMP算法
开发语言·c++·算法
captain3769 小时前
MyBatis(入门5)其他查询操作
java·数据库·spring boot·mybatis
无足鸟ICT10 小时前
【RHCA+】vmstat命令(监控系统资源)
linux·服务器
垆边人似月.10 小时前
RDMA 文件传输踩坑(五):READY 发送成功后,为什么出现 Work Request Flushed Error?
服务器·网络·tcp/ip
闪亮的路灯10 小时前
Linux 安装mqtt服务mosquitto
linux·运维·服务器
HideF10 小时前
nmcli
linux·服务器·网络
小此方10 小时前
Re:Mysql数据库基础篇(八):详细讲解复合查询、多表查询、自连接、多行、多列子查询与合并查询
数据库·mysql