This is my Logging class:
#include "log.h"
#include "ui_log.h"
#include <QDebug>
#include <QMutex>
bool Log::logOpen = false;
Log::Log(QWidget *parent) : QDialog(parent), ui(new Ui::Log)
{
ui->setupUi(this);
text = new QString;
this->bar = this->ui->logText->verticalScrollBar();
connect(this, SIGNAL(call_write(char*)), this, SLOT(write(char*)));
}
Log::~Log()
{
delete ui;
}
void Log::on_buttonClose_clicked()
{
Log::logOpen = false;
close();
}
void Log::on_buttonClear_clicked()
{
this->text->clear();
this->ui->logText->clear();
}
void Log::write(char *msg)
{
this->text->append(msg);
this->ui->logText->setPlainText(*this->text);
this->bar->setValue(bar->maximum());
free(msg);
}
void write_c(Log *ptr, char *msg) {
emit ptr->call_write(msg);
}
void r_printf(char *format, ...) {
char *buf = (char*) malloc(4096);
va_list argList;
va_start(argList, format);
vsnprintf(buf, 4096,format, argList);
va_end(argList);
write_c(logptr, buf);
}
This is, by far, THE most complicated piece of code I have ever written. This is how it works: r_printf(char *format, ...)
can be called from either C or C++, it takes the format
and va_list
arguments, and formats them. Then, it calls write_c
, which sends a signal the Logger, which is connected to itself, so the Qt scheduler schedules an update to the window by calling write()
, so that Qt does not freak out. Crazy, right?
Here is the log header, log.h
#ifndef LOG_H
#define LOG_H
#include <stdarg.h>
#ifdef __cplusplus
#include <QDialog>
#include <QString>
#include <QScrollBar>
namespace Ui {
class Log;
}
class Log : public QDialog
{
Q_OBJECT
public:
static bool logOpen;
explicit Log(QWidget *parent = 0);
~Log();
Ui::Log *ui;
QString *text;
QScrollBar *bar;
private slots:
void on_buttonClose_clicked();
void on_buttonClear_clicked();
void write(char *msg);
signals:
void call_write(char *msg);
};
#else
typedef struct Log Log;
#endif // __cplusplus
#ifdef __cplusplus
#define EXPORT_C extern "C"
#else
#define EXPORT_C
#endif
extern Log *logptr;
EXPORT_C void write_c(Log *ptr, char *msg);
EXPORT_C void r_printf(char *format, ...);
#endif // LOG_H
logptr
is the pointer to a Log object inside the Main window.
While this does work, and it does not corrupt memory, is there a better solution to this huge mess? Is this a good solution? Can it be improved?
The goal is to have something like printf(char *format, ...)
which can be called from either thread, from either C or C++. It should always work.