pythondialoggtkpygtkmessagedialog

gtk MessageDialog not closing until enclosing method finishes


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()

Solution

  • 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"