QThread updating a Widget in the GUI



  • Good day

    I am writing an application which has to update a QLable with info from a QThread in real time. I am stuck at the point where only the last emit is received by the QLable, for some reason. Here is my code:

    #ifndef RANDWALK_H
    #define RANDWALK_H
    
    #include <QThread>
    #include <QStringList>
    #include <QTime>
    #include <QDebug>
    
    class RandWalk : public QThread
    {
        Q_OBJECT
    public:
        RandWalk();
    
    public slots:
        void generateCoordinates(int steps, QStringList start);
    
    signals:
        void message(QString);
    
    private:
        int x;
        int y;
    
    };
    
    #endif // RANDWALK_H
    
    #include "randwalk.h"
    
    RandWalk::RandWalk()
    {
    }
    
    void RandWalk::generateCoordinates(int steps, QStringList start)
    {
        int startX = start.at(0).toInt();
        int startY = start.at(1).toInt();
        QTime time = QTime::currentTime();
        int seed = time.msec();
        QStringList rList;
        qsrand(seed);
        for(int i = 0; i < steps; i++)
        {
            rList << QString::number(qrand() + startX) + ", " +
                     QString::number(qrand() + startY);
            qDebug() << rList.at(i);
            emit message(rList.at(i));
            this->sleep(1);
        }
    }
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        walker1 = new RandWalk;
        walker1->start();
        connect(walker1, SIGNAL(message(QString)), ui->locationLbl, SLOT(setText(QString)));
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_goBtn_clicked()
    {
        QStringList start1;
        start1 << ui->xLedt->text() << ui->yLedt->text();
        walker1->generateCoordinates(10, start1);
    }
    `
    
    Your help will be much appreciated.
    
    Thank you


  • Usually Qt tries to "compact" the refresh requests; this is to avoid flickering.

    You could try to manually call QWidget::repaint() in a slot



  • @mcosta
    Thanks for the reply. I am not sure that this is the problem, because I have increased the sleep intervals in my iteration in the Thread to 5 seconds, and the label still only updates on the last one.
    Also, there is no place to call repaint() from, in my current program structure. What I mean is that the signal is emitted from the walker object, which also dictates the intervals.



  • I suggest to create a custom slot in you class and call setText and repaint from there; in that way you can be able to detect how often the signal is received

    void MainWindow::mySlot(const QString &text)
    {
        qDebug() << Q_FUNC_INFO;
        ui->locationLbl->setText(text);
        ui->locationLbl->repaint();
    }
    
    connect(walker1, SIGNAL(message(QString)), this, SLOT(mySlot(QString)));
    


  • It looks like your RandWalk thread isn't actually running. You are calling generateCoordinates() from the GUI thread, so it's holding up the program there. That explains why you only see the last update.

    The QThread documentation shows a couple different ways to do work in another thread:
    http://doc.qt.io/qt-5/qthread.html



  • @mcosta
    Good day
    Apologies for only replying now - we had an internet outage...
    Just after my last reply I tried your previous suggestion (to manually call QWidget::repaint() ) out a bit more, and it worked.
    Thank you very much!


  • Moderators

    As @Dyami-Caliri said your program is not using the thread at all.
    You are calling both generateCoordinates() and repaint() in the ui thread. There's no parallel execution here.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.