[Tkinter-discuss] single button threading

Cameron Laird Cameron at phaseit.net
Tue Jun 19 21:27:51 CEST 2007


On Mon, Jun 18, 2007 at 10:50:13AM +0200, Michael Lange wrote:
			.
			.
			.
> Brill IanT <woswwf at yahoo.co.uk> wrote:
> 
> > I am writing an application which fetches and parses a large number of urls for hyperlinks.
> >    
> >   My problem is that when the prog is in the middle of the 'fetching' stage, the gui becomes almost completely unresponsive.
> >    
> >   This is not at all what I want. I want the user to be able to interact with the gui while this process is going on. Even if just one button, a 'stop' button, is the only thing working, I would be satisfied with that. 
> >    
> >   Is there a way to perhaps thread a button or two while urllib2 is busy fetching a big list of urls? I ask this with some trepidation because I know how thread unfriendly tkinter is.
> >    
> 
> I did not find it that hard to use Tkinter with threads. You just have to make sure that
> all interaction with Tk is done from the main (gui) thread. Typically I use a bunch
> of variables to handle communication between Tkinter and the child thread, so the 
> "Stop" button would set a "stop_child_thread" flag to True, whereas the child
> thread continually updates a "progress" flag that allows the gui to draw some visual feedback
> about the progress made by the child.
> 
> I hope this helps
			.
			.
			.
There certainly are people who regard Tkinter threading as touchy.
I choose not to argue that point today.

I *will* point out that, in essentially all common systems (not 
just Tkinter, and not just any particular operating system), you'll
need to confine your GUI work to a single thread.

Let's sidestep all that for right now, and look at an example of a
responsive urllib2-using GUI in a single thread:
  from Tkinter import *
  from urllib2 import *
  
  master = Tk()
  
  def fetch_action():
      l.configure(text = "Beginning download")
      l.after(0, download)
  
  def download():
      global total_read
      global stop_reading
  
      URL = "http://wiki.python.org/moin/RecentChanges"
      f = urlopen(URL)
      total_read = 0
      stop_reading = 0
      l.after(0, read_more, f, 100)
  
  def read_more(handle, octets):
      global total_read
      global stop_reading
  
      if stop_reading:
          return
      print handle.read(octets),
      total_read += octets
      l.configure(text = "%d octets read" % total_read)
      l.after(1, read_more, handle, octets)
  
  def stop():
      global stop_reading
  
      stop_reading = 1
  
  l = Label(master, text = 40 * " ")
  b1 = Button(master, text = "Fetch", command = fetch_action)
  b2 = Button(master, text = "Stop reading", command = stop)
  l.pack()
  b1.pack()
  b2.pack()
  
  mainloop()
I like to think this speaks for itself.  If you execute this application
for itself, you'll see a GUI that remains responsive even while urllib2
operations are proceeding.


More information about the Tkinter-discuss mailing list