Qt 中捕获三方库自身标准打印方法

news2024/10/7 5:23:47

【写在前面】

        很多时候,我们为了方便调试,常常需要加入一些打印。

        例如 Qt 中的 QDebug,C 和 C++ 中的 printf / cout 等等,又或者是三方库提供的标准打印接口。

        然而大部分时候,这些打印相当不统一(格式和位置),并且因为 Qt 作为 GUI 框架,调试信息实在不应该直接置于 UI 之上。

        因此,需要一种能统一和标准化所有标准打印的方法( 所谓标准打印即标准输出 stdout 等),并且能够动态配置。


 【正文开始】

  • 对于 Qt 自身的打印,捕获起来相当容易:

        我们使用 qInstallMessageHandler() 安装一个消息处理器,它指向一个函数,其函数签名如下第一行所示:

typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
Q_CORE_EXPORT QtMessageHandler qInstallMessageHandler(QtMessageHandler);

         该函数能够捕获由 Qt Debug 产生的各种类型的打印消息,然后可以在此函数集中处理。

  • 对于三方库,只要他是标准输出,我们就可以使用一些技巧来捕获它:

        这里我们需要借助一个C库函数 freopen(),其声明如下:

FILE *freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream);

        该函数用于重定向输入输出流。它可以在不改变代码原貌的情况下改变输入输出环境,但使用时应当保证流是可靠的

        有了这些函数,接下来我们整合一下,来实现一个完整的,能够处理所有情况的函数:

static void initializeDebugEnveriment()
{
    static bool initialized = false;
    static QTextEdit *edit = new QTextEdit;
    static int lineCount = 0;
    static const QString stdoutFileDir = qApp->applicationDirPath() + "/cache";

    static QTimer *watcher = new QTimer(qApp);
    static quint64 fileSize = 0;
    static QFile watchedStdoutFile(stdoutFileDir + "/stdout");

    if (!initialized) {
        qRegisterMetaType<QTextCursor>("QTextCursor");

        auto palette = edit->palette();
        palette.setBrush(QPalette::Highlight, QColor(0, 120, 215));
        edit->setPalette(palette);
        edit->setReadOnly(true);
        edit->setWindowTitle(QStringLiteral("调试窗口"));
        edit->setWindowFlag(Qt::WindowStaysOnTopHint);
        edit->resize(700, 500);
        edit->show();

        if (!QDir().exists(stdoutFileDir)) QDir().mkpath(stdoutFileDir);

        std::freopen((stdoutFileDir + "/stdout").toLocal8Bit().data(), "w", stdout);
        watchedStdoutFile.open(QIODevice::ReadOnly);

        watcher->start(100);
        QObject::connect(watcher, &QTimer::timeout, watcher, []{
            if (watchedStdoutFile.size() != fileSize) {
                fileSize = watchedStdoutFile.size();
                auto watchedMsg = QString::fromLocal8Bit(watchedStdoutFile.readAll());
                if (!watchedMsg.isEmpty()) {
                    auto list = watchedMsg.split('\n');
                    for (auto msg: qAsConst(list)) {
                        msg = msg.trimmed();
                        auto time = QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh:mm:ss:zzz] ");
                        if (!msg.isEmpty()) msg = time + msg;
                        edit->append(msg);
                        if (!edit->textCursor().hasSelection()) edit->moveCursor(QTextCursor::End);
                        if (++lineCount > 50000) {
                            lineCount = 0;
                            edit->clear();
                        }
                    }
                }
            }
        });

        initialized = true;
    }

    static auto myMsgHandler = [](QtMsgType, const QMessageLogContext &, const QString &msg) -> void {
        auto time = QDateTime::currentDateTime().toString("[yyyy-MM-dd-hh:mm:ss:zzz] ");
        edit->append(time + msg);
        if (!edit->textCursor().hasSelection()) edit->moveCursor(QTextCursor::End);
        if (++lineCount > 50000) {
            lineCount = 0;
            edit->clear();
        }
    };

    qInstallMessageHandler(myMsgHandler);
}

        这里我用一个 QTextEdit 来显示所有捕获的打印,但这不是必要的,可以根据自己需求来改造。

        首先,因为要将标准输出重定向到文件,所以我们要创建一个文件夹用于缓存其输出。

        接着,将 stdout 重定向至一个文件中( 实际上可以是任意输出流 ),然后创建一个定时器用于监视其文件大小变化

        如果监视文件大小改变,则将内容读入( 即打印内容 ),并添加到 textEdit 中显示出来,此时就完成了标准打印的捕获。

        并且,这种方法能够捕获三方库的内部打印消息。

        最后,我添加了一段模拟代码来测试一下:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    initializeDebugEnveriment();

    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, &timer, []{
        static int count = 1;
        qDebug() << "This is Qt Debug message! Count:" << count++;
    });
    timer.start(1000);

    QTimer otherTimer;
    QObject::connect(&otherTimer, &QTimer::timeout, &otherTimer, []{
        static int count = 1;
        printf("This is printf stdout message! Count: %d", count++);
        fflush(stdout);
    });
    otherTimer.start(1000);

    return app.exec();
}

        效果图如下:


 【结语】

        现在有了这个函数,我们还可以动态控制打印窗口,即控制 textEdit 是否显示。

        另外提一点,如果嫌弃麻烦,可以直接 CONFIG += console,直接使用控制台打印。当然这个方法的缺点则是不能运行时配置,并且启动时会有一个控制台窗口。

        最后,源码地址:

        Github的:GitHub - mengps/QtExamples: 分享各种 Qt 示例,,说不定用得上呢~分享各种 Qt 示例,,说不定用得上呢~. Contribute to mengps/QtExamples development by creating an account on GitHub.https://github.com/mengps/QtExamples        CSDN的:

