【Qt开发】显示类控件(二)-> QLCDNumber

目录

[1 -> 概览](#1 -> 概览)

[2 -> 核心属性](#2 -> 核心属性)

[3 -> 核心功能与特性](#3 -> 核心功能与特性)

[4 -> 经典应用场景](#4 -> 经典应用场景)

[5 -> 优点和局限性](#5 -> 优点和局限性)

[6 -> 代码示例:倒计时](#6 -> 代码示例:倒计时)

[7 -> 总结](#7 -> 总结)


1 -> 概览

在构建现代软件界面时,开发者不仅追求功能强大,也日益注重视觉表现和用户体验。有时,为了契合特定主题(如工业控制、音频播放器、科学实验模拟或经典游戏),我们需要一种能够瞬间唤起用户时代感或专业感的界面元素。Qt 框架中的 **QLCDNumber**控件,正是为此而生的经典组件。

QLCDNumber 是一个用于显示数字的小部件。其核心设计理念是模拟老式的七段数码管**(Seven-segment display)** 或点阵式液晶显示**(LCD)** 效果。这种显示方式在计算器、电子钟表、仪器仪表等领域极为常见。它不像普通的标签**(QLabel)**那样直接渲染字体,而是通过点亮特定的"段"来组合成数字或少量字母,从而呈现出一种独特的、带有浓厚技术复古风的视觉效果。

2 -> 核心属性

|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 说明 |
| intValue | QLCDNumber 显示的数字值(int) |
| value | QLCDNumber 显示的数字值(double) 和 intValue 是联动的 例如给 value 设为 1.5,intValue 的值就是 2 另外,设置 value 和 intValue 的方法名字为 display,而不是 setValue 或者 setIntValue |
| digitCount | 显示几位数字 |
| mode | 数字显示形式 1. QLCDNumber::Dec:十进制模式,显示常规的十进制数字 2. QLCDNumber::Hex:十六进制模式,以十六进制格式显示数字 3. QLCDNumber::Bin:二进制模式,以二进制格式显示数字 4. QLCDNumber::Oct:八进制模式,以八进制格式显示数字 只有十进制的时候才能显示小数点后的内容 |
| segmentStyle | 设置显示风格 1. QLCDNumber::Flat:平面的显示风格,数字呈现在一个平坦的表面上 2. QLCDNumber::Outline:轮廓显示风格,数字具有清晰的轮廓和阴影效果 3. QLCDNumber::Filled:填充显示风格,数字被填充颜色并与背景区分开 |
| smallDecimalPoint | 设置比较小的小数点 |

3 -> 核心功能与特性

1. 数字显示

**QLCDNumber**最主要的功能是清晰地显示整型或浮点型数字。它可以自动处理数字的对齐方式(通常为右对齐),并支持显示一个额外的小数点。

2. 数码位数设置

开发者可以预先设定控件能够显示的数码位数。当数字的整数部分超出设定位数时,控件会显示溢出(通常为一连串的"E"或类似提示);当数字位数不足时,则会在左侧以零或空格进行填充,这非常符合传统电子设备的显示习惯。

3. 多种显示模式

控件提供了几种经典的显示模式,允许开发者根据整体UI风格进行选择:

  • 十六进制(Hex):可以显示数字0-9和字母A-F,适用于需要显示内存地址等信息的场景。

  • 十进制(Dec):最常用的模式,用于显示常规数字。

  • 八进制(Oct):显示八进制数字。

  • 二进制(Bin):以二进制形式显示数字,每一位都清晰可见。

4. 视觉风格定制

  • 段样式(Segment Style)QLCDNumber 允许选择数码管的视觉风格,例如"轮廓(Outlined)"、"填充(Filled)"和"扁平(Flat)",以适应不同深浅的背景色,确保显示清晰易读。

  • 颜色:虽然传统LCD是单色的(通常是深色背景上的亮色数字),但Qt允许你设置任意颜色作为数字("段")的颜色和背景色,从而创造出诸如暗黑模式下的绿色数字、复古的琥珀色或现代感的蓝色效果。

5. 溢出与特殊值处理

当显示的数字超出控件范围或为非数值(NaN)时,控件会有一个明确的视觉指示(如显示"E"),这为调试和用户提示提供了便利。

4 -> 经典应用场景

  • 计时器/秒表 :显示经过的时间或剩余时间,是 QLCDNumber 最经典的应用。

  • 媒体播放器:显示当前播放进度和总时长,完美复刻了传统音响设备的UI。

  • 计算器应用:作为计算结果的显示区域,是其最原始、最自然的用途。

  • 工业控制与仪表盘模拟:显示温度、转速、压力等实时数据,营造出专业的工业HMI(人机交互界面)氛围。

  • 游戏界面:在赛车游戏中显示速度,在模拟游戏中显示分数或资源数量,能有效增强游戏的特定时代感或科技感。

  • 系统监控工具:显示CPU占用率、内存使用量等数值信息。

5 -> 优点和局限性

优点

  • 风格独特:能快速为应用界面确立特定的视觉基调,这是使用标准字体无法轻易实现的。

  • 清晰可读:在高亮或大尺寸显示下,LCD风格的数字非常醒目,易于远距离或快速识别。

  • 轻量级:作为Qt内置控件,它非常高效,无需依赖外部资源。

局限性

  • 显示内容有限:基本上只能用于显示数字和极有限的字母(A-F, 'E'等),无法显示普通文本或复杂符号。

  • 风格固定:其外观是高度风格化的,如果与应用的整体现代扁平设计风格不搭,则会显得格格不入。它更适合作为"点睛之笔"而非主要信息展示控件。

6 -> 代码示例:倒计时

1. 在界面上创建一个 QLCDNumber,初始值设为 10

objectName 设为默认

2. 修改 widget.h 代码,创建一个 QTimer 成员,和一个 handle 函数

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void handle();

private:
    Ui::Widget *ui;
    QTimer* timer;
};
#endif // WIDGET_H

3. 修改 widget.cpp,在构造函数中初始化 QTimer

  • QTimer 表示定时器。通过 start 方法启动定时器之后,就会每隔一定周期,触发一次 QTimer::timeout 信号。
  • 使用 connect 把 QTimer::timeout 信号和 Widget::handle 连接起来,意味着每次触发 QTimer::timeout 都会执行 Widget::handle。
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>
#include <QTimer>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置初始值
    ui->lcdNumber->display(20);

    // 创建一个 QTimer 实例
    timer = new QTimer(this);

    // 把 QTimer 的 timeout 信号和咱们自己的槽函数进行连接
    connect(timer, &QTimer::timeout, this, &Widget::handle);

    // 启动定时器, 参数是触发 timeout 的周期. 单位是 ms
    timer->start(1000);

}

Widget::~Widget()
{
    delete ui;
}

4. 修改 widget.cpp,实现 handle

  • 通过 intValue 获取到 QLCDNumber 内部的数值。
  • 如果 value 的值归 0 了,就停止 QTimer。接下来 QTimer 也就不会触发 timeout 信号了。
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>
#include <QTimer>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置初始值
    ui->lcdNumber->display(20);

    // 创建一个 QTimer 实例
    timer = new QTimer(this);

    // 把 QTimer 的 timeout 信号和咱们自己的槽函数进行连接
    connect(timer, &QTimer::timeout, this, &Widget::handle);

    // 启动定时器, 参数是触发 timeout 的周期. 单位是 ms
    timer->start(1000);

}

Widget::~Widget()
{
    delete ui;
}

void Widget::handle()
{
    // 测试
    // qDebug() << "handle";
    int value = ui->lcdNumber->intValue();
    if (value <= 0)
    {
        timer->stop();
        return;
    }

    ui->lcdNumber->display(value - 1);

}

5. 执行程序,可以看到每隔一秒钟,显示的数字就减少 1

针对上述代码,存在两个问题:

1. 上述代码如果直接在 Widget 构造函数中,通过一个循环 + sleep 的方式是否可以呢?

cpp 复制代码
int value = ui->lcdNumber->intValue();
    while (true) 
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        if (value <= 0) 
        {
            break;
        }
        
        ui->lcdNumber->display(value - 1);
    }

显然,这个代码是不行的。循环会使 Widget 的构造函数无法执行完毕,此时的界面是不能正确构造和显示的。

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

cpp 复制代码
std::thread t([this]() 
    {
        int value = this->ui->lcdNumber->intValue();
        while (true) 
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            if (value <= 0) 
            {
                break;
            }
            
            this->ui->lcdNumber->display(value - 1);
        }
    });

这个代码同样是不行的。Qt 中规定,任何对于 GUI 上内容的操作,必须在 主线程中完成。像 Widget 构造函数,以及 connect 连接的 slot 函数,都是在主线程中调用的。而自己创建的线程则不是。

当我们自己的线程中尝试对界面元素进行修改时,Qt 程序往往会直接崩溃。

这样的约定主要是因为 GUI 中的状态往往是牵一发动全身的,修改一个地方,就需要同步的对其他内容进行调整。

比如调整了某个元素的尺寸,就可能影响到内部的文字位置,或者其他元素的位置。这里一连串的修改,都是需要按照一定的顺序来完成的。

由于多线程执行的顺序无法保障,因此,Qt 从根本上禁止了其他线程修改 GUI 状态,避免后续的一系列问题。

综上所述,使用定时器,是实现上述功能的最合理方案。

7 -> 总结

QLCDNumber 是Qt工具箱中一个极具特色的控件。它远不止是一个简单的数字显示器,更是一个强大的 "氛围营造者"。当你需要为用户界面添加一丝复古科技感、专业仪器感或清晰的数字焦点时,**QLCDNumber**是一个简单而高效的选择。它省去了开发者用图像自己绘制数字的麻烦,通过简单的属性设置就能达到出色的视觉效果,是 Qt 为丰富开发者界面表达能力所提供的一件精致而实用的工具。


感谢各位大佬支持!!!

互三啦!!!

相关推荐
蒋星熠2 小时前
中间件架构设计与实践:构建高性能分布式系统的核心基石
开发语言·数据库·分布式·python·中间件·性能优化·硬件工程
励志不掉头发的内向程序员2 小时前
STL库——AVL树
开发语言·c++·学习
晨非辰4 小时前
#C语言——刷题攻略:牛客编程入门训练(十一):攻克 循环控制(三),轻松拿捏!
c语言·开发语言·经验分享·学习·visual studio
励志码农6 小时前
JavaWeb 30 天入门:第二十三天 —— 监听器(Listener)
java·开发语言·spring boot·学习·servlet
天高云淡ylz6 小时前
子网掩码的隐形陷阱:为何能ping通却无法HTTPS访问
开发语言·php
希望20179 小时前
Golang Panic & Throw & Map/Channel 并发笔记
开发语言·golang
朗迹 - 张伟9 小时前
Golang安装笔记
开发语言·笔记·golang
yzx9910139 小时前
生活在数字世界:一份人人都能看懂的网络安全生存指南
运维·开发语言·网络·人工智能·自动化
小周同学@9 小时前
谈谈对this的理解
开发语言·前端·javascript