3

Sorry for the noob question but I really don't understand this.

I'm using python / tkinter and I want to display something (say, a canvas with a few shapes on it), and keep it displayed until the program quits. I understand that no widgets would be displayed until I call tkinter.tk.mainloop(). However, if I call tkinter.tk.mainloop(), I won't be able to do anything else until the user closes the main window.

I don't need to monitor any user input events, just display some stuff. What's a good way to do this without giving up control to mainloop?

EDIT:

Is this sample code reasonable:

class App(tk.Tk):
  def __init__(self, sim):
    self.sim = sim # link to the simulation instance
    self.loop()

  def loop():
    self.redraw() # update all the GUI to reflect new simulation state
    sim.next_step() # advance simulation another step
    self.after(0, self.loop)

  def redraw():
    # get whatever we need from self.sim, and put it on the screen

EDIT2 (added after_idle):

class App(tk.Tk):
  def __init__(self, sim):
    self.sim = sim # link to the simulation instance
    self.after_idle(self.preloop)

  def preloop():
    self.after(0, self.loop)

  def loop():
    self.redraw() # update all the GUI to reflect new simulation state
    sim.next_step() # advance simulation another step
    self.after_idle(self.preloop)

  def redraw():
    # get whatever we need from self.sim, and put it on the screen
max
  • 49,282
  • 56
  • 208
  • 355
  • Is this where multitreading comes in? – Geoffrey Jan 27 '11 at 09:53
  • @max: pretty close. That's the right concept, though I recommend against giving after a value of zero. GUI events shouldn't take very long, but they take more than zero milliseconds. You'll have to play with the value to get a feel for what gives good GUI performance while still letting your main logic run at top speed. – Bryan Oakley Jan 27 '11 at 22:03
  • @Bryan: I'm scared to test the delay value; what if the program runs in another environment later (e.g., with a different resolution, etc.)? Perhaps I should use `after_idle` instead - would that take care of the problem or does it have other issues? – max Jan 28 '11 at 21:28
  • @max: using `after_idle` can potentially lock up your GUI. The idle tasks are run until there is nothing on the idle queue, so if you do something during idle that places something on the queue the queue will never be empty. The generally accepted solution is for `after_idle` to call `after` with a value of zero to schedule your job. This gives tk a chance to process all idle events (things like screen redrawing), then process any other events (like mouse movement) before running your callback. – Bryan Oakley Jan 29 '11 at 23:20
  • Thank you - is my edited code what you're referring to? – max Jan 30 '11 at 23:21

1 Answers1

3

Tk needs an event loop, there's no avoiding that. That's how the widgets know to redraw themselves when obscured, for instance. So, you must have the event loop running.

You have at least three choices. First, use the main thread for the GUI, and put your other logic in a separate thread. A second option is to use two separate processes - one for the GUI, one for your program. Your program can communicate with the GUI over a socket to send it data to display.

Your third option is to learn to live within the event loop. After all, it's really nothing more than a while True that wraps your whole program. If your main logic runs in a loop, just take out your loop and replace it with the event loop. You can, for example, run one iteration of your code then have it call after to schedule itself to run again in a few ms. That call to after adds an event that will call your code whenever the GUI is done with any necessary upkeep.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thanks. I'm afraid of threads in Python, especially since even the GUI mainloop might end up having some CPU intensive tasks and not just I/O wait. Processes sound great - but is there a lot of overhead? – max Jan 27 '11 at 18:58
  • I updated my question with the sample of the code per the third solution. Is that what you meant? – max Jan 27 '11 at 19:01
  • 1
    Being afraid of threads is a very good instinct. Even though python makes them fairly simple, by and large threading is difficult and adds complexity. If they can be avoided, IMO, avoid them. – Bryan Oakley Jan 27 '11 at 22:04