Browser for QDebug output: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:snippets]]
[[Category:Snippets::Misc]]
 
{{LangSwitch}}
'''English''' | [[Browser_for_QDebug_output_German|Deutsch]]
 
[toc align_right="yes" depth="4"]


= A Browser for QDebug Log Output =
= A Browser for QDebug Log Output =
Line 13: Line 10:
==== logbrowser.pro ====
==== logbrowser.pro ====


<code><br />QT ''= core gui
<code>
<br />TARGET = DebugWindow<br />TEMPLATE = app
QT += core gui
<br />SOURCES''= main.cpp logbrowserdialog.cpp logbrowser.cpp<br />HEADERS += logbrowserdialog.h logbrowser.h<br /></code>
 
TARGET = DebugWindow
TEMPLATE = app
 
SOURCES+= main.cpp logbrowserdialog.cpp logbrowser.cpp
HEADERS += logbrowserdialog.h logbrowser.h
</code>


==== logbrowser.h ====
==== logbrowser.h ====
Line 21: Line 24:
<code>
<code>


#ifndef LOGBROWSER_H<br />#define LOGBROWSER_H
#ifndef LOGBROWSER_H
#define LOGBROWSER_H


#include &lt;QObject&amp;gt;
#include <QObject>


class LogBrowserDialog;
class LogBrowserDialog;


class LogBrowser : public QObject<br />{<br /> Q_OBJECT<br />public:<br /> explicit LogBrowser(QObject *parent = 0);<br /> ~LogBrowser();
class LogBrowser : public QObject
{
Q_OBJECT
public:
explicit LogBrowser(QObject *parent = 0);
~LogBrowser();


public slots:<br /> void outputMessage( QtMsgType type, const QString &amp;msg );
public slots:
void outputMessage( QtMsgType type, const QString &msg );


signals:<br /> void sendMessage( QtMsgType type, const QString &amp;msg );
signals:
void sendMessage( QtMsgType type, const QString &msg );


private:<br /> LogBrowserDialog *browserDialog;
private:
LogBrowserDialog *browserDialog;


};
};


#endif // LOGBROWSER_H<br /></code>
#endif // LOGBROWSER_H
</code>


==== logbrowser.cpp ====
==== logbrowser.cpp ====
Line 43: Line 56:
<code>
<code>


#include &quot;logbrowser.h&amp;quot;
#include "logbrowser.h"


#include &lt;QMetaType&amp;gt;
#include <QMetaType>


#include &quot;logbrowserdialog.h&amp;quot;
#include "logbrowserdialog.h"


LogBrowser::LogBrowser(QObject *parent) :<br /> QObject(parent)<br />{<br /> qRegisterMetaType&amp;lt;QtMsgType&amp;gt;(&quot;QtMsgType&amp;quot;);<br /> browserDialog = new LogBrowserDialog;<br /> connect(this, SIGNAL (sendMessage(QtMsgType,QString)), browserDialog, SLOT (outputMessage(QtMsgType,QString)), Qt::QueuedConnection);<br /> browserDialog-&gt;show();<br />}
LogBrowser::LogBrowser(QObject *parent) :
QObject(parent)
{
qRegisterMetaType<QtMsgType>("QtMsgType");
browserDialog = new LogBrowserDialog;
connect(this, SIGNAL (sendMessage(QtMsgType,QString)), browserDialog, SLOT (outputMessage(QtMsgType,QString)), Qt::QueuedConnection);
browserDialog->show();
}


LogBrowser::~LogBrowser()<br />{<br /> delete browserDialog;<br />}
LogBrowser::~LogBrowser()
{
delete browserDialog;
}


void LogBrowser::outputMessage(QtMsgType type, const QString &amp;msg)<br />{<br /> emit sendMessage( type, msg );<br />}<br /></code>
void LogBrowser::outputMessage(QtMsgType type, const QString &msg)
{
emit sendMessage( type, msg );
}
</code>


==== logbrowserdialog.h ====
==== logbrowserdialog.h ====
Line 59: Line 86:
<code>
<code>


#ifndef DIALOG_H<br />#define DIALOG_H
#ifndef DIALOG_H
#define DIALOG_H


