PDA

View Full Version : Showing progress bar while worker thread works



olidem
24th April 2009, 10:29
Hi guys!

I've got the following situation:

Somewhere in my GUI I start a lengthy computation in my BackgroundImageItem which inherits from QThread:



BackgroundImageItem* back = new BackgroundImageItem(filename);
// let the worker thread work:
back->start();


to inform the user that the application is working, I have written the following simple self-updating Progressbar:



class ThreadedProgressBar : public QThread, public QProgressBar
{
public:
ThreadedProgressBar(QWidget * parent)
: QProgressBar(parent)
{
this->setGeometry(
(parent->width() - 300)/2,
(parent->height()-30)/2,
300, 30);
this->setTerminationEnabled(true);
this->start();
};
void run()
{
while(true)
{
this->setValue((this->value()+20)%100);
this->update();
this->msleep(100);
}
};
virtual ~ThreadedProgressBar();
};


What I did then to show this ThreadedProgressbar was:



BackgroundImageItem* back = new BackgroundImageItem(filename);
// let the worker thread work:
back->start();
//start the progressBar,
//note: this->parentWidget() is the main widget of my app
ThreadedProgressBar * pbar = new ThreadedProgressBar(this->parentWidget());
// Join the gui thread with the worker thread
back->wait();
// a thread must be terminated before being deleted
pbar->terminate();
//clean up
delete pbar;



BUT THE PROGRESS BAR DOES NOT SHOW UP !!!!

I'm sure I just did a small mistake!

Thanks for zour help in advance,
best regards,
Olli

caduel
24th April 2009, 17:11
i) you must not use widgets in any but the gui (aka main) thread
ii) assuming you did not inherit QThread and QProgressBar:
when you put your ThreadedProgressBar to sleep, no events will get progressed

possible solutions:
i) use a QTimer to regularly update a QProgressBar
ii) have your worker thread signal its progress and connect that to some gui slot
iii) use a QProgressBar and put it into "busy mode" by setting min=max=0 to indicate that your program is doing something

HTH

bnolsen
25th April 2009, 14:19
The gui may only be controlled by the main thread for portability reasons. Windows WILL behave strangely or even crash if you do otherwise.

faldzip
25th April 2009, 15:59
same on X11 - crash for sure :] better look if some of the QtConcurrent functionality can be useful for you. QtConcurrent provides for example something like QFutureWatcher whic can give you the progress of task, when you use QtConcurrent for heavy computations.

olidem
27th April 2009, 14:57
Hi!

Thanks for your replies.

But my Problem is still not solved.

I have changed my strategy a bit:
I am extensively working on a QGraphicsView and Scene, so the idea is to hide all QGraphicsItems in my scene once the computation starts, and to show a Progressbar which is a subclass of QGraphicsItem.

the code looks like that:


//MainView is derived from QGraphicsView
void MainView::loadBackgroundImage(const QString& filename)
{
// the background item shall always be newly created.
if(this->scene()->items().contains(this->m_background))
this->scene()->removeItem(this->m_background);
delete m_background;

//hide all scene items
this->m_scalable_item->setVisible(false);

//get the progressbar (derived from QGraphicsItem)
GraphicsProgressBar * g = new GraphicsProgressBar;
this->scene()->addItem(g);
g->setPos(this->sceneRect().center());

this->scene()->update();

QTimer * timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), g, SLOT(updateProgress()));
timer->start(100);

//BackgroundImageItem is derived from QObject, QThread and QGraphicsItem
// start() starts the computation is background-thread
m_background = new BackgroundImageItem(filename);
m_background->start();
qDebug() << "work started";
//the gui thread should wait here until the worker has finished
m_background->wait();
qDebug() << QThread::currentThreadId() << "Waiting done.";

// I just add the background item here
this->scene()->addItem(this->m_background);
if(!this->scene()->items().contains(m_scalable_item))
this->scene()->addItem(m_scalable_item);
this->m_scalable_item->setVisible(true);

//free all timer resoureces and the progressbar
timer->stop();
timer->disconnect();
g->disconnect();
this->scene()->removeItem(g);
delete g;
delete timer;
}

The Progressbar code looks like:


class GraphicsProgressBar : public QObject, public QGraphicsItem
{
Q_OBJECT

public:

GraphicsProgressBar()
{
setZValue(5);
status = 1;
};

inline QRectF boundingRect() const { return QRectF(-66,-21,132,42); };

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
qDebug() << "paint";
painter->drawRect(-66,-21,132,42);
if(status >=1)
painter->drawRect(-65,-20,40,40);
if(status >=2)
painter->drawRect(-20,-20,40,40);
if(status >=3)
painter->drawRect(25,-20,40,40);
};

public slots:

void updateProgress()
{
status = (status+1)%4;
qDebug() << QThread::currentThreadId() << status;
//this->update();
};


private:
int status;
};

The progressbar does not show up.
Also, the hiding
The paint method gets never called!
Also the debugmsg from updateProgress never appears.
It seems that nothing I try to change at the graphicsScene or view has an effect.
Its not even possible to hide all elements.

HELP appreciated!

nix
27th April 2009, 15:46
Hi,

I think your problem comes from following line :


//the gui thread should wait here until the worker has finished
m_background->wait();


It seems you want block the Gui thread during the processing. But how your progressbar should be managed and refreshed if the GUI thread is blocked ??

You don't have to block the GUI thread, use QThread::finished() signal for manage post-treatement & cleaning once the processing is completed.

'hope it will help you.

olidem
27th April 2009, 20:43
Hi,

I think your problem comes from following line :


//the gui thread should wait here until the worker has finished
m_background->wait();


It seems you want block the Gui thread during the processing. But how your progressbar should be managed and refreshed if the GUI thread is blocked ??

You don't have to block the GUI thread, use QThread::finished() signal for manage post-treatement & cleaning once the processing is completed.

'hope it will help you.

Yes!
That was the hint I needed!
Thanks a lot!