QT 重定向qdebug输出到自绘界面

news2024/11/28 11:57:44

因为在嵌入式中调试qt需要查看输出信息,特意写了一个类用户便捷查看qdebug信息

界面如下:

提供了开始,停止,保存,清空,退出功能,具体代码下文给出

文件如下

#ifndef QDEBUGREDIRECT_H
#define QDEBUGREDIRECT_H
/*
 *qdebug  重定向类 定向到界面控件
 *李吉磊 2023.12.7
 *
*/

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QWidget>
#include <QMutex>


class qDebugRedirect : public QObject
{
    Q_OBJECT
public:
    qDebugRedirect();
    void showWidget();    //展示界面
    void closeWidget();    //关闭界面
    static void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);

private:
    void InitWidget();
    void StartRedirect();     //启动注册
    void StopRedirect();      //停止注册
    void Save2File();         //将界面文本内容保存到本地
    QWidget * m_widget;  //界面
    QTextEdit * m_Edit;
    QMutex m_mutex;
};

#endif // QDEBUGREDIRECT_H
#include "qdebugredirect.h"
#include <QGridLayout>
#include <QDebug>
#include <QDateTime>
#include <QDir>
qDebugRedirect * g_qDebugRedirect;

qDebugRedirect::qDebugRedirect()
{
    m_widget = nullptr;
    g_qDebugRedirect = this;
    //下面两行为在构造该类时启动重定向,后续只要展示出界面即可查看信息
    InitWidget();
    StartRedirect();
}

void qDebugRedirect::myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    // 加锁
    g_qDebugRedirect->m_mutex.lock();

    //信息分类
    QString strMsg("");
    QByteArray localMsg = msg.toLocal8Bit();
    switch(type)
    {
    case QtDebugMsg:
        strMsg = QString("Debug:");
        break;
    case QtInfoMsg:
        strMsg = QString("Info:");
        break;
    case QtWarningMsg:
        strMsg = QString("Warning:");
        break;
    case QtCriticalMsg:
        strMsg = QString("Critical:");
        break;
    case QtFatalMsg:
        strMsg = QString("Fatal:");
        break;
    default:
        break;
    }

    //文件名、函数名、行数
    strMsg += QString("Function: %1  File: %2  Line: %3 ").arg(context.function).arg(context.file).arg(context.line);

    // 时间和内容
    QString strDateTime = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString strMessage = QString("%1 %2:%3").arg(strDateTime).arg(strMsg).arg(localMsg.constData());
    int maxLen = 2*1024*1024;
    int len = g_qDebugRedirect->m_Edit->toPlainText().length();
    if(len > maxLen)
        g_qDebugRedirect->m_Edit->clear();
    g_qDebugRedirect->m_Edit->append(strMessage);
    g_qDebugRedirect->m_Edit->moveCursor(QTextCursor::End);

    // 解锁
    g_qDebugRedirect->m_mutex.unlock();

}


void qDebugRedirect::StartRedirect()
{
    qInstallMessageHandler(myMessageOutput);
}

void qDebugRedirect::StopRedirect()
{
    qInstallMessageHandler(nullptr);
}

void qDebugRedirect::InitWidget()
{
    if(m_widget == nullptr)
    {
        m_widget = new QWidget();
        QGridLayout * glay = new QGridLayout();
        glay->setSpacing(0);
        glay->setMargin(0);
        glay->setContentsMargins(0,0,0,0);
        m_widget->setLayout(glay);
        QPushButton * pbClose = new QPushButton();  //关闭界面按钮
        pbClose->setText("close");
        QObject::connect(pbClose,&QPushButton::clicked,this,[=](){
            closeWidget();
            //qDebug() << "close";
        });
        glay->addWidget(pbClose,0,8,1,1);
        QPushButton * pbBegin = new QPushButton();  //开始按钮
        pbBegin->setText("start");
        QObject::connect(pbBegin,&QPushButton::clicked,this,[=](){StartRedirect();});
        glay->addWidget(pbBegin,1,0,1,2);
        QPushButton * pbEnd = new QPushButton();    //结束按钮
        pbEnd->setText("stop");
        QObject::connect(pbEnd,&QPushButton::clicked,this,[=](){StopRedirect();});
        glay->addWidget(pbEnd,1,2,1,2);
        QPushButton * pSave = new QPushButton();    //保存按钮
        pSave->setText("save");
        QObject::connect(pSave,&QPushButton::clicked,this,[=](){Save2File();});
        glay->addWidget(pSave,1,4,1,2);
        QPushButton * pClear = new QPushButton();    //清理按钮
        pClear->setText("clear");
        QObject::connect(pClear,&QPushButton::clicked,this,[=](){
            m_Edit->clear();
        });
        glay->addWidget(pClear,1,8,1,1);


        //展示控件
        m_Edit = new QTextEdit();
        glay->addWidget(m_Edit,2,0,6,9);
        //m_widget->setWindowFlag(Qt::WindowStaysOnTopHint,true);
        //m_widget->setWindowFlags(Qt::FramelessWindowHint);
        //m_widget->setWindowModality(Qt::ApplicationModal);
        m_widget->resize(800,600);
    }
}

