PDA

View Full Version : [SOLVED?] Emiting signals from a QThread is blocking my QDialog.



hickscorp
17th April 2007, 14:53
Hello,

Here is what i have so far:
- A QDialog, with various controls in it (Buttons, Sliders, Combo Boxes etc).
- The QDialog also contains a custom progress bar i made, which has one slot named "setPercentage(int)".
- The Dialog starts a thread, which emits a signal named "percentageChanged(int)".
- In my QDialog, i connect the QThread's signal directly to my progress bar's slot.

The observed issue is, when the thread is running and the progress bar updating, the controls in my QDialog are frozen, just like if there were no thread.

If i just dont connect the thread to the pbar, it's ok, all are very fluid.

Anyone has a clue on how to avoid this?

Thanks ^^

[EDIT:] The only solution i see is, give a pointer to the PBar to the QThread, so it directly manages to set the percentage... but i feel like it's very ugly.
[EDIT2:] I think i know why this behaviour happens: in my PBar's setPercentage slot, i do a repaint(). Which is done too fast probably. Instead, i would like to "queue" a repaint event, so if the event loop finds two at the same time, it only repaint once...

marcel
17th April 2007, 14:56
Could you show us some code? Especially how do you create the thread and how you emit the signal...



The only solution i see is, give a pointer to the PBar to the QThread, so it directly manages to set the percentage... but i feel like it's very ugly.
It is quite "illegal". Interface objects must be modified only by the interface thread.

marcel
17th April 2007, 15:00
Oh, I see the problem now.
Don't connect the thread signal to the progress slot. Instead connect it to a slot in the dialog, in which you call setValue( int ).

Connecting it to setValue, as you do now, causes a DirectConnection to be made. This is why your GUI blocks - the worker thread updates your progress all the time.

Do as I said an it will work.

regards

marcel
17th April 2007, 15:03
I think i know why this behaviour happens: in my PBar's setPercentage slot, i do a repaint(). Which is done too fast probably. Instead, i would like to "queue" a repaint event, so if the event loop finds two at the same time, it only repaint once...

No, not true...

hickscorp
17th April 2007, 15:04
Hmm it is very complicated to show you some code, especially for the QDialog.
But here are some stuff which can help:

How i connect the thread to the PBar (From my QDialog):


connect( thrdProcessing, SIGNAL(percentDone(int)), prgBrCoreStatus, SLOT(setPercentage(int)) );
connect( thrdProcessing, SIGNAL(stepDone(int, int)), prgBrCoreStatus, SLOT(setStep(int, int)) );


How i start the thread (From my QDialog):


if (!thrdProcessing->isRunning()) {
// Start the core...
thrdProcessing->start();
} else
setWindowTitle(tr("The core is already running."));


Also, attached is the full source code of my PBar.

Thanks a lot again Marcel :)
Pierre

[EDIT:] FYI: The two attached files have been made with Visual Studio... under Windows. i recommend you to set the tabs space to 4 if you're using Kdevelop, i had this issue earlier :)

marcel
17th April 2007, 15:07
OK.

Instead of repaint, use update().
repaint() causes an immediate pintEvent(). update() will post it in the event queue, and it will be executed in the next event loop.

Try this first.

EDIT: I'm in Windows( VS 2003 )

regards

hickscorp
17th April 2007, 15:23
Marcel,

I just have tested with the "update" instead of the "repaint": no more freeze, but much "lag".
But i didnt see your previous post so i just changed this too, the lag doesnt go away.

In fact, the thread was connected to the dialog and i had this lag, so i thought maybe i should connect it to the PBar =/

Any other clue? Maybe i should put a timer in the progress bar, which checks let's say each 50ms to update()?

Pierre.

marcel
17th April 2007, 15:27
How many times do you emit the signal?
You should test before emitting the setProgress signal, to make sure you don't emit the same value more than one time. This happened to me some time ago. You should emit a single signal for every value that you set.

Emitting a lot of signals (which are turned into events ) can block the interface.

EDIT: Every time you emit the signal from the thread you should look at the previous value you emitted ( initially 0 ), and if they are not equal then it's ok to emit. Otherwise you wait for the next value.

Regards.

hickscorp
17th April 2007, 15:36
Your solution is a good solution, but in certain cases can't apply to me :)
But i suspect i'll see the problem when i'll put the real, heavy, slow processement in my thread (For now i have a fake processement routine in the thread, to test).

I have put a test on the last percentage emited, if it's the same it doesnt emit again. Still minimal lag, but now the GUI is usable :)

Thanks a lot, i'll come back post here if the problem is back after i put the real code in the thread.

Pierre.