欢迎光临
我们一直在努力

Qt 解析并显示rt-thread输出的彩色日志源码分享

Qt 解析并显示rt-thread输出的彩色日志源码分享

  • 一、ANSI Color Code(ANSI SGR 颜色码)介绍
    • 1、📌 基础格式
    • 2、 🎨 常用 SGR 参数组合
      • 1️⃣ 文本字体效果
      • 2️⃣ 基础文本颜色(8色)
      • 3️⃣ 背景颜色(8色)
      • ✳️ 256色扩展模式
      • ✴️ 真彩模式
    • 3、💡 典型应用场景
    • 4、🛠️ 注意事项
    • 5、编程支持示例代码
  • 二、rt-thread ulog组件介绍
    • 1、什么是ulog组件?
    • 2、主要功能和特点
    • 3、如何在RT-Thread中使用ulog?
    • 4、 示例代码
  • 三、源码分享
    • 1、效果展示
    • 2、源码分享
    • 2.1、rt-thread串口接收格式
      • 2.2、mainwindow.h
      • 2.3、mainwindow.h

在这里插入图片描述

一、ANSI Color Code(ANSI SGR 颜色码)介绍

ANSI SGR(Select Graphic Rendition)颜色码,它是文本终端中广泛使用的转义序列标准中的一部分,主要用于控制终端显示文本的样式(如颜色、背景、字体效果等)。该标准由 ANSI X3.64 定义。


1、📌 基础格式

