Question

I'm new here. :)

I am having trouble emigrating from GTK+ in C to PyGTK, specifically I do not understand why (in this specific context of a pause/play button) gtk.main_quit() does nothing even though it is called.

In my working example, after you press "Play", press "Pause" and then try to use the "Quit" button. On my end the "Quit" button, even though it calls gtk.main_quit() (and prints stuff after it to prove it does), will not have any effect on the program. Any ideas on what I am doing wrong?

Here it is:

import pygtk
pygtk.require('2.0')
import gtk, gobject, cairo
import time

global paused
paused = False
running = False

def some_stuff(widget, data=None):
  global paused
  global running
  x = 0
  if running:
    return
  running = True
  paused = False
  while True:
    x += 1
    print x
    while gtk.events_pending():
      gtk.main_iteration(False)
    while paused:
      while gtk.events_pending():
    gtk.main_iteration(False)
  running = False
  paused = False

def pause_stuff(widget, data=None):
  global paused
  paused = not paused

def force_quit(widget, data=None):
  print 'before'
  gtk.main_quit()   # doesn't work, gtk main loop keeps running
  #exit()            # obviously works to kill everything
  print 'after'


def main():
  window = gtk.Window()
  window.connect("delete-event", force_quit)
  window.show()
  vbox = gtk.VBox(True, 3)
  vbox.show()
  window.add(vbox)

  button = gtk.Button("Play")
  button.connect("clicked", some_stuff, None)
  vbox.add(button)
  button.show()

  button = gtk.Button("Pause")
  button.connect("clicked", pause_stuff, None)
  vbox.add(button)
  button.show()

  button = gtk.Button("Quit")
  button.connect("clicked", force_quit, None)
  vbox.add(button)
  button.show()
  window.present()
  gtk.main()
  return 0

if __name__ =="__main__":
  main()
Was it helpful?

Solution 2

Adding this as answer based on the comment to the other answer (since this is a bit long for a comment). Let's assume that one game iteration is fast and you can do one in gtk main thread without hurting the UI.

  1. Make a function that runs one single iteration of your game (to begin with you can just print something). The function should be an "idle handler callback" (see below). It should return True, except if the game is paused or stopped: in that case it should return False (meaning the function should not be called again).
  2. In Play() add an idle handler for the iteration function
  3. In Pause(), update the paused variable, and if unpausing also add an idle handler like in Play()

This way the iteration function keeps getting called after Play is called (but the UI is also updated). after Pause the iteration function is still called once, but it will return False and will not be called again.

OTHER TIPS

gtk.main_quit() instructs the GTK main loop to terminate. It has no effect in your code because your some_stuff() function implements its own version of the main loop, unaffected by calls to gtk.main_quit(). Since the outer while never exits, once the Play button is clicked, you never return into the real GTK main loop.

A correct GTK program does not reimplement the main loop like some_stuff() does, precisely to avoid such problems, and also to avoid busy-looping while nothing is going on. The while gtk.events_pending(): gtk.main_iteration() idiom should be used very sparingly, only when absolutely necessary (updating a progress bar comes to mind).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top