Connect a method for window destroy - python

I have a main window with a Gtk Button named openDialog. If I click on this button another Window (addName) popups. I would like to write a method (or a function, don't know which is the right name in python) in my main window file, called printHi. I would like to run this printHi method (in my main window file), when addName window is destroyed.
I tried something like this:
def on_addName_destroy():
printHi()
But it doesn't work. Any suggestion?

You can make use of "delete-event" signal of gtk.Widget. It is also possible to make use of "destroy" signal of gtk.Object. Here is a sample which connects to both the signals although in your case connecting to any one of them should suffice.
#!/usr/bin/env python
import gtk
def on_addName_destroy(gtkobject, data=None):
print "This is called later after delete-event callback has been called"
print "Indication that the reference of this object should be destroyed"
print "============================================"
def on_addName_delete(widget, event, data=None):
print "This is called on delete request"
print "Propagation of this event further can be controlled by return value"
print "--------------------------------------------"
return False
def show_popup(widget, data=None):
dialog = gtk.Window(gtk.WINDOW_TOPLEVEL)
dialog.set_size_request(100, 100)
label = gtk.Label("Hello!")
dialog.add(label)
dialog.connect("delete-event", on_addName_delete)
dialog.connect("destroy", on_addName_destroy)
dialog.show_all()
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_size_request(100, 100)
button = gtk.Button("Popup")
button.connect("clicked", show_popup)
window.add(button)
window.connect("destroy", lambda x: gtk.main_quit())
window.show_all()
gtk.main()
Hope this helps!

Related

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

python gtk multi window

i have a big problem (for me!) with python gtk module.
i can open multi windows; but i can't close singly ( one time , one window ).
if i close a window, all windows close automatically.
i want to close the first window only. after closing firt window, come a new window ( by my choice).
for example :
#!/usr/bin/env python
import pygtk
pygtk.require20()
import gtk
class CLS1(object):
def __init__(self):
self.mywindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.mywindow.connect("delete_event", gtk.main_quit)
self.btn = gtk.Button("Cls1|Btn")
self.mywindow.add(self.btn)
self.mywindow.show_all()
def main(self):
gtk.main()
class CLS2(object):
def __init__(self):
self.mywindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.mywindow.connect("delete_event", gtk.main_quit)
self.btn = gtk.Button("Cls2|Btn")
self.mywindow.add(self.btn)
self.mywindow.show_all()
def main(self):
gtk.main()
class APP(object):
def __init__(self):
self.mywindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.mywindow.connect("delete_event", gtk.main_quit)
self.hori = gtk.HBox()
self.btn1 = gtk.Button("AppBtn1")
self.btn2 = gtk.Button("AppBtn2")
self.btn1.connect("clicked", self.show_me , "AppBtn1")
self.btn2.connect("clicked", self.show_me , "AppBtn2")
self.hori.pack_start(self.btn1)
self.hori.pack_start(self.btn2)
self.mywindow.add(self.hori)
self.mywindow.show_all()
def show_me(self, penar, data):
if data=="AppBtn1" :
CLS1().main()
if data=="AppBtn2":
CLS2().main()
gtk.main_quit()
def main(self):
gtk.main()
APP().main()
i want this :
1- i will run the program
2- the "APP" class will work and will come "APP" window
3- if i click a button (AppBt1 or AppBtn2) ; the "APP" window will close (automatically ; not by me!)
4- if i was clicked "AppBtn1" button on "APP" window (#step 3) ; the "CLS1" class will work and its window will open
,or if i was clicked "AppBtn2" button on "APP" window (#step 3) ; the "CLS2" class will work and its window will open
i wanna only one window on the screen while program running; if i click a button ; its window will close and a new window will open (by my choice, and automatically!)
how can i do this? and can you write its code :)
thanks a lot !
Calling gtk.main_quit will kill the whole program (it basically stop GTK). So what you need, is just to stop GTK when the last window has been closed. What you're currently doing is stopping GTK when any window is closed.
So just use a global variable that you will use as a counter of the windows open. On the delete-event handler, decrement that counter, and if it reached 0 that means you have no more windows open, and you can call gtk.main_quit, otherwise, do nothing and the window will just be normally destroyed.
To kill the parent window, just pass the parent as the last parameter when you connect to the clicked signal. In the associated callback, you'll get that last parameter and call gtk.Widget.destroy on it.
Well a better way might be to modify the window that's already open instead of closing it and opening another.

How to get a gtkDialog's default response to trigger of the space bar as well

I have a messageDialog set up so that its default response is gtk.RESPONSE_OK so the okay button is clicked when the user hits enter even if the okay button does not have focus. I would like to also have the space bar trigget the default_response. What is the best way to do this?
This is with python 2.4 in a linux environment. Unfortunately I don't have permission to upgrade python.
Connect to the key-press-event signal on the message dialog:
def on_dialog_key_press(dialog, event):
if event.string == ' ':
dialog.response(gtk.RESPONSE_OK)
return True
return False
dialog = gtk.MessageDialog(message_format='Some message', buttons=gtk.BUTTONS_OK_CANCEL)
dialog.add_events(gtk.gdk.KEY_PRESS_MASK)
dialog.connect('key-press-event', on_dialog_key_press)
dialog.run()
Bear in mind, though, that changing users' expectations of the user interface is generally considered Not Cool.
I'm a total noob at pygtk, but I could not get #ptomato's example + "hello world" boilerplate to work unless I responded to space and return plus added a call to dialog.destroy(). Take it for what it is worth.
#!/usr/bin/env python
# example helloworld.py
import pygtk
pygtk.require('2.0')
import gtk
def md_event(dialog, event):
if event.keyval in (gtk.keysyms.Return, gtk.keysyms.space):
dialog.response(gtk.RESPONSE_OK)
dialog.destroy()
return True
elif event.keyval == gtk.keysyms.Escape:
dialog.response(gtk.RESPONSE_CANCEL)
dialog.destroy()
return True
return False
class HelloWorld:
# This is a callback function. The data arguments are ignored
# in this example. More on callbacks below.
def hello(self, widget, data=None):
print "Hello World"
# Another callback
def destroy(self, widget, data=None):
gtk.main_quit()
def create_message_dialog(self, x, y):
md = gtk.MessageDialog(buttons=gtk.BUTTONS_OK_CANCEL, message_format="wawawawaaaaa")
md.add_events(gtk.gdk.KEY_PRESS_MASK)
md.connect("key-press-event", md_event)
result = md.run()
print result
def __init__(self):
# create a new window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
# Here we connect the "destroy" event to a signal handler.
# This event occurs when we call gtk_widget_destroy() on the window,
# or if we return FALSE in the "delete_event" callback.
self.window.connect("destroy", self.destroy)
# Sets the border width of the window.
self.window.set_border_width(10)
self.button2 = gtk.Button("Message Dialog")
self.button2.connect("clicked", self.create_message_dialog, None)
self.window.add(self.button2)
self.button2.show()
# and the window
self.window.show()
def main(self):
# All PyGTK applications must have a gtk.main(). Control ends here
# and waits for an event to occur (like a key press or mouse event).
gtk.main()
def run_hello():
hello = HelloWorld()
hello.main()
# If the program is run directly or passed as an argument to the python
# interpreter then create a HelloWorld instance and show it
if __name__ == "__main__":
run_hello()

create a gtk.window under a gtk.widget

I wanna show a gtk.Window under a gtk.widget.
But I don't know how to retrieve the gtk.widget's coordinates for my gtk.window.
Anyone knows ?
Thanks.
You can use the "window" attribute of the gtk.Widget to get the gtk.gdk.Window associated with it. Then look at the get_origin() method to get the screen coordinates.
These coordinates are for the top-level window, I believe (I could be wrong about that, but my code below seems to support that). You can use the get_allocation() method to get the coordinates of a widget relative to its parent.
I got the idea from here. Be warned though: some window managers ignore any initial settings for window position. You might want to look at this post for more info, but I haven't personally checked it out.
Were you intending to create another top-level window? Or a popup window?
#!/usr/bin/env python
import sys
import pygtk
import gtk
class Base:
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("destroy", self.on_destroy)
self.box = gtk.VButtonBox()
self.buttons = [
gtk.Button("Test 1"),
gtk.Button("Test 2"),
gtk.Button("Test 3")
]
for button in self.buttons:
self.box.add(button)
button.connect("clicked", self.show_coords)
button.show()
self.window.add(self.box)
self.box.show()
self.window.show()
def show_coords(self, widget, data=None):
print "Window coords:"
print self.window.get_window().get_origin()
print "Button coords:"
print widget.get_allocation()
def on_destroy(self, widget, data=None):
gtk.main_quit()
def main(self):
gtk.main()
if __name__ == "__main__":
base = Base()
base.main()

PyGTK Label emit ButtonPressEvent does nothing and returns False

Labels can have links by using Pango markup, but the "button-press-event" on a label is not emitted when the label is used in an Expander. I thought that if I created a subclass of Expander and emitted the "button-press-event" myself, the link would be clicked. A minimal example of "button-press-event" failing is given below:
import gtk
def on_activate(label, uri):
print(uri)
def on_click(widget, event):
label.emit('button-press-event', event)
window = gtk.Window()
expander = gtk.Expander()
window.add(expander)
label = gtk.Label('link')
label.set_use_markup(True)
label.connect("activate-link", on_activate)
expander.set_label_widget(label)
expander.connect("button-press-event", on_click)
window.connect("destroy", gtk.main_quit)
window.show_all()
gtk.mainloop()
If I add print calls, I can see that on_click() is being called, but on_activate() is not. The strange thing is, if I print the returns of label.emit(...), it prints False. What does that mean? How can I click the link?

Categories