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

日志重定向:让 qDebug() 实时显示在 Qt 窗口中

效果

image

源码

#include "mainwindow.h" // 包含主窗口头文件
#include <QApplication> // 包含 QApplication
#include <QTextEdit>    // 包含 QTextEdit,用于显示日志
#include <QScrollBar>   // 包含 QScrollBar(虽然这个例子中没直接用,但有时用于控制滚动条)
#include <QDateTime>    // 包含 QDateTime,用于获取时间戳
#include <QMetaObject>  // 包含 QMetaObject,用于跨线程调用
#include <QFileInfo>    // 包含 QFileInfo(此例中未使用,但常用于文件操作)
#include <QTextBlock>   // 包含 QTextBlock(此例中未使用,用于文本块操作)
#include <QTextDocument> // 包含 QTextDocument(此例中未使用,是 QTextEdit 的底层文档)
#include <QTextCursor>  // 包含 QTextCursor,用于控制文本编辑器的光标// 全局静态指针,指向用于显示日志的 QTextEdit 控件
static QTextEdit *g_logEdit = nullptr;/*** @brief 自定义消息处理器,用于将 Qt 消息(qDebug, qInfo 等)重定向到 g_logEdit 控件。* * @param type 消息类型 (QtDebugMsg, QtInfoMsg, etc.)* @param context 消息上下文(包含文件名、行号、函数名等)* @param msg 实际的消息字符串*/
void redirectOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{// 如果日志控件未设置,则直接返回,不处理消息if (!g_logEdit) return;QString prefix, color;// 根据消息类型设置前缀和颜色(使用 HTML 颜色代码)switch (type) {case QtDebugMsg:    prefix = "DEBUG";    color = "#2d2d2d"; break; // 深灰色case QtInfoMsg:     prefix = "INFO";     color = "#0066cc"; break; // 蓝色case QtWarningMsg:  prefix = "WARN";     color = "#cc6600"; break; // 橙色case QtCriticalMsg: prefix = "CRITICAL"; color = "#cc0000"; break; // 红色case QtFatalMsg:    prefix = "FATAL";    color = "#990000"; break; // 深红色default:            prefix = "UNKNOWN";  color = "#808080"; break; // 灰色
    }// 关键步骤:转义消息字符串,防止用户输入的内容(如 `<` 或 `&`)被解释为 HTML 标签// toHtmlEscaped() 只转义必要的字符,保持单行文本的格式。QString escapedMsg = msg.toHtmlEscaped(); // 只转义 <>&",保持单行// 如果原始消息中包含换行符 `\n`,并且希望在 QTextEdit 中也换行,// 可以使用:escapedMsg = msg.replace("\n", "<br/>").toHtmlEscaped();// 格式化日志行,使用 HTML 标签进行着色和格式控制QString line = QString(// 使用 C++11 的原始字符串字面量 R"(...)" 避免对引号和反斜杠的转义R"(<font color="#888888">[%1]</font> <font color="#00aa00">%2:</font> <font color="%3">%4</font><br>)")// %1:时间戳 (hh:mm:ss.zzz).arg(QDateTime::currentDateTime().toString("hh:mm:ss.zzz"))// %2:日志级别前缀,-8 表示固定宽度左对齐.arg(prefix, -8)// %3:日志文本颜色
                       .arg(color)// %4:转义后的日志内容.arg(escapedMsg); // 使用转义后的 msg,并用 <br> 强制换行// 因为日志消息可能在非 GUI 线程中产生,所以必须使用 QMetaObject::invokeMethod// 将更新 UI 的操作(插入 HTML)放入 GUI 线程的事件队列中。
    QMetaObject::invokeMethod(g_logEdit, [line]() {QTextEdit *edit = g_logEdit;// 移动光标到文档末尾edit->moveCursor(QTextCursor::End);// 插入格式化好的 HTML 日志行edit->insertHtml(line);// 确保光标(和文档末尾)可见,实现自动滚动edit->ensureCursorVisible();}, Qt::QueuedConnection); // 使用 Qt::QueuedConnection 确保是异步跨线程调用
}/*** @brief 程序的入口点*/
int main(int argc, char *argv[])
{// 创建 QApplication 实例
    QApplication a(argc, argv);// 安装自定义消息处理器,替换 Qt 默认的处理器
    qInstallMessageHandler(redirectOutput);// 创建主窗口实例
    MainWindow w;// 查找主窗口中名为 "textEditLog" 的 QTextEdit 控件,并将其赋值给全局指针g_logEdit = w.findChild<QTextEdit*>("textEditLog");// 显示主窗口
    w.show();// 发送一些测试消息,它们现在应该会被重定向到 QTextEdit 控件中qDebug() << "程序启动成功!所有 qDebug() 现在都会显示在这里";qInfo()    << "这是一条 Info 消息";qWarning() << "这是一条警告消息";qCritical()<< "这是一条严重错误消息";// 启动 Qt 事件循环return a.exec();
}
main.cpp
#include "mainwindow.h" // 包含主窗口的头文件
#include "ui_mainwindow.h" // 包含由 Qt Designer 生成的 UI 头文件
#include <QTextEdit>    // 包含 QTextEdit 控件
#include <QVBoxLayout>  // 包含 QVBoxLayout(虽然这里没有直接使用布局类,但包含了常用的 UI 控件头文件)/*** @brief MainWindow 类的构造函数* @param parent 父 QWidget 指针,通常为 nullptr*/
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) // 调用 QMainWindow 基类的构造函数, ui(new Ui::MainWindow) // 初始化 ui 成员指针
{// 设置由 Qt Designer 生成的界面元素(如果使用 designer 的话,但这里主要通过代码创建控件)ui->setupUi(this);// ---------- 创建并配置日志文本框 ----------// 动态创建 QTextEdit 控件,并指定父对象为当前 MainWindowQTextEdit *logEdit = new QTextEdit(this);// 设置对象的名称。这个名字 ("textEditLog") 是 main.cpp 中用于查找并关联日志重定向函数的关键!logEdit->setObjectName(QStringLiteral("textEditLog"));// 设置文本框为只读,用户不能手动编辑日志内容logEdit->setReadOnly(true);// 设置行自动换行模式为不换行。日志通常需要水平滚动条来查看完整的一行。logEdit->setLineWrapMode(QTextEdit::NoWrap);// 使用 QStyleSheet 设置日志文本框的样式logEdit->setStyleSheet(R"(
        QTextEdit {// 设置等宽字体,如 Consolas,以保持日志时间戳和前缀对齐整齐font-family: "Consolas", "Courier New", "DejaVu Sans Mono", monospace;// 设置字体大小font-size: 10pt;// 移除默认的边框,使外观更简洁
            border: none;})");// 将新创建的日志文本框设置为 MainWindow 的中心控件
    setCentralWidget(logEdit);
}/*** @brief MainWindow 类的析构函数*/
MainWindow::~MainWindow()
{// 释放由 ui 成员指针指向的资源delete ui;
}
mainwindow.cpp

 