#include &lt;QDialog&amp;gt;
#include <QDialog>


class QTextBrowser;<br />class QPushButton;
class QTextBrowser;
class QPushButton;


class LogBrowserDialog : public QDialog<br />{<br /> Q_OBJECT
class LogBrowserDialog : public QDialog
{
Q_OBJECT


public:<br /> LogBrowserDialog(QWidget *parent = 0);<br /> ~LogBrowserDialog();
public:
LogBrowserDialog(QWidget *parent = 0);
~LogBrowserDialog();


public slots:<br /> void outputMessage( QtMsgType type, const QString &amp;msg );
public slots:
void outputMessage( QtMsgType type, const QString &msg );


protected slots:<br /> void save();
protected slots:
void save();


protected:<br /> virtual void keyPressEvent( QKeyEvent *e );<br /> virtual void closeEvent( QCloseEvent *e );
protected:
virtual void keyPressEvent( QKeyEvent *e );
virtual void closeEvent( QCloseEvent *e );


QTextBrowser *browser;<br /> QPushButton *clearButton;<br /> QPushButton *saveButton;<br />};
QTextBrowser *browser;
QPushButton *clearButton;
QPushButton *saveButton;
};


#endif // DIALOG_H<br /></code>
#endif // DIALOG_H
</code>


==== logbrowserdialog.cpp ====
==== logbrowserdialog.cpp ====
Line 83: Line 124:
<code>
<code>


#include &quot;logbrowserdialog.h&amp;quot;
#include "logbrowserdialog.h"
 
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTextBrowser>
#include <QPushButton>
#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QCloseEvent>
#include <QKeyEvent>
 
LogBrowserDialog::LogBrowserDialog(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout *layout = new QVBoxLayout;
setLayout(layout);
 
browser = new QTextBrowser(this);
layout->addWidget(browser);
 
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->setContentsMargins(0, 0, 0, 0);
layout->addLayout(buttonLayout);
 
buttonLayout->addStretch(10);
 
clearButton = new QPushButton(this);
clearButton->setText("clear");
buttonLayout->addWidget(clearButton);
connect(clearButton, SIGNAL (clicked()), browser, SLOT (clear()));
 
saveButton = new QPushButton(this);
saveButton->setText("save output");
buttonLayout->addWidget(saveButton);
connect(saveButton, SIGNAL (clicked()), this, SLOT (save()));
 
resize(200, 400);
}
 
 
LogBrowserDialog::~LogBrowserDialog()
{
 
}


#include &lt;QVBoxLayout&amp;gt;<br />#include &lt;QHBoxLayout&amp;gt;<br />#include &lt;QTextBrowser&amp;gt;<br />#include &lt;QPushButton&amp;gt;<br />#include &lt;QFileDialog&amp;gt;<br />#include &lt;QDir&amp;gt;<br />#include &lt;QFile&amp;gt;<br />#include &lt;QMessageBox&amp;gt;<br />#include &lt;QTextStream&amp;gt;<br />#include &lt;QCloseEvent&amp;gt;<br />#include &lt;QKeyEvent&amp;gt;