void qDebugRedirect::showWidget()    //展示界面
{
    InitWidget();
    m_widget->show();
}

void qDebugRedirect::closeWidget()    //关闭界面
{
    if(m_widget)
    {
        m_widget->close();
        delete m_widget;
        m_widget = nullptr;
    }
}

void qDebugRedirect::Save2File()
{
    //创建log文件夹
    qDebug() << "currentPath : " << QDir::currentPath();

    QDir dir("log");
    if (!dir.exists())
    {
        QDir dir;
        bool b = dir.mkdir("log");
        qDebug() << "dir.mkdir(\"log\") = "  << b;
    }

    //创建log文件
    QString currentDate = QDateTime::currentDateTime().toString("yyyyMMdd");
    QString logName = "log" + currentDate + ".txt";
    QString logFileName = "log/" + logName;

    //写入文件
    QFile file(logFileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Append))
    {
        qDebug() << "file.open : " << logFileName << "faild";
        file.close();
        return ;
    }
    qDebug() << "file.open : " << logFileName << "succeed";
    QTextStream stream(&file);
    stream << m_Edit->toPlainText() << "\r\n";;
    file.flush();
    file.close();
}



使用方法也很简单

先构造

qDebugRedirect * m_widget;

m_widget = new qDebugRedirect();

然后展示界面或关闭界面

m_widget->showWidget();   展示界面

m_widget->closeWidget();  关闭界面

当然了界面自带close 按钮 或者 窗体的x 退出按钮均可退出

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

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

相关文章

vue2中使用jsplumb完成流程图

前言 之前的几个demo都是在vue3中写的,虽然可以直接拿去复用。 但是根据有些看客反馈,想用一个vue2版本的,毕竟很多人开发功能的时间都不是特别富裕。大多时候还是用现成的demo更好一些。 这里我就写一个简易版本的demo,可以实现绘制,并且删除连接线和节点等功能,篇幅也不大…

麻雀1号开发板开箱

麻雀1号是上海睿赛德电子科技有限公司全新推出的一款高性价比音频Wi-Fi开发板&#xff0c;内置RT-Thread&#xff0c;主打 Wi-Fi、音频和摄像头拍照功能&#xff0c;配合丰富的组件及例程&#xff0c;可降低多媒体应用的开发门槛。 开发板介绍 正面&#xff1a; 背面&#x…

手搓图片滑动验证码_JavaScript进阶

手搓图片滑动验证码 背景代码效果图展示网站 背景 在做前端项目开发的时候&#xff0c;少不了登录注册部分&#xff0c;既然有登录注册就少不了机器人验证&#xff0c;验证的方法有很多种&#xff0c;比如短信验证码、邮箱验证码、图片滑动、图片验证码等。 由于鄙人在开发中…

docker安装与详细配置redis

docker安装redis 连接虚拟机 vagrant up //启动虚拟机 vagrant ssh //连接虚拟机进入root用户 su root输入密码&#xff1a;和账户名一样 vagrant 下载redis 直接下载redis镜像,下载redis最新镜像 docker pull redis下载的都是DockerHub中默认的官方镜像 创建文件目…

golang slice 数组针对某个字段进行排序

这里主要用到golang的sort.Sort方法&#xff0c;先看这个函数的简介&#xff1a; 介绍链接&#xff1a;https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter03/03.1.html 如何实现&#xff1a; import "sort"// UserInfo 用户信息结构…

Bionorica成功完成SAP S/4HANA升级 提升医药制造业务效率

企业如何成功地将其现有的ERP ECC系统转换升级到SAP S/4HANA&#xff0c; 并挖掘相关潜力来推动其数字化战略&#xff1f;Bionorica应用SNP软件实施了实时ERP套件&#xff0c;为进一步的增长和未来的创新奠定了基础。 草药市场的领导者&#xff1a;Bionorica Bionorica是世界领…

.NET使用分布式网络爬虫框架DotnetSpider快速开发爬虫功能

前言 前段时间有同学在微信群里提问&#xff0c;要使用.NET开发一个简单的爬虫功能但是没有做过无从下手。今天给大家推荐一个轻量、灵活、高性能、跨平台的分布式网络爬虫框架&#xff08;可以帮助 .NET 工程师快速的完成爬虫的开发&#xff09;&#xff1a;DotnetSpider。 注…

Java实现屏幕截图程序(一)

在Java中&#xff0c;可以使用Robot类来实现屏幕截图程序。Robot类提供了一组用于生成输入事件和控制鼠标和键盘的方法。 Java实现屏幕截图的步骤如下&#xff1a; 导入Robot类 import java.awt.Robot;创建Robot对象 Robot robot new Robot();获取屏幕分辨率信息 Dimensi…

