PDA

View Full Version : GUI Updates from separate Thread



sa5webber
16th June 2012, 07:24
I have a GUI containing a QTableWidget whose rows contain strings. The strings are processed in a separate thread in order to keep the GUI free for providing status by selecting each row as the string in that row is being processed and also to abort the overall processing if desired. My problem is that the GUI's QTableWidget does not show/update row selection for each row until after all the rows have already been processed even though the GUI slot that performs the selectRow is called correctly at the right time. It looks as if the QTableWidget selectRow is queued for later execution after the thread is finished.

I did see one comment which suggested that the problem might be the thread wait executed after the thread start, but without the wait the program crashes with the error that the thread was terminated before processing was complete. What do I need to do to get the GUI to update the row selection on the QTableWidget when I execute the emit from the separate thread?



mainwindow.cpp
***************************************
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <stdexcept>

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

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_btnRun_clicked()
{
TestThread testThread(this);
testThread.TestCmds(_testCmds);
testThread.SetStartIndex(0);
connect(&testThread, SIGNAL(stepChanged(int)), this, SLOT(testThreadStepChanged(int)));
connect(&testThread, SIGNAL(finished()), this, SLOT(testThreadFinished()));
testThread.start();
testThread.wait();
}

void MainWindow::testThreadStepChanged(int step)
{
// tblCmds is a QTableWidget with rows of strings
ui->tblCmds->selectRow(step);
ui->tblCmds->repaint();
}

void MainWindow::testThreadFinished()
{
qDebug("Received Thread Finished Signal");
}

mainwindow.h
***************************************
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "qthread.h"
#include "qtablewidget.h"
#include "testthread.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private slots:
void on_btnRun_clicked();
void testThreadStepChanged(int step);
void testThreadFinished();

private:
Ui::MainWindow *ui;
QStringList _testCmds;
};

#endif // MAINWINDOW_H


testthread.cpp
***************************************
#include "testthread.h"

TestThread::TestThread(QObject *parent) :
QThread(parent)
{
}

void TestThread::run()
{
for(int si=_startIndex; si < _testCmds.count(); si++)
{
if(_stopFlag) return;
emit stepChanged(si);
}
}

testthread.h
***************************************
#ifndef TESTTHREAD_H
#define TESTTHREAD_H

#include <QThread>

class TestThread : public QThread
{
Q_OBJECT
public:
explicit TestThread(QObject *parent = 0);

void SetStartIndex(int startIndex);
void TestCmds(QStringList testCmds);
void Stop();

signals:
void stepChanged(int step);

public slots:

private:
void run();

QStringList _testCmds;
int _startIndex;
bool _stopFlag;
};

#endif // TESTTHREAD_H

wysota
16th June 2012, 08:07
Creating an object on a stack will destroy that object when the scope where the object was created ends. Create the object on the heap instead.

Lesiok
16th June 2012, 08:08
1. You ARE blocking GUI thread beacuse second thread is created in slot on_btnRun_clicked() and You are waiting in this slot for finishing this thread.
2. In worker thread You are NOT starting event loop. So signals from worker thread are NOT provided to main thread.

wysota
16th June 2012, 08:26
2. In worker thread You are NOT starting event loop. So signals from worker thread are NOT provided to main thread.
This is actually false. Signals don't need an event loop, only slots do.

Lesiok
16th June 2012, 17:09
This is actually false. Signals don't need an event loop, only slots do.
My mistake. Thank you for correcting Wysota.

sa5webber
16th June 2012, 20:08
Auggh, that should have been obvious to me now that you point it out. Made the necessary changes and it now works like a charm. Thanks.