Question

Here is a mocked up version of what I'm trying to do in my GUI. I have a MessageDialog which is created somewhere during the execution of a callback method. My problem is the MessageDialog won't close until the callback method finishes its execution.

I have a "dialog.destroy()" which I would expect to destroy the dialog. I click on "Yes/No" and the button depresses, but the dialog doesn't go away until "_go" finishes.

The "time.sleep(4)" is in there to simulate other stuff happening in my "_go" method after my MessageDialog interaction is over.

from gi.repository import Gtk, GObject
import time

class Gui(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete_event", Gtk.main_quit)
        self.set_size_request(700, 600)
        notebook = Gtk.Notebook()
        notebook.set_tab_pos(Gtk.PositionType.TOP)
        notebook.append_page(MyTab(), Gtk.Label("A tab"))
        self.add(notebook)
        notebook.show_all()
        self.show()

class MyTab(Gtk.VBox):
    def __init__(self):
        super(MyTab, self).__init__()
        self.go_button = Gtk.Button()
        self.go_button.add(Gtk.Image().new_from_stock(Gtk.STOCK_APPLY,
                                                 Gtk.IconSize.BUTTON))
        top_box = Gtk.HBox()
        top_box.pack_start(self.go_button, False, True, 5)
        self.pack_start(top_box, False, True, 5)

        # setup callbacks
        self.go_button.connect("clicked", self._go)

    def _go(self, _):
        dialog = Gtk.MessageDialog(Gtk.Window(), 
                                   Gtk.DialogFlags.MODAL,
                                   Gtk.MessageType.QUESTION,
                                   Gtk.ButtonsType.YES_NO,
                                   "RESPONSE REQUIRED")
        dialog.format_secondary_text("are you having fun?")
        response = dialog.run()
        dialog.destroy()
        print "your response is: " + str(response)
        time.sleep(4)
        print "left _go"

def main():
    """
    Main entry point.
    """
    Gui()
    Gtk.main()

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

Solution 3

As per the comments on user4815162342's answer I came up with a solution that uses a nested main loop. This class takes in a dialog and provides a run method.

class NestedDialog(object):
    def __init__(self, dialog):
        self.dialog = dialog
        self.response_var = None

    def run(self):
        self._run()
        return self.response_var

    def _run(self):
        self.dialog.show()
        self.dialog.connect("response", self._response)
        Gtk.main()

    def _response(self, dialog, response):
        self.response_var = response
        self.dialog.destroy()
        Gtk.main_quit()

The dialog is then run as follows:

def _go(self, _):
    dialog = Gtk.MessageDialog(Gtk.Window(), 
               Gtk.DialogFlags.MODAL,
               Gtk.MessageType.QUESTION,
               Gtk.ButtonsType.YES_NO,
               "RESPONSE REQUIRED")
    dialog.format_secondary_text("are you having fun?")
    nested_dialog = NestedDialog(dialog)
    response = nested_dialog.run()
    print "your response is: " + str(response)
    time.sleep(4)
    print "left _go"

OTHER TIPS

This problem is not specific to dialogs. Any GUI change is invisible until you return to the main loop and give the system a chance to process the events accumulated by modifying the widgets.

If you really want to update the GUI immediately in the callback, you can manually spin the accumulated events with a loop like this after the call to dialog.destroy():

while Gtk.events_pending():
    Gtk.main_iteration()

However, be aware that this will not only update the screen, but also run other accumulated events, including idle and timeout handlers and button click callbacks (if any are pending). That can have unexpected consequences.

This is the correct behaviour. The window only disappears when control is given back to Gtk's main loop which only happens at the end of your _go callback.

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