力扣面试题 08.12. 八皇后(java回溯解法)

Problem: 面试题 08.12. 八皇后 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 八皇后问题的性质可以利用回溯来解决&#xff0c;将大问题具体分解成如下待解决问题&#xff1a; 1.以棋盘的每一行为回溯的决策阶段&#xff0c;判断当前棋盘位置能否放置棋子 2.如何判…

JavaScript <关于逆向RSA非对称加密算法的案例(代码剖析篇)>--案例(五点一)

引用上文: CSDNhttps://mp.csdn.net/mp_blog/creation/editor/134857857 剖析: var bitsPerDigit16; // 每个数组元素可以表示的二进制位数// 数组复制函数&#xff0c;将源数组部分复制到目标数组的指定位置 function arrayCopy(src, srcStart, dest, destStart, n) {var m…

OpenVINS学习1——数据集配置与运行

前言 OpenVINS是基于MSCKF的开源VIO算法&#xff0c;有非常详细的官网文档可以学习使用&#xff0c;将来一段时间的主要实践工作&#xff0c;就是深度掌握这份开源代码。 https://docs.openvins.com/ 一、环境配置与Euroc数据集运行 我的环境是Ubuntu20.04&#xff0c;ROS1&a…

EasyX图形化学习

1.EasyX是什么&#xff1f; 是基于Windows的图形编程&#xff0c;给用户提供函数接口&#xff0c;最终函数调用会由Windows的API实现。 注&#xff1a;EasyX只适配 c 。 2.头文件&#xff1a; <easyx.h>---只包含最新的函数 <graphics.h>---包含<easyx.h&g…

前程无忧接口分析

前程无忧接口分析 所需用到的工具URL解析通过抓包软件或者开发者选项抓取数据包对代码中的参数解析分析对acw_sc__v2进行分析对acw_sc__v2进行转换代码生成生成outPutList数组生成arg2参数生成arg3参数最终的效果 对详情页面的分析对timestamp__1258的生成分析 所需用到的工具 …

一些系统日常运维命令和语句

一、前言 记录一些日常系统运维的命令和语句 二、linux命令与语句 1、linux查看各目录使用磁盘情况 du -h /home home为目录 du -h /home 2.查看内存使用情况 free -h 3、查看进程和CPU使用情况 top top 三、数据库语句 1、统计mysql数据库表数量 SELECT COUNT(*) A…

【爬取二手车并将数据保存在数据库中】

爬取二手车并将数据保存在数据库中 查看网页结构分析爬取步骤解密加密信息将密文解密代码&#xff1a; 进行爬取&#xff1a;爬取函数写入解密文件函数和获取城市函数解密文件&#xff0c;返回正确字符串函数保存到数据库 运行结果 查看网页结构分析爬取步骤 可以看出网页使用…

新版本AndroidStudio删除无用资源

第一步&#xff1a; 第二步&#xff1a; 第三步&#xff0c;等加载完&#xff0c;自己选择要删除的文件。 注意&#xff01;&#xff01;&#xff01; 可能会遇到没有显示无用资源&#xff0c;这时把项目运行在真机上就出来了。

学习pytorch19 pytorch使用GPU训练

pytorch使用GPU进行训练 1. 数据 模型 损失函数调用cuda()2. 使用谷歌免费GPU gogle colab 需要创建谷歌账号登录使用, 网络能访问谷歌3. 执行4. 代码 B站土堆学习视频&#xff1a; https://www.bilibili.com/video/BV1hE411t7RN/?p30&spm_id_frompageDriver&vd_sourc…

Python Authlib库:构建安全可靠的身份验证系统

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在现代应用程序中&#xff0c;安全性是至关重要的&#xff0c;特别是在处理用户身份验证时。Authlib库为Python开发者提供了一套强大的工具&#xff0c;用于简化和增强身份验证和授权流程。本文将深入探讨Authli…

js/jQuery常见操作 之各种语法例子(包括jQuery中常见的与索引相关的选择器)

js/jQuery常见操作 之各种语法例子&#xff08;包括jQuery中常见的与索引相关的选择器&#xff09; 1. 操作table常见的1.1 动态给table添加title&#xff08;指定td&#xff09;1.1.1 给td动态添加title&#xff08;含&#xff1a;获取tr的第几个td&#xff09;1.1.2 动态加工…

elasticsearch聚合、自动补全、数据同步

目录 一、数据聚合1.1 聚合的种类1.2 DSL实现聚合1.2.1 Bucket聚合语法1.2.2 聚合结果排序1.2.3 限定聚合范围1.2.4 Metric聚合语法 1.3 RestAPI实现聚合 二、自动补全2.1 拼音分词器2.2 自定义分词器2.3 自动补全查询2.4 RestAPI实现自动补全 三、数据同步3.1 思路分析3.1.1 同…