views:

478

answers:

2

I have a problem with threads in pygtk. My application consist of a program that downloads pictures off the internet and then displays it with pygtk. The problem is that in order to do this and keep the GUI responsive, I need to use threads.

So I got into a callback after the user clicked on the button "Download pictures" and I call the method to download the pictures that is within that same class.

thread.start_new_thread(self.images_download, (path,pages)

This won't work. The only way I get my program to get into the thread is by using

gtk.threads_init()

Before starting any thread. Now it downloads the pictures but the GUI remains unresponsive. I googled this and I tried putting gtk.threads_enter and gtk.threads_leave around the threads but it just doesn't work.

+6  A: 

Your question is a bit vague, and without a reference to your actual code it's hard to speculate what you're doing wrong.

So I'll give you some pointers to read, then speculate wildly based on experience.

First of all, you seem to think that you can only keep the GUI responsive by using threads. This is not true. You can also write your code asynchronously, and do everything in a single-threaded application. Twisted is built on this programming model. I recently made a blog post that explains how I created an asynchronous task interface, and example runners both for CLI and GTK+. You can look at those examples to see how tasks can be implemented asynchronously, and the UI still gets updated.

Second, if you prefer to use threads for some reason, you will need to understand the GTK+ threading model a little.

You should start by reading The PyGTK FAQ entry on the subject, and you might find this blog post easy to understand too.

Now, on to speculation. I am guessing that you are trying to update your GTK UI from the thread, and not handling the locking properly. If this is the case, you are better off for now deferring all your UI updates you want to do from threads to the main thread by using gobject.idle_add() This way, all UI calls will be made from the main thread. It is an easier mental model to follow in your programming.

Once you feel you really understand the threading and locking models, you could consider updating the UI from your threads, but it's easy to miss a threads_enter()/threads_leave()

Thomas Vander Stichele
+1: Don't use threads, just use asynchronous I/O.
nosklo
A: 

You can use gtk.gdk.threads_init() in order to allow any thread modify the UI with the respecting gtk.gdk.threads_enter() and gtk.gdk.theads_leave() lock, but, the problem with this is that doesn't work well on windows. I have tested it on Linux and performs quite well, but I had no luck making this to work over win32.

=== Edit ===

I have been browsing about this, you could make use of the gobject.io_add_watch to check if there is something in your socket, grab it and then update the GUI. check my post about this: Sockets (and some other files) and PyGTK without threads.

markuz