Is there a cross-platform possibility to capture a printf() from stdout (No QProcess)?
-
Hi,
I am writing my first QT Gui Application thus I am not very experienced yet regarding QT.
I use a standard c library (http://libnodave.sourceforge.net/) in my project to communicate with an industrial controller (PLC).In that library are several printf()-Statements which I want to redirect to qdebug() (or use it in some place on the GUI). This has to work on both linux and windows.
Could anyone help me to find some hints to do that? I tried some code snippets from some old mailing list posts which did not work and I am completely frustrated. The problem first sounded not very complicated but the deeper I look for a solution the more I despair of it.
I appreciate any hint you could give me.
Thanks in advance.Jochen
-
Hi,
is this of any help to you?
http://qt-project.org/forums/viewthread/23075Regards
Buggy -
Or hopefully this one fits better (incidentally, it also mentions a guy named Jochen ;)
http://lists.qt.nokia.com/public/qt-interest/2011-January/030998.htmlRegards
Buggy -
Hi,
indeed I found that two posting and the first thread seems to be worth a try.
Unfortunately the link to the code of that guy in the second thread is not working anymore and I did not findhttp://lists.trolltech.com/qt-interest/2005-06/thread00166-0.html
somewhere else :-(
-
Hi,
here is an "old copy":http://web.archive.org/web/20120109050130/http://lists.trolltech.com/qt-interest/2005-06/thread00166-0.html
But from my understanding you did not look for a std::string based solution anyway but for the C printf one?
-
Hi, seems what you are looking is:
http://stackoverflow.com/questions/5911147/how-to-redirect-printf-output-back-into-code
-
[quote author="devjb" date="1372758457"]Hi, thanks for the hint.
That code example might indeed do its work. But as far as I see, I have to execute it somehow cyclic with a timer to do what I want. That does not sound like an elegant way, does it?Regards
Jochen[/quote]
Yes, but you can use select() under posix system and Io Completion Port under windows system to watch the pipe if you want.
The source code of QProcess can be used as reference.
-
Hi, FYI, I just implement a new class with asynchronous I/O.
https://github.com/dbzhang800/StdoutRedirector
Simply create a instance of StdoutRedirector, then watch the readyRead() signal of it.
@
redirector = new StdoutRedirector(this, StdoutRedirector::StandardOutput|StdoutRedirector::StandardError);
connect(redirector, SIGNAL(readyRead()), this, SLOT(...));
@When data exists, read() can be used to get the data.
@
QByteArray StdoutRedirector::read(qint64 maxlen)
@ -
Thank you,
nice solution.
I just finished a solution for me on my own yesterday, based on the above-mentioned stackoverflow post. It catches every stdout output and throws it on the debug console as well as in a widget on the main window.
Regards
Jochen
main.cpp:
@//configure stdout to autoflush (seems it needs slight changes on win)
setvbuf(stdout, NULL, _IONBF, 0);@stdoutredirector.h:
@#ifndef STDOUTREDIRECTOR_H
#define STDOUTREDIRECTOR_H
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QMainWindow>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
/* gcc defined unix */
#ifdef LINUX
#include <unistd.h>
#endif
#ifdef BCCWIN
#include <io.h>
#define pipe(X) _pipe(X,4096,O_BINARY)
#define fileno _fileno
#define dup2 _dup2
#define read _read#endif
#include <assert.h>class stdoutRedirector : public QThread
{
Q_OBJECT
public:stdoutRedirector(); ~stdoutRedirector(); void run();
signals:
void writeOut(QString);
public slots:
void terminate();private:
int fds[2]; int res; char buf[256]; int so; bool terminate_;
};
#endif // STDOUTREDIRECTOR_H@
logtoparent.h:
@#ifndef LOGTOPARENT_H
#define LOGTOPARENT_H
#include "mainwindow.h"
#include <QMainWindow>
#include <QString>class logToParent : public QMainWindow
{
Q_OBJECT
public:
explicit logToParent(MainWindow *parent = 0);
~logToParent();
QStatusBar *parentStatbar;
signals:
void threadTerminator();
public slots:void updateParentLog(QString logString);
};
#endif // LOGTOPARENT_H@
logtoparent.cpp:
@#include "logtoparent.h"
using namespace std;logToParent::logToParent(MainWindow *parent) :
QMainWindow(parent)
{
stdoutRedirector * myRedirector = new stdoutRedirector;
connect(this, SIGNAL(threadTerminator()),myRedirector,SLOT(terminate()));
cout << "Debug: Qthread for logging run: " << myRedirector->isRunning() << endl;
myRedirector->start();
cout << "Debug: Logger constructed" << endl;
cout << "Debug: Qthread for logging run: " << myRedirector->isRunning() << endl;
parentStatbar = parent->ui->statusBar;
connect(myRedirector, SIGNAL(writeOut(QString)),this,SLOT(updateParentLog(QString)));
}logToParent::~logToParent()
{
emit threadTerminator();
}void logToParent::updateParentLog(QString logString)
{
parentStatbar->showMessage(logString,2500);}@
stdoutredirector.cpp:
@#include "stdoutredirector.h"stdoutRedirector::stdoutRedirector()
{
res=pipe(fds);
assert(res==0);so=fileno(stdout); // close stdout handle and make the writable part of fds the new stdout. res=dup2(fds[1],so); assert(res!=-1); terminate_ = false;
}
stdoutRedirector::~stdoutRedirector()
{}
void stdoutRedirector::run()
{Q_FOREVER{ res=read(fds[0],buf,sizeof(buf)-1); assert(res>=0 && res<sizeof(buf)); buf[res]=0; emit writeOut(buf); qDebug() << buf; //fprintf(stderr,"printf: %s\n",buf); if (terminate_) { return; } }
}
void stdoutRedirector::terminate()
{
terminate_ = true;
}
@and finally, in main window's constructor:
@logToParent* logger = new logToParent(this);@