I have created a PyGTK application that shows a Dialog when the user presses a button.
The dialog is loaded in my __init__ method with:
builder = gtk.Builder()
builder.add_from_file("filename")
builder.connect_signals(self)
self.myDialog = builder.get_object("dialog_name")
In the event handler, the dialog is shown with the command self.myDialog.run(), but this only works once, because after run() the dialog is automatically destroyed. If I click the button a second time, the application crashes.
I read that there is a way to use show() instead of run() where the dialog is not destroyed, but I feel like this is not the right way for me because I would like the dialog to behave modally and to return control to the code only after the user has closed it.
Is there a simple way to repeatedly show a dialog using the run() method using gtkbuilder? I tried reloading the whole dialog using the gtkbuilder, but that did not really seem to work, the dialog was missing all child elements (and I would prefer to have to use the builder only once, at the beginning of the program).
[SOLUTION] (edited)
As pointed out by the answer below, using hide() does the trick. I first thought you still needed to catch the “delete-event”, but this in fact not necessary. A simple example that works is:
import pygtk
import gtk
class DialogTest:
def rundialog(self, widget, data=None):
self.dia.show_all()
result = self.dia.run()
self.dia.hide()
def destroy(self, widget, data=None):
gtk.main_quit()
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("destroy", self.destroy)
self.dia = gtk.Dialog('TEST DIALOG', self.window,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
self.dia.vbox.pack_start(gtk.Label('This is just a Test'))
self.button = gtk.Button("Run Dialog")
self.button.connect("clicked", self.rundialog, None)
self.window.add(self.button)
self.button.show()
self.window.show()
if __name__ == "__main__":
testApp = DialogTest()
gtk.main()
Actually, read the documentation on
Dialog.run(). The dialog isn’t automatically destroyed. If youhide()it when therun()method exits, then you should be able torun()it as many times as you want.Alternatively, you can set the dialog to be modal in your builder file, and then just
show()it. This will achieve an effect that’s similar, but not quite the same asrun()– becauserun()creates a second instance of the main GTK loop.EDIT
The reason you are getting a segmentation fault if you don’t connect to the
delete-eventsignal is that you are clicking the close button twice. Here is what happens:run()method.run()overrides the normal behavior of the close button, the dialog is not closed. It is also not hidden, so it hangs around.run()is not active anymore, the normal behavior of the close button is triggered: the dialog is destroyed.run()method of the destroyed dialog. Crash!So if you make sure to
hide()the dialog after step 3, then everything should work. There’s no need to connect to thedelete-eventsignal.