概述
Qt开发过程中经常需要输出调试日志,这些日志分为五个级别:qDebug、qWarning、qInfo、qCritical、qFatal。这些日志在调试过程中我们可以在开发工具的程序输出窗口查看,而实际使用的release版本脱离开发环境后则没办法显示这些信息。如果能在release版本中也将这些信息打印出来的话就可以方便后续程序维护及bug定位。
将日志信息重定向输出到txt文件中是一种不错的方法,实现也比较简单,但是需要去相应路径打开文件查看,不够直观。如果想实时查看输出日志的话可以将日志重定向输出到界面控件QTextEdit上,并且根据日志类别控制信息显示的颜色,本文提供这样一种实现手段。效果如下图所示
实现原理
1.qInstallMsgHandler函数用于安装之前定义的Qt消息处理程序。返回指向上一个消息处理程序的指针,其函数原型为:
QtMessageHandler qInstallMessageHandler(QtMessageHandler handler)
2.在myMessageOutput函数中将调试信息及信息类型(组合成结构体LogElement)输出至一个缓冲区队列中。
3.界面上设置定时读取队列数据显示在QTextEdit中,根据信息类型控制该行信息的颜色,实现代码如下。
main.cpp
#include "mainwindow.h"
#include <QApplication>
void LogMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
static QMutex mutex;
Q_UNUSED(context);
mutex.lock();
QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz");
QString message = QString("%1 %2\r\n").arg(current_date_time).arg(msg);
LogElement log_element={type,message};
log_txt.enqueue(log_element);
mutex.unlock();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qInstallMessageHandler(LogMessage);
qDebug()<<"startup application!";
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#define RED QColor(192,0,0)
#define GREEN QColor(0,192,0)
#define YELLOW QColor(192,192,0)
#define BLACK QColor(0,0,0)
#define GRAY QColor(128,128,128)
typedef struct{
QtMsgType type;
QString txt;
}LogElement;
extern QQueue<LogElement> log_txt;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_Timer0Timeout();
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
private:
Ui::MainWindow *ui;
QTimer *timer0;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
QQueue<LogElement> log_txt;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);;
timer0=new QTimer(this);
timer0->setInterval(100);
connect(timer0,&QTimer::timeout,this,&MainWindow::on_Timer0Timeout);
timer0->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_Timer0Timeout()
{
QTextCharFormat tcf;
while(log_txt.count()){
LogElement log_element=log_txt.dequeue();
switch (log_element.type) {
case QtMsgType::QtInfoMsg:
tcf.setForeground(Qt::blue);
break;
case QtMsgType::QtWarningMsg:
tcf.setForeground(Qt::red);
break;
default:
tcf.setForeground(Qt::black);
break;
}
ui->textEdit->moveCursor(QTextCursor::End);
ui->textEdit->textCursor().insertText(log_element.txt,tcf);
}
}
void MainWindow::on_pushButton_clicked()
{
qDebug()<<"提示:消息1!";
}
void MainWindow::on_pushButton_2_clicked()
{
qInfo()<<"警告:消息2!";
}
void MainWindow::on_pushButton_3_clicked()
{
qWarning()<<"错误:消息3!";
}