https://download.csdn.net/download/u011283226/87097616https://download.csdn.net/download/u011283226/87097616

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高清架构整洁之道PDF下载

架构整洁之道高清PDF下载&#xff0c;请扫描如下二维码&#xff0c;支付3元。并加微信&#xff0c;发给你。谢谢。

你想制作一款属于自己的游戏吗?

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网站】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且…

无线传感器网络(Wireless Sensor Networks)概述

文章目录IntroductionSensor Mote PlatformsLow-End-PlatformsHigh-End-PlatformsWSN Architecture and Protocol StackWSN Design ConsiderationsHardware ConstraintsFault ToleranceScalabilityProduction CostWSN TopologyTransmission MediaPower ConsumptionSensingData …

编译原理11:LR分析、句柄、LR文法

LR分析法概述 句柄和规范归约 LR分析法 s:shitf 移进 r:reduce 规约 LR分析示例 LR文法 k越大&#xff0c;处理能力越强&#xff0c;但复杂度越高 会人工消除冲突&#xff0c;使得符合LR文法 小结

动态规划算法学习一:DP的重要知识点、矩阵连乘算法

文章目录前言一、矩阵连乘问题1、问题描述2、完全加括号3、问题分析4、最优子结构性质5、状态表示和递推方程6、自问题个数和求解顺序二、计算最优值示例1、问题描述2、计算最优值示例*****3、构造最优解4、算法实现三、基本要素-最优子结构四、基本要素-重叠子问题五、递归方法…

具有生物活性的天然产物——雷公藤

雷公藤为卫矛科雷公藤属植物&#xff0c;是我国一种资源比较丰富的传统中草药&#xff0c;迄今为止&#xff0c;已有超过 500 多种化合物从雷公藤中分离出来&#xff0c;包括萜类、生物碱类、黄酮类、木脂素类等。其结构多样的有效成分具有抗炎、抗感染、免疫抑制和抗肿瘤等作用…

腾讯云TRTC服务实现Web视频会议

腾讯云TRTC服务实现Web视频会议 背景 近期公司承接了某高校智慧校园的项目建设工作&#xff0c;其中在家校协作的板块中需要进行视频教学&#xff0c;以及线上屏幕共享&#xff0c;为了完成这一需求&#xff0c;我在自研与第三方服务的选择之间选择了第三方&#xff0c;主要因…

【交通标志识别】基于BP神经网络实现交通标志识别系统(含语音报警)附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

java在Windows配置Path环境变量

java在Windows配置Path环境变量 在命令行窗口输入java时&#xff0c;命令行提示’java’ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 第一步&#xff1a;鼠标右键点击我的电脑&#xff0c;点击“属性” 第二步&#xff1a;点击“高级系统设置” 第三步&…

ProNas-振动噪声工程界新一代的前沿技术

作者&#xff1a;张工 随着汽车、船舶、高铁动车、轨道车辆、商用飞机、起重机械等交通运输工具和风电机组、家用电器、航天器等振动噪声。仿真模型的日益精细和庞大&#xff0c;现代噪声、振动及舒适性&#xff08;NVH&#xff09;仿真计算及验证领域面临着计算效益&#xf…

