Search code examples
c++qtqtimerqtextbrowser

Insert text in while(1) loop to texteditor in QT


Am trying to print "Some text" to QTextBrowser, continuously for "n" time. Where "n" is integer. For this I have used QTimer::SingleShot for timing. Once the timeout is triggered a FLAG is set to false and this "FLAG" is monitored in while loop to break when FLAG is false and it shall insert the text till FLAG is set to FALSE. Initial value for FLAG is true.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    FLAG = true;

}

void MainWindow::on_pushButton_clicked()
{
    ui->pushButton->setEnabled(false);
   RunTheTimer();
    int counter = 0;

    do
    {
        ui->textBrowser->insertPlainText(QString("Inside While loop %1 \n").arg(counter++));
        counter++;
    }while(FLAG);

    FLAG = true;

}
void MainWindow::RunTheTimer()
{
     ui->textBrowser-> insertPlainText("Timer Started");
    QTimer::singleShot(60000, this, SLOT(Update()));// One Minute

}

void MainWindow::Update()
{
   ui->textBrowser-> insertPlainText("Timeout signal triggered");
    ui->pushButton->setEnabled(true);
   FLAG = false;
}
MainWindow::~MainWindow()
{
    delete ui;
}

Application is getting Hang, When I click Pushbutton. After debugging I observed, timeout is not triggering once the execution is entered to while(1) loop and application is not able to insert any text inside while(1) loop. Why this behavior? What am I doing wrong?

Thanks.


Solution

  • You are not returning control to the event loop, many things in Qt are not designed to work without an event loop, Have a look at this page from the Qt wiki, in your case:

    • QTextBrowser won't be able to show the newly added text, since this requires the widget to be able to receive paint events (and this is impossible without an event loop).
    • The timer that sets your flag to false won't be able to fire, since your program is always busy executing your while loop, and it won't be able to do anything else (unless it gets out from that while loop and this is impossible if it does not set your flag to false. . .).

    Instead of using an endless loop, if you want to execute something as repeatedly as possible, you can use a QTimer and set its interval property to 0, this is a special value that causes the timer to timeout as soon as the event loop finishes processing all events in the event queue.

    Using the above approach instead of your endless loop, you can use another timer to stop the above timer after a specific amount of time, and you don't have to worry about events not arriving and timers not firing since the event loop is always executing now.

    Here is a possible implementation of the above approach:

    screenshot

    #include <QtWidgets>
    
    int main(int argc, char* argv[]){
        QApplication a(argc, argv);
    
        //set up GUI
        QWidget widget;
        QVBoxLayout layout(&widget);
        QTextBrowser textBrowser;
        QPushButton button("Add Text");
        layout.addWidget(&textBrowser);
        layout.addWidget(&button);
    
        //timer with 0 interval instead of while loop
        QTimer workTimer;
        workTimer.setInterval(0);
        int counter=0;
        QObject::connect(&workTimer, &QTimer::timeout, [&]{
            //add text to textBrowser whenever the workTimer fires
            textBrowser.append(QStringLiteral("Additional Text %1").arg(counter++));
        });
        //when the button is clicked
        QObject::connect(&button, &QPushButton::clicked, [&]{
            //start work timer
            workTimer.start();
            button.setEnabled(false);
            //stop work timer after 5 seconds
            QTimer::singleShot(5000, [&]{
                workTimer.stop();
                button.setEnabled(true);
            });
        });
        widget.show();
    
        return a.exec();
    }