每条样式控制命令以 ESC [ 开头(ESC 为 ASCII 缩写,十进制为 27,十六进制 \\x1b),后接数字参数(参数间用 ; 分隔),最后以 m 结尾。大多数编程语言中以 \\033[…] 或 \\u001B[…] 表示。

通用模板: \\033[<参数1>;<参数2>;…;<参数N>m

例如:红色文本 + 加粗: \\033[1;31m


2、 🎨 常用 SGR 参数组合

1️⃣ 文本字体效果

参数状态描述
0 重置 清除所有样式
1 加粗 / 高亮 ✅ 建议使用
2 淡色 ✅ 效果有限
3 斜体 ✅ 常用
4 下划线 ✅ 常用
5 闪烁 ✘ 老旧使用
7 反色 ✅ 常见
9 删除线 🟡 支持有限

2️⃣ 基础文本颜色(8色)

参数颜色描述
30 黑色 🖤🖤
31 红色 ❤️❤️
32 绿色 💚💚
33 黄色 💛💛
34 蓝色 💙💙
35 粉色 💜💜
36 青色 🟩🟩
37 白色 ◯◯

示例代码:

print("\\033[31m红色文本示例: Hello \\033[m") # \\033[m 用于重置


3️⃣ 背景颜色(8色)

参数背景颜色文本渲染效果
40 黑色背景 ❤️🖤
41 红色背景 ❤️❤️
42 绿色背景 🟢🟢
43 黄色背景 🔶🔶
44 蓝色背景 💙💙
45 粉背景 🟣🟣
46 青背景 🟦🟦
47 白背景 ▫️▫️

示例:红字绿底且加粗: \\033[1;32;41m重磅消息\\033[0m


✳️ 256色扩展模式

现代终端大多支持256色模式,使用如下格式:

# 文本颜色
\\033[38;5;<颜色索引>m
# 背景颜色
\\033[48;5;<颜色索引>m

其中 <颜色索引> 取值范围:

  • 0-15:传统16色
  • 16-231:6×6×6 RGB 颜色(大大扩充)
  • 232-255:24阶灰度(黑→白)

示例:显示RGB色表索引为201的文本颜色:

# 终端中使用
echo -e "\\033[38;5;201m流光紫 \\033[0m"


✴️ 真彩模式

支持RGB真彩色调,格式如下:

\\033[38;2;<R>;<G>;<B>m # 文字颜色调整
\\033[48;2;<R>;<G>;<B>m # 背景颜色设置

其中 <R>, <G>, <B> 均指0-255之间的值。

例如涂蓝文本并蓝色背景:

print("\\033[38;2;0;120;255m蓝宝库\\033[0m")


3、💡 典型应用场景

  • 日志染色支持:命令行工具的输出着色(如 Python logger、Node.js winston)
  • 终端工具美化:Git/Terraform/Docker等提示文本
  • CLI界面:交互命令行界面(如常见服务器面板)依次进行多类样式分类
  • 现代Shell工具(如PowerShell, zsh)均支持ANSI转义序列显示美观界面。


    4、🛠️ 注意事项

    • 兼容性差异:并非每个终端都能对所有参数(尤其5xxx级高阶代码)正确处理
    • 嵌套复位:建议在使用后立刻加入 \\033[0m 以防后续文字渲染混乱
    • 性能开销:文本级渲染转义代码每次输出都会造成本地重复渲染开销

    5、编程支持示例代码

    class Color:
    reset = '\\033[0m'
    bold = '\\033[1m'
    underline = '\\033[4m'
    red = '\\033[31m'
    green = '\\033[32m'
    blue = '\\033[94m'

    print(Color.red + "重要警告" + Color.reset + Color.bold + "请注意" + Color.reset)


    ✅ 欲深入了解拓展参数表和颜色空间转换函数可参考ANSI官方手册。如有疑问请随时咨询!

    二、rt-thread ulog组件介绍

    1、什么是ulog组件?

    ulog是RT-Thread中的一个标准化日志管理模块,用于记录系统运行时的调试信息、警告和错误。它提供了一种高效的方式来输出日志数据,方便开发者排查问题和监控系统状态。ulog的核心目标是减少资源占用,同时保持灵活性和扩展性,适合嵌入式设备开发。

    2、主要功能和特点

    ulog组件具有以下关键特性:

    • 线程安全:在多线程环境中安全输出日志数据,避免竞争条件。
    • 多级日志机制:通过设置不同的日志级别来控制输出信息,有效管理日志内容:
      • 日志级别包括:DEBUG(调试)、INFO(信息)、WARN(警告)、ERROR(错误)等。
    • 可插拔的后端输出:ulog支持多种输出模式和格式,包括:
      • 串口控制台:这是最常见的输出方式,适用于开发阶段。
      • 外部文件系统:可以将日志保存到SD卡或Flash中。
      • 用户定义的自定义输出:开发者可以扩展ulog接口,将日志转到自定义设备如USB或网络。
    • 高效的内存使用:ulog设计紧凑,避免了不必要的内存开销,适合资源有限的MCU(微控制器单元)。

    3、如何在RT-Thread中使用ulog?

    为了在RT-Thread系统中启用ulog组件,开发者需要配置和调用相关API。具体步骤如下:

    • 启用ulog组件:在RT-Thread配置文件中(如Kconfig或SCons),开启ulog支持。
    • 设置日志级别:通过API设置全局日志级别,例如设置为INFO级别,则只会输出INFO及以上级别的日志。
    • 输出日志信息:在代码中使用ulog提供的模块接口来输出日志。
    • 配置日志过滤:开发者可以为特定模块或线程设置日志过滤规则,突出关键信息。

    4、 示例代码

    以下是一个使用RT-Thread ulog组件的C代码示例。假设已启用ulog,代码展示了如何在应用中记录日志:

    #include <rtthread.h>
    #include <ulog.h> // 引入ulog库

    void sample_task(void)
    {
    LOG_D("这是一条DEBUG级别的日志"); // DEBUG级别日志
    LOG_I("这是一条INFO级别的日志"); // INFO级别日志
    LOG_W("这是一条WARN级别的日志"); // WARN级别日志
    LOG_E("这是一条ERROR级别的日志"); // ERROR级别日志
    }

    int main(void)
    {
    // 创建任务并导出到线程
    rt_thread_t tid = rt_thread_create("sample", sample_task, RT_NULL, 512, 5, 10);
    rt_thread_startup(tid);
    return 0;
    }

    在这个示例中:

    • LOG_D, LOG_I, LOG_W, LOG_E 是ulog的宏定义,分别输出DEBUG、INFO、WARN、ERROR级别的日志。
    • 开发者可以在线程任务中直接调用这些接口,日志会根据设置输出到后端(如串口)。

    三、源码分享

    1、效果展示

    在这里插入图片描述

    2、源码分享

    2.1、rt-thread串口接收格式

    串口接收的数据格式为:

    1. 绿色 32
    字符串:
    \\x1B[0m\\x1B[32m0101 10:51:53 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 33 32 6d 30 31 2d 30 31 20 31 30 3a 35 31 3a 35 33 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d
    2. 红色 31
    字符串:
    \\x1B[0m\\x1B[31m0101 10:51:54 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 33 31 6d 30 31 2d 30 31 20 31 30 3a 35 31 3a 35 34 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d
    3. 黄色 33
    字符串:
    \\x1B[0m\\x1B[33m0101 10:51:55 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 33 33 6d 30 31 2d 30 31 20 31 30 3a 35 31 3a 35 35 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d
    4. 蓝色 34
    字符串:
    \\x1B[0m\\x1B[34m0101 10:51:56 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 33 34 6d 30 31 2d 30 31 20 31 30 3a 35 31 3a 35 36 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d
    5. 紫色 35
    字符串:
    \\x1B[0m\\x1B[35m0101 10:51:57 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 33 35 6d 30 31 2d 30 31 20 31 30 3a 35 31 3a 35 37 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d
    6. 青色 36
    字符串:
    \\x1B[0m\\x1B[36m0101 10:51:58 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 33 36 6d 30 31 2d 30 31 20 31 30 3a 35 31 3a 35 38 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d
    7. 亮红 91
    字符串:
    \\x1B[0m\\x1B[91m0101 10:51:59 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 39 31 6d 30 31 2d 30 31 20 31 30 3a 35 31 3a 35 39 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d
    8. 亮绿 92
    字符串:
    \\x1B[0m\\x1B[92m0101 10:52:00 I/mavlink_comm: mavlink active!\\r\\r\\n\\x1B[0m
    HEX:
    1b 5b 30 6d 1b 5b 39 32 6d 30 31 2d 30 31 20 31 30 3a 35 32 3a 30 30 20 49 2f 6d 61 76 6c 69 6e 6b 5f 63 6f 6d 6d 3a 20 6d 61 76 6c 69 6e 6b 20 61 63 74 69 76 65 21 0d 0d 0a 1b 5b 30 6d

    2.2、mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QSerialPort>
    #include <QSerialPortInfo>

    QT_BEGIN_NAMESPACE
    namespace Ui {
    class MainWindow;
    }
    QT_END_NAMESPACE

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow() override;

    private:
    void splitLines();
    int parseAnsi(const QByteArray &rawLine, QString &outText);
    private slots:
    void btnClickedSlot();
    void onSerialRecvData();
    QColor ansiCodeToColor(int code);
    private:
    Ui::MainWindow *ui;
    QSerialPort m_serial;
    QByteArray m_rxBuffer; // 接收环形缓存
    };
    #endif // MAINWINDOW_H

    2.3、mainwindow.h

    #include "mainwindow.h"
    #include "ui_mainwindow.h"

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

    connect(this->ui->btnConnect,&QPushButton::clicked,this,&MainWindow::btnClickedSlot);

    connect(&m_serial, &QSerialPort::readyRead, this, &MainWindow::onSerialRecvData);
    }

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

    void MainWindow::splitLines()
    {
    const QByteArray sep = "\\r\\r\\n";
    int sepLen = sep.size();

    // 循环查找所有完整行
    while (true)
    {
    int pos = m_rxBuffer.indexOf(sep);
    if (pos < 0)
    break; // 无完整行,退出

    // 截取一行原始数据(不含分隔符)
    QByteArray rawLine = m_rxBuffer.left(pos);
    // 移除已处理行 + 分隔符
    m_rxBuffer = m_rxBuffer.mid(pos + sepLen);

    // 解析ANSI颜色并发送信号
    QString text;
    int code = parseAnsi(rawLine, text);
    qDebug()<<"code:"<<code<<" text:"<<text;

    QColor textColor = ansiCodeToColor(code);

    // 获取光标
    QTextCursor cursor = this->ui->textBrowser->textCursor();
    QTextCharFormat fmt;

    // 设置文字颜色
    fmt.setForeground(textColor);
    // 可选:加粗(ansi 1)可扩展判断
    // if(ansiCode == 1) fmt.setFontWeight(QFont::Bold);

    // 应用格式到光标
    cursor.setCharFormat(fmt);
    this->ui->textBrowser->setTextCursor(cursor);

    // 追加一行文本,自动换行
    this->ui->textBrowser->append(text);

    }
    }

    int MainWindow::parseAnsi(const QByteArray &rawLine, QString &outText)
    {
    outText.clear();
    int colorCode = 0; // 0 = 重置样式

    int i = 0;
    int len = rawLine.size();
    while (i < len)
    {
    // 判断 ESC[ 序列 0x1B 0x5B
    if (rawLine.at(i) == 0x1B && (i+1) < len && rawLine.at(i+1) == 0x5B)
    {
    i += 2; // 跳过 \\033[
    QString numStr;
    // 读取数字直到 'm'
    while (i < len && rawLine.at(i) != 'm')
    {
    numStr += rawLine.at(i);
    i++;
    }
    // 读到m,更新颜色码
    if (i < len && rawLine.at(i) == 'm')
    {
    colorCode = numStr.toInt();
    i++;
    }
    }
    else
    {
    // 普通可见字符,存入文本
    outText += rawLine.at(i);
    i++;
    }
    }
    return colorCode;
    }

    void MainWindow::btnClickedSlot()
    {
    // 1. 配置串口参数
    m_serial.setPortName("COM1"); // 串口号
    m_serial.setBaudRate(QSerialPort::Baud115200); // 波特率
    m_serial.setDataBits(QSerialPort::Data8); // 数据位8
    m_serial.setParity(QSerialPort::NoParity); // 无校验
    m_serial.setStopBits(QSerialPort::OneStop); // 停止位1
    m_serial.setFlowControl(QSerialPort::NoFlowControl);

    // 打开串口
    if(m_serial.open(QIODevice::ReadWrite))
    {
    qDebug() << "串口打开成功";
    }
    else
    {
    qDebug() << "串口打开失败:" << m_serial.errorString();
    }
    }

    void MainWindow::onSerialRecvData()
    {
    m_rxBuffer.append(m_serial.readAll());
    // 循环切分完整行
    splitLines();
    }

    QColor MainWindow::ansiCodeToColor(int code)
    {
    switch (code)
    {
    case 30: return Qt::gray;
    case 31: return QColor(255, 80, 80); // 红
    case 32: return QColor(80, 255, 80); // 绿
    case 33: return QColor(255, 255, 80); // 黄
    case 34: return QColor(80, 180, 255); // 蓝
    case 35: return QColor(255, 80, 255); // 紫
    case 36: return QColor(80, 255, 255); // 青
    case 37: return Qt::white; // 白
    case 0: // \\033[0m 重置为默认白色
    default: return Qt::white;
    }
    }

    在这里插入图片描述

    赞(0)
    未经允许不得转载:171主机测评 » Qt 解析并显示rt-thread输出的彩色日志源码分享
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址