FL Studio21水果体验尝鲜版音乐宿主程序FL2023

FL Studio21从大家看来的音乐玩具&#xff0c;逐渐发展成相当严肃的DAW。如今&#xff0c;正被全球大量用户使用。它总是有着自己的方式&#xff0c;在工作流程和设计上&#xff0c;都不与竞争者相仿。 FL Studio是一款功能强大的虚拟音乐制作软件,通过它创作wav,MP3,MIDI,loo…

iOS多项选项卡TYTabPagerBar和分页控制器TYPagerController使用小结

最近做项目的时候&#xff0c;用到了顶部选项卡和底部分页控制器相关的功能。之前做的话都是自己手动封装&#xff0c;通过两个UIScrollView联动来实现。公司同事给推荐了一个封装好的库&#xff0c; TYPagerController&#xff0c;内部也是通过ScrollView的联动来实现的&…

微信小程序 java ssm电影迷爱好者交流平台

电影交流平台是基于java编程语言&#xff0c;mysql数据库&#xff0c;idea开发工具开发的后台&#xff0c;前端是微信小程序开发工具开发。本设计分为用户和管理员两个角色&#xff0c;其中用户可以登陆微信端&#xff0c;查看电影信息&#xff0c;查看电影分类&#xff0c;对电…

Inobitec DICOM Viewer Pro 2.8.0 Crack

Inobitec DICOM Viewer Pro 2.8.0扩大医生可见和可能的极限。通过为医疗行业提供优质的创新 IT 解决方案&#xff0c;我们可以为改善全球人民的健康做出很多贡献。 动态渐进版&#xff08;每季度发布&#xff09;扩展功能 高级 3D 重建 以 OBJ、STL、PLY 格式导出表面 先进的…

SpringBoot2.x 自动化生成代码整合Mybatis

前言 Mybatis 是一个持久层ORM框架&#xff0c;负责Java与数据库数据交互&#xff0c;也可以简易理解为中介&#xff0c;相对于它&#xff0c;还有个中介是hibernate,不过在mybatis中sql语句的灵活性&#xff0c;可优化性比较强&#xff0c;这也是现在大多数人选择的原因。 1. …

【快速学习系列】Mybatis缓存和使用SpringBoot开启MyBatis缓存+ehcache

【快速学习系列】Mybatis缓存和使用SpringBoot开启MyBatis缓存ehcache Mybatis缓存 MyBatis一级缓存 Mybatis对缓存提供支持&#xff0c;但是在没有配置的默认情况下&#xff0c;它只开启一级缓存&#xff0c;一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一…

全员全域安全守护,蔚来ET7获Euro NCAP五星安全评级背后的硬核实力

2022年11月16日&#xff0c;蔚来智能电动旗舰轿车ET7 获得Euro NCAP&#xff08;欧盟新车安全评鉴协会&#xff09;五星安全评级&#xff0c;成为继ES8之后蔚来又一款获得欧洲五星安全评级的车型。ET7分别在乘客安全、儿童安全、弱势道路使用者安全、辅助安全得分91%、87%、73%…

两个事务并发写,能保证数据唯一吗?

哟&#xff0c;又是我小白。最近有点高产了。 连我自己都害怕了。 直接进入正题吧。 两个事务并发写&#xff0c;能保证数据唯一吗&#xff1f; 我先来解释下标题讲的是个啥。 我们假设有这么一个用户注册的场景。用户并发请求注册新用户。 你有一张数据库表&#xff0c;也就…

【数据可视化】第二章——基于matplotlib的数据可视化

目录系列课程学习目标1. 基于matplotlib的数据可视化2 matplotlib.pyplot函数库简介3 matplotlib.pyplot相关函数简介3.1 plt.plot(x, y, format_string, **kwargs)3.2 plt.title()3.3 plt.xlabel()/ylabel()3.4 plt.legend()3.5 pyplot的中文显示3.5.1 第一种方法3.5.2 第二种…

C#上位机系列(2)—常用控件的介绍:文本标签,按键,输入框

本文是讲解C#.net平台的Winform框架下的第二个内容&#xff0c;手把手介绍项目的创建方式以及一些写软件时常用的功能&#xff0c;讲解从零开始的每一个步骤。 本次介绍三个最常用控件的使用 1.文本控件Label 功能&#xff1a;显示一个文本 2.按键控件Button 功能&#x…