LogBrowserDialog::LogBrowserDialog(QWidget *parent)<br /> : QDialog(parent)<br />{<br /> QVBoxLayout *layout = new QVBoxLayout;<br /> setLayout(layout);
void LogBrowserDialog::outputMessage(QtMsgType type, const QString &msg)
{
switch (type) {
case QtDebugMsg:
browser->append(msg);
break;


browser = new QTextBrowser(this);<br /> layout-&gt;addWidget(browser);
case QtWarningMsg:
browser->append(tr("— WARNING: %1").arg(msg));
break;


QHBoxLayout '''buttonLayout = new QHBoxLayout;<br /> buttonLayout-&gt;setContentsMargins(0, 0, 0, 0);<br /> layout-&gt;addLayout(buttonLayout);
case QtCriticalMsg:
<br /> buttonLayout-&gt;addStretch(10);
browser->append(tr("— CRITICAL: %1").arg(msg));
<br /> clearButton = new QPushButton(this);<br /> clearButton-&gt;setText(&quot;clear&amp;quot;);<br /> buttonLayout-&gt;addWidget(clearButton);<br /> connect(clearButton, SIGNAL (clicked()), browser, SLOT (clear()));
break;
<br /> saveButton = new QPushButton(this);<br /> saveButton-&gt;setText(&quot;save output&amp;quot;);<br /> buttonLayout-&gt;addWidget(saveButton);<br /> connect(saveButton, SIGNAL (clicked()), this, SLOT (save()));
<br /> resize(200, 400);<br />}


<br />LogBrowserDialog::~LogBrowserDialog()<br />{
case QtFatalMsg:
<br />}
browser->append(tr("— FATAL: %1").arg(msg));
break;
}
}


<br />void LogBrowserDialog::outputMessage(QtMsgType type, const QString &amp;msg)<br />{<br /> switch (type) {<br /> case QtDebugMsg:<br /> browser-&gt;append(msg);<br /> break;
<br /> case QtWarningMsg:<br /> browser-&gt;append(tr(&quot;— WARNING: %1&amp;quot;).arg(msg));<br /> break;
<br /> case QtCriticalMsg:<br /> browser-&gt;append(tr(&quot;— CRITICAL: %1&amp;quot;).arg(msg));<br /> break;
<br /> case QtFatalMsg:<br /> browser-&gt;append(tr(&quot;— FATAL: %1&amp;quot;).arg(msg));<br /> break;<br /> }<br />}


<br />void LogBrowserDialog::save()<br />{<br /> QString saveFileName = QFileDialog::getSaveFileName(<br /> this,<br /> tr(&quot;Save Log Output&amp;quot;),<br /> tr(&quot;%1/logfile.txt&amp;quot;).arg(QDir::homePath()),<br /> tr(&quot;Text Files ('''.txt);;All Files (*)&quot;)<br /> );
void LogBrowserDialog::save()
{
QString saveFileName = QFileDialog::getSaveFileName(
this,
tr("Save Log Output"),
tr("%1/logfile.txt").arg(QDir::homePath()),
tr("Text Files (*.txt);;All Files (*)")
);


if(saveFileName.isEmpty())<br /> return;
if(saveFileName.isEmpty())
return;


QFile file&amp;amp;#40;saveFileName&amp;amp;#41;;<br /> if(!file.open(QIODevice::WriteOnly)) {<br /> QMessageBox::warning(<br /> this,<br /> tr(&quot;Error&amp;quot;),<br /> QString(tr(&quot;&lt;nobr&amp;gt;File '%1'&lt;br/&amp;gt;cannot be opened for writing.&lt;br/&amp;gt;&lt;br/&amp;gt;&quot;<br /> &quot;The log output could &lt;b&amp;gt;not&amp;lt;/b&amp;gt; be saved!&lt;/nobr&amp;gt;&quot;))<br /> .arg(saveFileName));<br /> return;<br /> }
QFile file(saveFileName);
if(!file.open(QIODevice::WriteOnly)) {
QMessageBox::warning(
this,
tr("Error"),
QString(tr("<nobr>File '%1'<br/>cannot be opened for writing.<br/><br/>"
"The log output could <b>not</b> be saved!</nobr>"))
.arg(saveFileName));
return;
}


QTextStream stream(&amp;file);<br /> stream &lt;&lt; browser-&gt;toPlainText();<br /> file.close();<br />}
QTextStream stream(&file);
stream << browser->toPlainText();
file.close();
}


void LogBrowserDialog::closeEvent(QCloseEvent *e)<br />{<br /> QMessageBox::StandardButton answer = QMessageBox::question(<br /> this,<br /> tr(&quot;Close Log Browser?&quot;),<br /> tr(&quot;Do you really want to close the log browser?&quot;),<br /> QMessageBox::Yes | QMessageBox::No<br /> );
void LogBrowserDialog::closeEvent(QCloseEvent *e)
{
QMessageBox::StandardButton answer = QMessageBox::question(
this,
tr("Close Log Browser?"),
tr("Do you really want to close the log browser?"),
QMessageBox::Yes | QMessageBox::No
);


if (answer == QMessageBox::Yes)<br /> e-&gt;accept();<br /> else<br /> e-&gt;ignore();<br />}
if (answer == QMessageBox::Yes)
e->accept();
else
e->ignore();
}


