PDA

View Full Version : Update progress bar in another thread



qt_developer
18th June 2012, 09:09
Hi all,

I have an application with an additional thread that handles a heavy process for the purpose of the GUI doesn't lock.

In this process is needed update a progress bar that resides in the main thread but sometimes the application closes unexpectedly.

I get these messages in application output:



QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
QObject::killTimers: timers cannot be stopped from another thread


How can I solve this issue?

My code:



#ifndef THREADMANAGER_H
#define THREADMANAGER_H

#include <QObject>

class QThread;
class GComputationWorker;

class ThreadManager: public QObject
{
Q_OBJECT
public:
// constructors and destructor
/**
* Returns an instance of this class. When called for the first
* time, a new instance is created and returned. After that,
* calling InstanceL returns the same instance that was created
* earlier.
*
* @return A pointer to a ThreadManager object
*/
static ThreadManager* instance();

private:
// constructor
/**
* Default constructor is private because we are using the
* singleton design pattern.
*/

ThreadManager();

public:

void doComputationWork();

private:

static ThreadManager *_instance;

QThread *computationThread;

GComputationWorker *computationWorker;

};

#endif // THREADMANAGER_H




#include "threadmanager.h"
#include "gcomputationworker.h"

#include <QThread>

ThreadManager * ThreadManager::_instance = NULL;

ThreadManager::ThreadManager()
{
_instance = NULL;
computationThread = new QThread;
computationWorker = new GComputationWorker;
computationWorker->moveToThread(computationThread);
}

ThreadManager* ThreadManager::instance()
{
if (ThreadManager::_instance == 0)
ThreadManager::_instance = new ThreadManager();
return ThreadManager::_instance;
}

void ThreadManager::doComputationWork()
{
computationOperFinished = false;
computationThread->start();
computationThread->setPriority(QThread::NormalPriority);
QMetaObject::invokeMethod(computationWorker, "doWork", Qt::QueuedConnection);
}




#ifndef GCOMPUTATIONWORKER_H
#define GCOMPUTATIONWORKER_H

#include <QObject>

class GComputationWorker : public QObject
{
Q_OBJECT
public:

GComputationWorker();

~GComputationWorker();

public slots:

void doWork();
};

#endif // GCOMPUTATIONWORKER_H




#include "gcomputationworker.h"

GComputationWorker::GComputationWorker()
{
}

GComputationWorker::~GComputationWorker()
{
}

void GComputationWorker::doWork()
{
// Start computation
// The progress bar is updated by setValue method
}


Usage:



void MainWindow::startRun()
{
ThreadManager::instance()->doComputationWork();
}

void MainWindow::onProgressBarValueChanged(int value)
{
if (ui->progressBar->maximum() == value)
{
ui->progressBar->hide();
}
}


Regards.

amleto
18th June 2012, 11:23
qregistermetatype: http://qt-project.org/doc/qt-4.8/qmetatype.html#qRegisterMetaType

That will allow you to send those types across thread boundaries.
As for the timer issue, I'm not sure if that will cause your crash or not, maybe an assert.

Please give more details about what causes the crash/assert.
Have you debugged?
What line is the problem on?
What is the call stack?


You show a problem with a timer, but I do not see any code involving timers...

Lesiok
18th June 2012, 11:57
You can't modify GUI objects from another thread.

qt_developer
18th June 2012, 12:14
I haven't used timers but I get the error:

QObject::killTimers: timers cannot be stopped from another thread



You can't modify GUI objects from another thread.

I haven't modified the GUI directly. I'm using cross thread signal and slot connection to set the progress on the bar.



connect(this, SIGNAL(signalUpdate(int)), mainWindowPointer, SLOT(onUpdateProgressBar(int)), Qt::QueuedConnection);
...
emit signalUpdate(valueToSet);


What's wrong?

amleto
18th June 2012, 12:19
What's wrong? First, what is the problem, please :) Be sure to adjust your code for qRegisterMetaType and then report any changes.

From our perspective, you have only shown some console output and some code, and said that your app crashes. We cannot be sure (without searching through Qt source code) if those console outputs are related to the app exit or not. So please respond to these pertinent questions already posed:


Please give more details about what causes the crash/assert.
Have you debugged?
What line is the problem on?
What is the call stack?

qt_developer
18th June 2012, 12:28
The problem is that the crash is random. Sometimes doesn't occurs.

The ThreadManager class is implemented properly?

amleto
18th June 2012, 12:50
Only if it is only accessed via a single thread. It is not thread safe.

If you have an app with 'random' crash/assert, then throwing up pieces of code and asking, 'is it ok?', is not the best way to resolve the issue.

You need to debug your app when it crashes and give more information, or give more code. Preferably enough to compile.

qt_developer
19th June 2012, 17:00
I have solved the problem, I was accessing to a bad memory address, for this reason I got the weird message:

"QObject::killTimers: timers cannot be stopped from another thread"

Regards.

amleto
19th June 2012, 18:41
Another case where the OP puts up some code absolutely irrelevant to his problem. Also avoided/evaded questions asking about information obtained from debugging. This is why I like compilable examples :)