The method I use to report to multiple types of output is to use an abstract "Logger" base class. Then, inherit classes from Logger, one for GUI and for CLI or whatever else you want to log to. Every object that sends to the log simply emits a Log(const QString&), which is picked up by the relevant class.
/// An interface to be implemented by loggers.
class ILogger : public QObject
{
Q_OBJECT
public:
ILogger(QObject* parent = {});
Q_SLOT virtual void Log(const QString& txt) = 0;
};
ILogger::ILogger(QObject* parent) : QObject(parent) {}
/// Logs to a QPlainTextEdit
class TextBoxGUILogger : public ILogger
{
Q_OBJECT
public:
TextBoxGUILogger(QObject* parent = {});
void setWidget(QPlainTextEdit*);
void Log(const QString& txt) override;
private:
QPointer<QTextEdit> m_txtEditBox;
};
TextBoxGUILogger::TextBoxGUILogger(QObject* parent) : ILogger(parent) {}
void TextBoxGUILogger::setWidget(QPlainTextEdit* edit)
{
m_txtEditBox = edit;
}
void TextBoxGUILogger::Log(const QString& txt)
{
if (m_txtEditBox) m_txtEditBox->append(txt);
}
/// Logs to the standard output.
class CLILogger : public ILogger
{
Q_OBJECT
public:
CLILogger(QObject* parent = {});
void Log(const QString& txt) override;
};
CLILogger::CLILogger(QObject* parent) : ILogger(parent) {}
void CLILogger::Log(const QString& txt)
{
printf("%s", txt.toLocal8Bit().constData());
}
/// Logs to a file.
class FileLogger : public ILogger
{
Q_OBJECT
public:
FileLogger(QObject* parent = {});
/// The file can be owned by another object, or it can be made a child
/// of the logger. In either case the behavior will be correct.
void setFile(QFile*);
void Log(const QString& txt) override;
private:
QPointer<QFile> m_file;
};
FileLogger::FileLogger(QObject* parent) : ILogger(parent) {}
void FileLogger::setFile(QFile* file)
{
m_file = file;
}
void FileLogger::Log(const QString& txt)
{
if (m_file)
m_file->write(txt.toLocal8Bit().constData());
}
So, you can now create the relevant logger...
For standard output (CLI): -
ILogger* pLogger = new CLILogger;
Or QPlainTextEdit
: -
ILogger* pLogger = new TextBoxGuiLogger;
Finally, to a file: -
ILogger* pLogger = new FileLogger;
Each class that is going to log connects to the logger: -
// Qt 5 connect syntax
connect(someClass, &SomeClass::Log, pLogger, &ILogger::Log);
This allows you to create one or more logging objects at the same time and the objects that log don't care what it is that is doing the logging, they just emit a signal: -
emit Log("Log this text");