http://www.jsqmd.com/news/51600/

相关文章:

  • 铝单板厂家哪家好?河南霖锋幕墙用品质与实力给出答案
  • 活动预告|本周六!IvorySQL 邀您相聚第八届中国 PostgreSQL 数据库生态大会
  • 后保研可以中途换老师吗?服务过程中的师资调整机制说明
  • 深入解析:微电子科学与工程专业毕设选题指南:热门方向推荐 2026届
  • 突破成绩限制:后保研如何助力不同排名学生实现院校跃升?
  • 保研规划哪家有保障?这份保研机构挑选指南请收好
  • 2025新款卫衣厂家推荐:COVERNAT男女薄厚款,简约复古百搭之选
  • 年会策划公司哪家性价比高?这十大策划公司按需选配不花冤枉钱!
  • 2025年11月最新成都实木隔断源头厂家排名揭晓
  • 2025 年 11 月棒球帽品牌实力推荐榜:涵盖薄款/厚款/男款/女款/可水洗/复古款/潮流款/运动款,精选百搭设计与舒适面料之选
  • 分布式架构原理与实现---第二篇
  • 2025在职保研规划机构综合评测报告:10 家靠谱机构横向对比
  • 车规TVS管行业现状与技术发展趋势分析-ASIM阿赛姆
  • 后保研课程可回放?从线上服务体验看后保研课程学习灵活性
  • 2025年深圳这家DSE培训机构成果亮眼
  • 2025 年 11 月卫衣品牌实力推荐榜:薄款/厚款/男款/女款/可水洗/纯棉/连帽/无帽,潮流贴肤与透气百搭的舒适之选
  • ALV爱乐惟国际教育:深耕A-Level课程,助你直通世界名校
  • 送女朋友礼物推荐:极萌胶原炮领衔10款好礼,从少女肌到仪式感全拿捏
  • 从 “看得见总量” 到 “找得到根源”:隐式内存治理让运维效率翻倍
  • Docker安装(基于云服务器ECS实例 CentOS 7.9系统) - 教程
  • 2025 年 11 月羽绒服厂家推荐排行榜:薄款/厚款/男款/女款/可水洗/抗皱/百搭/潮流款/街头风/小红书热门款,时尚与实用兼具的冬季精选
  • 情人节礼物推荐指南:极萌胶原炮,科技守护她的年轻光芒
  • 2025年高压纳米均质机工厂权威推荐榜单:均质机‌/高压均质机‌/高压细胞破壁机源头工厂精选
  • 2025 年 11 月 GEO 公司口碑指南:多行业企业推荐合集
  • 2025棒球帽厂家推荐:COVERNAT薄款/厚款/男女款可水洗,潮流百搭之选
  • 11月追加2、2025年质量好的四川红绿灯厂家最新TOP厂家排名 (2)
  • 使用caddy搭建github ipv6 proxy
  • 实用指南:3个SQL聚合模式让老板以为你是数据魔法师:职场实战完全指南
  • 2025 年 11 月羽绒服厂家潮流推荐榜:薄款/厚款/男款/女款/可水洗/复古款/街头风/通勤/百搭羽绒服,兼具时尚设计与实用保暖的全新选择
  • 网站建设企业有哪些,抖音推广/抖音代运营/小红书推广/新闻营销/GEO优化/网络营销/网络推广/新闻发布/网络公关网站建设品牌找哪家