void LogBrowserDialog::keyPressEvent(QKeyEvent *e)<br />{<br /> // ignore all keyboard events<br /> // protects against accidentally closing of the dialog<br /> // without asking the user<br /> e-&gt;ignore();<br />}<br /></code>
void LogBrowserDialog::keyPressEvent(QKeyEvent *e)
{
// ignore all keyboard events
// protects against accidentally closing of the dialog
// without asking the user
e->ignore();
}
</code>


==== main.cpp ====
==== main.cpp ====
Line 123: Line 251:
<code>
<code>


#include &lt;QApplication&amp;gt;<br />#include &lt;QPointer&amp;gt;<br />#include &lt;QDebug&amp;gt;<br />#include &quot;logbrowser.h&amp;quot;
#include <QApplication>
#include <QPointer>
#include <QDebug>
#include "logbrowser.h"


QPointer&amp;lt;LogBrowser&amp;gt; logBrowser;
QPointer<LogBrowser> logBrowser;


void myMessageOutput(QtMsgType type, const char *msg)<br />{<br /> if(logBrowser)<br /> logBrowser-&gt;outputMessage( type, msg );<br />}
void myMessageOutput(QtMsgType type, const char *msg)
{
if(logBrowser)
logBrowser->outputMessage( type, msg );
}


int main(int argc, char *argv[])<br />{<br /> QApplication a(argc, argv);
int main(int argc, char *argv[])
{
QApplication a(argc, argv);


logBrowser = new LogBrowser;<br /> qInstallMsgHandler(myMessageOutput);
logBrowser = new LogBrowser;
qInstallMsgHandler(myMessageOutput);


qDebug() &lt;&lt; &quot;test for debug&amp;quot;;<br /> int result = a.exec&amp;amp;#40;&amp;#41;;<br /> qDebug() &lt;&lt; &quot;application exec return result =&quot; &lt;&lt; result;
qDebug() << "test for debug";
int result = a.exec();
qDebug() << "application exec return result =" << result;


delete logBrowser;<br /> return result;<br />}<br /></code>
delete logBrowser;
return result;
}
</code>

Latest revision as of 11:25, 24 February 2017

En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh

A Browser for QDebug Log Output

The code on this page shows how a simple log browser can be added to an application.

It consists of the actual log browser (class LogBrowserDialog in logbrowserdialog.h and logbrowserdialog.h) and a small wrapper (class LogBrowser in logbrowser.h and logbrowser.h). The wrapper is instantiated in the main function of an application and creates the browser window. It also acts as an intermediary and converts the const char * based messages from the debug system into QString based messages. With this trick the debug messages can be sent to the actual browser by the means of signal/slot connections. This adds basic thread support to the browser.

logbrowser.pro

QT += core gui

TARGET = DebugWindow
TEMPLATE = app

SOURCES+= main.cpp logbrowserdialog.cpp logbrowser.cpp
HEADERS += logbrowserdialog.h logbrowser.h

logbrowser.h

#ifndef LOGBROWSER_H
#define LOGBROWSER_H

#include <QObject>

class LogBrowserDialog;

class LogBrowser : public QObject
{
 Q_OBJECT
public:
 explicit LogBrowser(QObject *parent = 0);
 ~LogBrowser();

public slots:
 void outputMessage( QtMsgType type, const QString &msg );

signals:
 void sendMessage( QtMsgType type, const QString &msg );

private:
 LogBrowserDialog *browserDialog;

};

#endif // LOGBROWSER_H

logbrowser.cpp

#include "logbrowser.h"

#include <QMetaType>

#include "logbrowserdialog.h"

LogBrowser::LogBrowser(QObject *parent) :
 QObject(parent)
{
 qRegisterMetaType<QtMsgType>("QtMsgType");
 browserDialog = new LogBrowserDialog;
 connect(this, SIGNAL (sendMessage(QtMsgType,QString)), browserDialog, SLOT (outputMessage(QtMsgType,QString)), Qt::QueuedConnection);
 browserDialog->show();
}

LogBrowser::~LogBrowser()
{
 delete browserDialog;
}

void LogBrowser::outputMessage(QtMsgType type, const QString &msg)
{
 emit sendMessage( type, msg );
}

logbrowserdialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

class QTextBrowser;
class QPushButton;

class LogBrowserDialog : public QDialog
{
 Q_OBJECT

public:
 LogBrowserDialog(QWidget *parent = 0);
 ~LogBrowserDialog();

public slots:
 void outputMessage( QtMsgType type, const QString &msg );

protected slots:
 void save();

protected:
 virtual void keyPressEvent( QKeyEvent *e );
 virtual void closeEvent( QCloseEvent *e );

QTextBrowser *browser;
 QPushButton *clearButton;
 QPushButton *saveButton;
};

#endif // DIALOG_H

logbrowserdialog.cpp

#include "logbrowserdialog.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTextBrowser>
#include <QPushButton>
#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QCloseEvent>
#include <QKeyEvent>

LogBrowserDialog::LogBrowserDialog(QWidget *parent)
 : QDialog(parent)
{
 QVBoxLayout *layout = new QVBoxLayout;
 setLayout(layout);

browser = new QTextBrowser(this);
 layout->addWidget(browser);

QHBoxLayout *buttonLayout = new QHBoxLayout;
 buttonLayout->setContentsMargins(0, 0, 0, 0);
 layout->addLayout(buttonLayout);

 buttonLayout->addStretch(10);

 clearButton = new QPushButton(this);
 clearButton->setText("clear");
 buttonLayout->addWidget(clearButton);
 connect(clearButton, SIGNAL (clicked()), browser, SLOT (clear()));

 saveButton = new QPushButton(this);
 saveButton->setText("save output");
 buttonLayout->addWidget(saveButton);
 connect(saveButton, SIGNAL (clicked()), this, SLOT (save()));

 resize(200, 400);
}


LogBrowserDialog::~LogBrowserDialog()
{

}


void LogBrowserDialog::outputMessage(QtMsgType type, const QString &msg)
{
 switch (type) {
 case QtDebugMsg:
 browser->append(msg);
 break;

 case QtWarningMsg:
 browser->append(tr("— WARNING: %1").arg(msg));
 break;

 case QtCriticalMsg:
 browser->append(tr("— CRITICAL: %1").arg(msg));
 break;

 case QtFatalMsg:
 browser->append(tr("— FATAL: %1").arg(msg));
 break;
 }
}


void LogBrowserDialog::save()
{
 QString saveFileName = QFileDialog::getSaveFileName(
 this,
 tr("Save Log Output"),
 tr("%1/logfile.txt").arg(QDir::homePath()),
 tr("Text Files (*.txt);;All Files (*)")
 );

if(saveFileName.isEmpty())
 return;

QFile file(saveFileName);
 if(!file.open(QIODevice::WriteOnly)) {
 QMessageBox::warning(
 this,
 tr("Error"),
 QString(tr("<nobr>File '%1'<br/>cannot be opened for writing.<br/><br/>"
 "The log output could <b>not</b> be saved!</nobr>"))
 .arg(saveFileName));
 return;
 }

QTextStream stream(&file);
 stream << browser->toPlainText();
 file.close();
}

void LogBrowserDialog::closeEvent(QCloseEvent *e)
{
 QMessageBox::StandardButton answer = QMessageBox::question(
 this,
 tr("Close Log Browser?"),
 tr("Do you really want to close the log browser?"),
 QMessageBox::Yes | QMessageBox::No
 );

if (answer == QMessageBox::Yes)
 e->accept();
 else
 e->ignore();
}

void LogBrowserDialog::keyPressEvent(QKeyEvent *e)
{
 // ignore all keyboard events
 // protects against accidentally closing of the dialog
 // without asking the user
 e->ignore();
}

main.cpp

#include <QApplication>
#include <QPointer>
#include <QDebug>
#include "logbrowser.h"

QPointer<LogBrowser> logBrowser;

void myMessageOutput(QtMsgType type, const char *msg)
{
 if(logBrowser)
 logBrowser->outputMessage( type, msg );
}

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

logBrowser = new LogBrowser;
 qInstallMsgHandler(myMessageOutput);

qDebug() << "test for debug";
 int result = a.exec();
 qDebug() << "application exec return result =" << result;

delete logBrowser;
 return result;
}