Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Catching all stdout (cout and maybe printf?) to QtextEdit

Catching all stdout (cout and maybe printf?) to QtextEdit

Scheduled Pinned Locked Moved General and Desktop
7 Posts 4 Posters 8.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    CodeMonkey99
    wrote on 19 Nov 2014, 14:37 last edited by
    #1

    Having seen this very topic in my search of many other threads, I still can't get my code to work. Any guidance or advice would be very much appreciated by this Qt-newbie.

    My intent is to capture each line of standard output cout (and possibly printf) from a library (or sub-function) in a QtextEdit box. I would like to get the "live" updates (otherwise I would just return a string from the library function and post that to the Qtextedit). I suspect the problem with my code is that I'm not actually launching a seperate process exactly: instead of launching a command line program, I'm just calling a library or sub-function. (I think I'm not properly using the Qprocess object.)

    Code follows:

    @#include "uic.h"
    #include "ui_uic.h"
    #include <qobject.h>
    #include <qprocess.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include <qstring.h>
    #include <qdebug.h>
    #include <assert.h>

    QProcess* proc; // global

    ////##############################################
    UIC::UIC(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::UIC)
    {
    ui->setupUi(this);

    // Directly write to QtextEdit box
    ui->UIC_text->append("Directly Appending!");
    
    // QProcess related code
    proc = new QProcess( this );
    proc->waitForStarted();
    
    // make connections
    assert( connect( proc, SIGNAL(readyReadStandardOutput()),
               this, SLOT(my_readFromStdOut()) ));
    
    assert( connect( proc, SIGNAL(readyRead()),
               this, SLOT(my_readFromStdOut()) ));
    
    
    std::cout << "\n Test1\n";
    printf("\n Test2 \n");
    

    }
    ////##############################################
    UIC::~UIC()
    {
    delete proc;
    delete ui;
    }
    ////##############################################
    void UIC::my_readFromStdOut()
    {
    qDebug()<< "Reached Connected Slot!!!!!";

    ui->UIC_text->append( proc->readAll() );
    ui->UIC_text->append( proc->readAllStandardOutput() );
    ui->UIC_text->append( proc->readAllStandardError() );
    

    }
    ////##############################################
    void UIC::on_pb_clicked() // on pushbutton clicked
    {
    qDebug()<< "Got to clicked!";
    std::cout << "Some Text from Button! \n";
    do_something();
    printf("\n Again \n");
    }
    ////##############################################
    void do_something(void)
    {
    std::cout << "\nIn Subfunction Test1\n";
    printf("\n In Subfunction Test2\n");
    }
    ////##############################################

    @

    The slot "my_readFromStdOut" is never reached and no standard output reaches the Qtextbox.

    I'm using Qt Creator 3.2.2 based on Qt 5.3.2 on a Win7 machine. Again, I would sincerely appreciate any guidance or help!

    1 Reply Last reply
    0
    • C Offline
      C Offline
      CodeMonkey99
      wrote on 20 Nov 2014, 22:28 last edited by
      #2

      DBoosalis, Ok - that clears things up for me a bit. I have been reading the Qt documentation and all, but some of these big-picture type things are tough to figure out. Thank you.

      MuldeR, Wow - thank you very much for that code you pasted. It's been a little tricky trying to get the output from the new thread back to the QtTextEdit display, but I think I'm almost there. When it's all working I will post the code here.

      1 Reply Last reply
      0
      • M Offline
        M Offline
        MuldeR
        wrote on 20 Nov 2014, 23:14 last edited by
        #3

        [quote author="CodeMonkey99" date="1416522519"] It's been a little tricky trying to get the output from the new thread back to the QtTextEdit display[/quote]

        The sample code was just to show how it can be done in principle. In Qt, I'd use a QThread for this purpose and return the captured strings via a queued signal.

        My OpenSource software at: http://muldersoft.com/

        Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

        Go visit the coop: http://youtu.be/Jay...

        1 Reply Last reply
        0
        • C Offline
          C Offline
          CodeMonkey99
          wrote on 21 Nov 2014, 22:56 last edited by
          #4

          That makes more sense.. I've had a little time to get back to this. I think I'm almost there: I can catch stdout in "real-time" (as shown in the time stamp form the output). However, though the text is captured real time, it isn't displayed real time. It only shows up on the Qtextbox in one giant chunk when the "do_something" function completes and then the pushbutton slot finishes execution. In other words all of the captured text shows up as one big block with no delay (which I would expect with intermiediate output).

          Output:

          Main thread constructor:: 0x13f8
          Captured: Test1 0.0002
          Captured: Test2 0.0002
          --------------------------------Button Clicked

             Directly Written
          

          Captured: COUT from Button! 2.3368
          Captured: In subfunction COUT.. 2.3392
          Captured: In subufnction PRINTF w/ DELAY! 3.8394

          How do properly connect it such that the output is displayed as soon as the string_out signal is sent?

          Code and listening class below:

          @#ifndef H_GET_STD
          #define H_GET_STD

          #include <Windows.h>
          #include <io.h>
          #include <fcntl.h>
          #include <qthread.h>
          #include <qdebug.h>

          #define BUFF_SIZE 4096

          // structure for timing functions
          typedef struct
          {
          LARGE_INTEGER freq;
          LARGE_INTEGER start;
          LARGE_INTEGER stop;
          } TICTOC;
          ////##############################################
          class stdout_worker : public QObject
          {
          Q_OBJECT

          signals:
          void string_out(const QString &value);
          void update_display();

          public:
          int fd_pipe[2];

          FILE* fPipeRd;
          FILE* fPipeWr;
          TICTOC tt;
          ////##############################################
          void stdout_worker::qtic (TICTOC* timer)
          {
          QueryPerformanceFrequency(&timer->freq);
          QueryPerformanceCounter(&timer->start);
          }

          ////##############################################
          double stdout_worker::qtoc (TICTOC* timer)
          {

          QueryPerformanceCounter(&timer->stop);
          return (double) ((timer->stop.QuadPart)-(timer->start.QuadPart))/(timer->freq.QuadPart);

          }
          ////##############################################
          void stdout_worker::setup_monitoring()
          {
          //Create the pipe
          if(_pipe(fd_pipe, BUFF_SIZE, _O_TEXT) != 0)
          {
          abort();
          }

          //Get FILE pointers
          fPipeRd = _fdopen(fd_pipe[0], "r");
          fPipeWr = _fdopen(fd_pipe[1], "w");
          if(!(fPipeRd && fPipeWr))
          {
          abort();
          }

          //Replace stdout and stderr streams
          *stdout = *fPipeWr;
          *stderr = *fPipeWr;

          //Disable buffering
          setvbuf(stdout, NULL, _IONBF, 0);
          setvbuf(stderr, NULL, _IONBF, 0);
          }
          ////##############################################
          private slots:
          void monitor_stdout()
          {
          //Init the buffer
          char buffer [BUFF_SIZE];
          size_t currentPos = 0;

          this->qtic(&tt);

          //Process captured text
          while(!(feof(fPipeRd) || ferror(fPipeRd)))
          {
          const int c = fgetc(fPipeRd);
          if((c != EOF) && (c != '\r') && (c != '\n') && (c != '\b'))
          {
          if(currentPos < BUFF_SIZE)
          {
          buffer[currentPos++] = c;
          }
          }
          else
          {
          if(currentPos > 0)
          {
          buffer[(currentPos < BUFF_SIZE) ? currentPos : (BUFF_SIZE - 1)] = '\0';
          QString txt;
          txt.sprintf("%s %s %0.4lf", "Captured: ", buffer, this->qtoc(&tt));
          emit string_out(txt);
          Sleep(1);
          emit update_display();

           currentPos = 0;
          }
          

          }
          }
          }
          };

          ////#######################################################
          ////#######################################################
          ////#######################################################

          #endif

          @

          Main code:

          @
          #define BUFF_SIZE 4096

          ////##############################################
          UIC::UIC(QWidget *parent) :
          QMainWindow(parent),
          ui(new Ui::UIC)
          {
          ui->setupUi(this);
          QString txt;

          txt.sprintf("Main thread constructor:: %#x", QThread::currentThreadId());
          ui->UIC_text->append(txt);

          // private element in UIC
          stdout_thread = new QThread(); // listening thread for stdout

          // private element in UIC
          dsp_thread = new QThread(); // display thread

          // private element in UIC, instantiate listening object
          my_stdout = new stdout_worker();

          // move to thread
          my_stdout->moveToThread(stdout_thread);

          // setup listening object;
          my_stdout->setup_monitoring();

          // move display to display thread
          ui->UIC_text->moveToThread(dsp_thread);

          // when thread is started, launch onSTD
          connect(stdout_thread, SIGNAL(started()), my_stdout, SLOT(monitor_stdout()));

          stdout_thread->start();
          dsp_thread->start();

          //// link emitted text to text box
          //connect(my_stdout, SIGNAL(string_out(QString)), ui->UIC_text, SLOT(append(QString)), Qt::DirectConnection);
          //connect(my_stdout, SIGNAL(update_display()), ui->UIC_text, SLOT(repaint()), Qt::DirectConnection);

          // link emitted text to text box
          connect(my_stdout, SIGNAL(string_out(QString)), ui->UIC_text, SLOT(append(QString)), Qt::QueuedConnection);
          connect(my_stdout, SIGNAL(update_display()), ui->UIC_text, SLOT(repaint()), Qt::QueuedConnection);

          //connect(my_stdout, SIGNAL(string_out(QString)), ui->UIC_text, SLOT(update_text(QString)));

          printf("Test1 \n");
          std::cout << "Test2 \n ";

          }
          ////##############################################
          UIC::~UIC()
          {
          delete ui;
          }
          ////##############################################
          void UIC::on_pb_clicked()
          {
          ui->UIC_text->append("--------------------------------Button Clicked\n");
          ui->UIC_text->append(" Directly Written\n");
          std::cout << "COUT from Button! \n";
          ui->UIC_text->repaint();
          do_something();

          }
          ////##############################################

          void UIC::update_text(const QString &value)
          {
          ui->UIC_text->append(value);
          ui->UIC_text->repaint();

          }
          ////##############################################
          void do_something(void)
          {

          std::cout << "In subfunction COUT..\n"; fflush(stdout);
          

          Sleep(1500);
          printf("In subufnction PRINTF w/ DELAY!\n");
          }
          ////##############################################
          @

          1 Reply Last reply
          0
          • M Offline
            M Offline
            MuldeR
            wrote on 21 Nov 2014, 23:50 last edited by
            #5

            Sure, if you call a function that takes a lot of time from the main (GUI) thread, this will make your whole GUI "freeze" until the function has returned and thus control flow returns returns to the Qt event loop! That's why functions that compute longer than a few seconds should be moved into a "background" worker thread. Either that, or QApplications::processEvents() needs to be called in short intervals by the lengthy function. The latter needs to be used with care!


            Try:
            @void do_something(void)
            {
            for(int i = 0; i < 10; i++)
            {
            printf("In subufnction PRINTF w/ DELAY!\n");
            for(j = 0; j < 15; j++)
            {
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
            Sleep(100);
            }
            }
            }@

            My OpenSource software at: http://muldersoft.com/

            Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

            Go visit the coop: http://youtu.be/Jay...

            1 Reply Last reply
            0
            • O Offline
              O Offline
              OlegOleg
              wrote on 10 Jul 2019, 16:55 last edited by OlegOleg 7 Oct 2019, 17:29
              #6

              hello CodeMonkey99, I am trying to do the exactly same thing you tried to do, i.e. redirecting output from std::cout to a QTextBrowser. I tried to run the code

              proc = new QProcess( this );
              

              and then connecting the readyReadStandardOutput() signal to my self-defined slot function. After that I tried QProcess::waitForStarted(). However by calling QProcess::state() it turned out that the QProcess has never started! is this really the right way to do it?

              I tried to sift through the code and discussion that follows your post, however they appear to be extremely disorganized and I do not understand what was going on.

              I'd appreciate it if you may tell me how you have overcome this problem.

              Thank you.

              jsulmJ 1 Reply Last reply 12 Jul 2019, 05:36
              0
              • O OlegOleg
                10 Jul 2019, 16:55

                hello CodeMonkey99, I am trying to do the exactly same thing you tried to do, i.e. redirecting output from std::cout to a QTextBrowser. I tried to run the code

                proc = new QProcess( this );
                

                and then connecting the readyReadStandardOutput() signal to my self-defined slot function. After that I tried QProcess::waitForStarted(). However by calling QProcess::state() it turned out that the QProcess has never started! is this really the right way to do it?

                I tried to sift through the code and discussion that follows your post, however they appear to be extremely disorganized and I do not understand what was going on.

                I'd appreciate it if you may tell me how you have overcome this problem.

                Thank you.

                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on 12 Jul 2019, 05:36 last edited by jsulm 7 Dec 2019, 05:36
                #7

                @OlegOleg said in Catching all stdout (cout and maybe printf?) to QtextEdit:

                it turned out that the QProcess has never started

                Then you should check why the process doesn't start.
                Connect a slot to https://doc.qt.io/qt-5/qprocess.html#errorOccurred and use https://doc.qt.io/qt-5/qiodevice.html#errorString in the slot to check what happened.
                Also, you can show how you're using QProcess.

                https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                2

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved