Frage

I am trying to code an application that consists of various windows (e.g., generic message dialog, login dialog, main interface, etc.) and am having trouble getting the gtk.main_quit function to be called: either I get a complaint about the call being outside the main loop, or the function doesn't get called at all.

I am a newbie to both Python and GTK+, but my best guess as to how to get this to work is to have a "root" window, which is just a placeholder that is never seen, but controls the application's GTK+ loop. My code, so far, is as follows:

import pygtk
pygtk.require("2.0")
import gtk

class App(gtk.Window):
  _exitStatus = 0

  # Generic message box
  def msg(self, title, text, type = gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK):
    # Must always have a button
    if buttons == gtk.BUTTONS_NONE:
      buttons = gtk.BUTTONS_OK

    dialog = gtk.MessageDialog(None, 0, type, buttons, title)
    dialog.set_title(title)
    dialog.set_geometry_hints(min_width = 300)
    dialog.set_resizable(False)
    dialog.set_deletable(False)
    dialog.set_position(gtk.WIN_POS_CENTER)
    dialog.set_modal(True)
    dialog.format_secondary_text(text)

    response = dialog.run()
    dialog.destroy()

    return response

  def nuke(self, widget, data):
    gtk.main_quit()
    exit(self._exitStatus)

  def __init__(self):
    super(App, self).__init__()
    self.connect('destroy', self.nuke)

    try:
      raise Exception()
    except:
      self.msg('OMFG!', 'WTF just happened!?', gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE)
      self._exitStatus = 1
      self.destroy()

    if self.msg('OK', 'Everything worked fine') == gtk.RESPONSE_OK:
      self.destroy()

# Let's go!
App()
gtk.main()

The nuke function never gets called, despite the explicit calls to destroy.


DIFF On @DonQuestion's advice:

- self.destroy()
+ self.emit('destroy')

- App()
+ app = App()

This didn't solve the problem...


UPDATE Accepted @jku's answer, but also see my own answer for extra information...

War es hilfreich?

Lösung

First, there is a bit of a test problem with the code: You call Gtk.main_quit() from the App initialization: this happens before main loop is even running so signals probably won't work.

Second, you'll probably get a warning on destroy(): 'destroy' handler only takes two arguments (self plus one) but yours has three...

Also with regards to your comment about control flow: You don't need a Window to get signals as they're a GObject feature. And for your testing needs you could write a App.test_except() function and use glib.idle_add (self.test_except) in the object initialization -- this way test_except() is called when main loop is running.

Andere Tipps

I think @jku's answer identifies my key error, so I have marked it accepted, but while playing around, I found that the MessageDialog does not need to run within the GTK+ loop. I don't know if this is as designed, but it works! So, I broke my generic message dialog out into its own function and then kept the main app altogether in a class of its own, which respects the main loop as I was expecting:

import pygtk
pygtk.require("2.0")
import gtk

def msg(title, text, type = gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK):
  # Only allowed OK, Close, Cancel, Yes/No and OK/Cancel buttons
  # Otherwise, default to just OK
  if buttons not in [gtk.BUTTONS_OK, gtk.BUTTONS_CLOSE, gtk.BUTTONS_CANCEL, gtk.BUTTONS_YES_NO, gtk.BUTTONS_OK_CANCEL]:
    buttons = gtk.BUTTONS_OK

  dialog = gtk.MessageDialog(None, 0, type, buttons, title)
  dialog.set_title(title)
  dialog.set_geometry_hints(min_width = 300)
  dialog.set_resizable(False)
  dialog.set_deletable(False)
  dialog.set_position(gtk.WIN_POS_CENTER)
  dialog.set_modal(True)
  dialog.format_secondary_text(text)

  response = dialog.run()
  dialog.destroy()
  return response

class App:
 def __init__(self):
   # Build UI
   # Connect signals
   # Show whatever

 def appQuit(self, widget):
   gtk.main_quit()

 def signalHandler(self, widget, data = None):
   # Handle signal
   # We can call msg here, when the main loop is running

# Load some resource
# We can call msg here, despite not having invoked the main loop
try:
  # Load resource
except:
  msg('OMFG!', 'WTF just happened!?', gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE)
  exit(1)

# n.b., Calls to msg work even without the following code
App()
gtk.main()
exit(0)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top