Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redirect std::cout to QTextEdit

Tags:

c++

iostream

qt

Is it possible (and more importantly -how-) to redirect an output stream to a QTextBox. So that if I write std::cout << "test" anywhere in the application it gets redirected to a textbox I defined?

I tried the obvious (where ui.textEdit is a pointer to the text edit box):

std::cout.rdbuf(ui.textEdit);
std::cout << "test";

However this doesn't work. (obviously). - Nor does redirecting cout to qDebug work (or even direction a qDebug to a textfield).

I'm using qt4.8 btw...

EDIT: So I tried the solution posted in the mailing list.. However now an access violation shows up.

class MainInterface : public QMainWindow
{
    Q_OBJECT
....
private: 
    QDebugStream qout

With the constructor:

MainInterface::MainInterface(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags),
    qout(std::cout, ui.textEdit)
{

And in a member function the following line is posted: std::cout << "Project Loaded" << std::endl;

That line now causes an access violation from "qscoped_pointer". (Should I post this with more detail as seperate question?)

EDIT: well the "solution" was to only declare qout after the ui.textEdit was fully created.

like image 228
paul23 Avatar asked Nov 04 '22 06:11

paul23


2 Answers

I wrote my own function for this problem , for a QTextEdit, just be aware that if you run it with heavy operations along the main Thread your GUI will freeze. So you have to instantiate a new QThread for example then the GUI respectively the QTextEdit will be updated accordingly:

Header File:

class myConsoleStream :  public std::basic_streambuf<char>
{

public:
    myConsoleStream(std::ostream &stream, QTextEdit* text_edit);

    virtual ~myConsoleStream();
    static void registerMyConsoleMessageHandler();

private:

    static void myConsoleMessageHandler(QtMsgType type, const QMessageLogContext &, const QString &msg);

protected:


    // Diese Funktion wird aufgerufen wenn std::endl im Stream erscheint
    virtual int_type overflow(int_type v)
        {
            if (v == '\n')
            {
                log_window->append("");
            }
            return v;
        }

    virtual std::streamsize xsputn(const char *p, std::streamsize n);

private:

    std::ostream &m_stream;
    std::streambuf *m_old_buf;
    QTextEdit* log_window;

};
#endif // Q_DEBUGSTREAM_H

.cpp File:

myConsoleStream::myConsoleStream(std::ostream &stream, QTextEdit* text_edit)
    :std::basic_streambuf<char>()
    ,m_stream(stream)


{
    this->log_window = text_edit;
    this->m_old_buf = stream.rdbuf();

    stream.rdbuf(this);

}

myConsoleStream::~myConsoleStream()
{
    this->m_stream.rdbuf(this->m_old_buf);
}

void myConsoleStream::registerMyConsoleMessageHandler()
{
    qInstallMessageHandler(myConsoleMessageHandler);
}


void myConsoleStream::myConsoleMessageHandler(QtMsgType type, const QMessageLogContext &, const QString &msg)
{

    QByteArray localMsg = msg.toLocal8Bit();
       switch (type) {
       case QtDebugMsg:
          // fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
           break;
       case QtInfoMsg:
          // fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
           break;
       case QtWarningMsg:
          // fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
           break;
       case QtCriticalMsg:
           //fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
           break;
       case QtFatalMsg:
          // fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
           break;
       default:
            std::cout << msg.toStdString().c_str();
           break;

       }
}

In your mainwindow you just have to instantiate your new Stream :

new myConsoleStream(std::cout, this->ui->Console);
  myConsoleStream::registerMyConsoleMessageHandler(); 

and you are good too go! Hope this helps.

like image 90
Astraeus Avatar answered Nov 12 '22 17:11

Astraeus


You could reset cout to your own ostream implementation which would emit signals which you hook onto the append slot. You sub-problems/exercises are therefore:

  1. redirect cout
  2. redirect cout to your own ostream implementation or one that you can extend
  3. emit signals to QTextBox

These sub-topics are available on SO, as far as I know

like image 27
Sebastian Mach Avatar answered Nov 12 '22 17:11

Sebastian Mach