需求简介:由于做的是嵌入式工业相机,我们的软件运行在linux上,每次测试软件时,需要查看测试数据时只能写日志或者通过串口打印到PC。当在现场使用时没有电脑想看程序时时运行的数据就做不到,唯一的办法就是写日志,然后把日志拷贝出来拿到电脑上查看,这样一来非常浪费时间,也不能在设备上看时时的测试数据。基于此自己写了这个类似与qDebug()打印信息的工具mDebug(),把数据打印到自己指定的窗口,这样就解决了问题,提高了现场的测试效率,程序运行界面如下所示:
这个界面做的很类似ubuntu的终端界面。mDebug()的实现原理主要是使用了C++的重载功能,对不同的数据类型都重载了<<运算符,使mDebug()可以打印指定的数据类型,为了方便使用mDebug()能打印的数据类型几乎包含了QT的所有基本数据类和opencv的所有基本数据类型。之所以也要支持打印opencv的数据类,是因为我们工业相机是基于opencv这个开源库实现的。下面介绍mDebug()的实现。
创建一个MyDebug类(MyDebug.h 和 MyDebug.cpp)
第一:MyDebug.h文件内容介如下。
//引入opencv库
#include <unistd.h>
#include <cv.h>
//引入QT类
#include <QTextEdit>
#include <QDateTime>
#include <QFile>
using namespace cv;
using namespace std;
//宏 返回MyDebug对象
#define mDebug() MyDebug::myDebug()
//做类前置声明
class QPoint;
class QPointF;
class QRect;
class QRectF;
class CvPoint;
class CvPoint2D32f;
class MyDebugDlg;
class QTextEdit;
1.1、在MyDebug类中对想要打印的数据类型进行 <<运算符重载,所有要重载的数据类型如下。
//重载 << 运算符
MyDebug& operator<<(const QString &sMsg); //重载 << 运算符 打印QString
MyDebug& operator<<(const String &sMsg); //重载 << 运算符 打印String
MyDebug& operator<<(const bool &sMsg); //重载 << 运算符 打印bool
MyDebug& operator<<(const char &sMsg); //重载 << 运算符 打印char
MyDebug& operator<<(const signed short &sMsg); //重载 << 运算符 打印short
MyDebug& operator<<(const unsigned short &sMsg); //重载 << 运算符 打印unsigned short
MyDebug& operator<<(const signed int &sMsg); //重载 << 运算符 打印int
MyDebug& operator<<(const unsigned int &sMsg); //重载 << 运算符 打印unsigned int
MyDebug& operator<<(const signed long &sMsg); //重载 << 运算符 打印long
MyDebug& operator<<(const unsigned long &sMsg); //重载 << 运算符 打印undigned long
MyDebug& operator<<(const qint64 &sMsg); //重载 << 运算符 打印qint64
MyDebug& operator<<(const quint64 &sMsg); //重载 << 运算符 打印quint64
MyDebug& operator<<(const float &sMsg); //重载 << 运算符 打印float
MyDebug& operator<<(const double &sMsg); //重载 << 运算符 打印double
MyDebug& operator<<(const char* sMsg); //重载 << 运算符 打印char*
MyDebug& operator<<(const QByteArray &sMsg); //重载 << 运算符 打印QByteArray
MyDebug& operator<<(const QPoint &sMsg); //重载 << 运算符 打印QPoint
MyDebug& operator<<(const QPointF &sMsg); //重载 << 运算符 打印QPointF
MyDebug& operator<<(const QRect &sMsg); //重载 << 运算符 打印QRectF
MyDebug& operator<<(const QRectF &sMsg); //重载 << 运算符 打印CvPoint
MyDebug& operator<<(const CvPoint &sMsg); //重载 << 运算符 CvPoint
MyDebug& operator<<(const CvPoint2D32f &sMsg); //重载 << 运算符 打印CvPoint2D32f
MyDebug& operator<<(const Point &sMsg); //重载 << 运算符 打印CvPoint2D32f
MyDebug& operator<<(const void *sMsg); //重载 << 运算符 打印指针地址
从重载的形式上看,每种数据类打印完之后,该函数都会引用返回MyDebug对象,这是为了可以使用<<运算符可以连续打印信息到串口。如果不引用返回MyDebug对象,一次一行就只能打印一个信息,而不能在一行打印多个不同的数据类型,所以引用返回这是必须的。
1.2、在MyDebug类里面添加三个静态函数,分别返回MyDebug对象的函数、打印信息到指定窗口的函数、写信息到日志文件的函数,三个函数原形如下所示:
public:
//返回MyDebug对象
static MyDebug myDebug(){return MyDebug();}
//设置信息显示到哪个窗口
static void setWrite2Wnd(QTextEdit *pEdit) {m_pEdit = pEdit;}
//设置是否把信息写到日志文件
static void setWrite2Log(bool bWrite2Log) {m_bWrite2Log = bWrite2Log;}
以上三个函数是public类型的,是提供给外部使用的使用。在MyDebug类添加两个私有静态成员变量,一个是控制是否把打印信息写到日志文件,一个是显示信息的窗口指针。两个成员变量声明如下:
private:
static bool m_bWrite2Log; //是否写到日志文件中 true:写 false:不写
static QTextEdit *m_pEdit; //显示信息的控件指针
1.3、声明了静态成员,就必须对静态成员初始化,C++的语言,以下是初始化原形。
bool MyDebug::m_bWrite2Log = false;
QTextEdit* MyDebug::m_pEdit = NULL;
1.4、另外在声明6个私有函数,函数的声明即作用如下:
private:
void initWnd(); //初始化打印信息串口,清空旧内容、设置格式
void initLog(); //初始化日志文件,创建日志文件
QString stringToHtmlFilter(QString str);//格式化字符串,比如想设置信息的颜色大小,可以同个这个函数格式字符格式
void Write(const QString &sMsg); //在每个重载<<运算符的地方调用,把打印信息显示到窗口和写到日志
void write2Log(const QString &sMsg); //将Debug信息保存到 log.txt
void write2Wnd(const QString &sMsg); //将Debug信息显示到 m_pEdit
以上6个函数是私有类型,只给MyDebug类使用,不对外提供使用权限。
第二:MyDebug.cpp文件内容介如下。
2.1、实现构造函数
MyDebug::MyDebug()
{
initWnd();//初始化打印信息串口,清空旧内容、设置格式
initLog();//初始化日志文件,创建日志文件
}
2.2、实现重载<<函数
//实现打印QString数据类型
MyDebug& MyDebug::operator<<(const QString &sMsg)
{
Write(sMsg);
return *this;//返回MyDebug对象,这是重点
}
//实现打印String数据类型
MyDebug& MyDebug::operator<<(const String &sMsg)
{
QString s(sMsg.c_str());
Write(s);
return *this;//返回MyDebug对象,这是重点
}
//实现打印bool数据类型
MyDebug& MyDebug::operator<<(const bool &sMsg)
{
QString s = sMsg ? QString("true") : QString("false");
Write(s);
return *this;//返回MyDebug对象,这是重点
}
....太多了就不一一列举了,大家可以参考以上三个例子来写。
其它的函数实现就不一一写了,待会会把工程源码上传,需要的可以下载。
第三:MyDebug的使用。
3.1、在需要打印的地方引入MyDebug.h
#include "MyDebug.h"
3.2、使用例子如下:
例1:打印字符串
MyDebug::setWrite2Wnd(ui->textEdit); //设置打印窗口对象指针
MyDebug::setWrite2Log(true); //设置打印信息保存到日志文件
//打印二行信息到窗口并保存到日志文件
mDebug() << tr("this is MyDebug program");
mDebug() << tr("create time is 2018.09.20");
例2:打印整数、浮点数、双精度浮点数、bool
mDebug() << 18 << 26 << 31.2 << 44.9 << true ;
例3:打印QT和opencv结构体数据类型。
mDebug() << Point(10, 10) << QPoint(100, 100);
例4:打印指针类型
mDebug() << ui;
第四:测试结果
结果1:在窗口打印5行信息
结果2:日志文件