[PyQt] Threads with PyQt. Qt's or Python's?

Giovanni Bajo rasky at develer.com
Tue Feb 3 10:28:26 GMT 2009


On mar, 2009-02-03 at 10:56 +0100, Frédéric wrote:
> Le 19/1/2009, "Giovanni Bajo" <rasky at develer.com> a écrit:
> 
> >This would work on Qt4 as well, but of course it's not ideal as you need 
> >a timer to poll the queue. It's much easier to use QThreads and simply 
> >post the events (or use the asynchronous signals).
> >
> >Plus, you can now do non-trivial things from the secondary threads (eg: 
> >painting with QPainter over a QImage) so it's worth sitting down and 
> >analyzing all these possibilities before desiging the code with Qt4.
> 
> I started to use QThreads, and I have some minor problems.
> 
> When my app was build on PyGTK, I was using standard python threads, and
> a serializer to push PyGTK calls from the threads. The serializer queue
> was periodically read and executed from the main thread.
> 
> I replaced the python threads by QThread, and removed all serializer
> calls. This works pretty well (and faster), except for one thing: I
> can't refresh my progressbar from the thread. Doing this output the
> following message:
> 
>     QPixmap: It is not safe to use pixmaps outside the GUI thread
>     QPainter: It is not safe to use drawPixmap() outside the GUI thread
> 
> The documentation says that a QPainter can only paint on QImage, QPrinter
> and QPicture, but not on QWidget and QPixmap (it seems that painting on
> QGraphicsItem works fine, as I don't have warnings; can you confirm?).

I'm unsure but yes, it probably works because it's a simply a QImage
under the hoods.

> So, how can I refresh my progressbar from my thread? Is there a Qt
> mecanism I could use? I'm not that familiar with Qt custom
> events/signals or so...

Read the documentation about connecting signals and slots across threads
(asynchronous thread connection). What you want is to simply emit a
signal from the thread (self.emit(SIGNAL("UPDATED_PROGRESS"), value)),
and connect to that signal from the main thread; in the slot, update the
widget.

The trick is that a signal/slot connection across a thread is different
from a normal one: in a normal connection, slots are called immediately,
within the "emit()" call. Instead, in an asynchronous connection, when
the signal is emitted, an event is posted to the main thread (posting
events is thread-safe); then the receiving thread's exec loop will
process the event and call the correct slot.
-- 
Giovanni Bajo
Develer S.r.l.
http://www.develer.com




More information about the PyQt mailing list