Reputation: 6139
I know that, from here,
grab_set() [#]: Routes all events for this application to this widget.
OK but it doesn't prevent the user to close the parent window with X button. In addition to other events, how can I route "X button close" event as well?
MWE:
from Tkinter import *
class Window(Toplevel):
def __init__(self, master):
Toplevel.__init__(self)
class MainWindow(Tk):
def __init__(self):
Tk.__init__(self)
Button(self, command=self.open_window).grid(row=0, column=0)
def open_window(self):
win = Window(self)
win.grab_set()
app = MainWindow()
app.mainloop()
Upvotes: 1
Views: 1126
Reputation: 15226
For windows you can use:
root.protocol("WM_DELETE_WINDOW", your_function_here)
I don't know about other operating systems as I have not tested it on anything other than windows.
Works fine in a class as well.
self.root.protocol("WM_DELETE_WINDOW", self.your_method_here)
I have added some code to your post to illustrate its use. Note when you press the X button the program will rune the close_program method.
Edit: Without being able to test on Mac I have added what I think will fix your problem. I have added an if statement in the close_program method to check if the top level exist before attempting to close.
Update: I added a check for the variable win
to deal with possible errors if toplevel was never opened but still trying to close root window.
from tkinter import *
class Window(Toplevel):
def __init__(self, master):
Toplevel.__init__(self)
self.protocol("WM_DELETE_WINDOW", self.close_program)
def close_program(self):
print ("destroying Window")
self.destroy()
class MainWindow(Tk):
def __init__(self):
Tk.__init__(self)
Button(self, command=self.open_window).grid(row=0, column=0)
self.protocol("WM_DELETE_WINDOW", self.close_program)
def open_window(self):
global win
win = Window(self)
win.grab_set()
def close_program(self):
if 'win' in globals():
if win.winfo_exists() == 1:
print("top level still active")
else:
print("destroying MainWindow")
self.destroy()
else:
print("destroying MainWindow")
self.destroy()
app = MainWindow()
app.mainloop()
Upvotes: 1
Reputation: 21453
Lets say that if the child window exists, trying to close the parent window will put it into focus, this would require a few changes:
.protocol("WM_DELETE_WINDOW")
so it checks for a child window.class MainWindow(Tk):
def __init__(self):
Tk.__init__(self)
Button(self, text="hello there", command=self.open_window).grid(row=0, column=0)
self.protocol("WM_DELETE_WINDOW", self.try_to_close)
self.win = None
def open_window(self):
if self.win is None or not self.win.winfo_exists():
self.win = Window(self)
self.win.lift(self)
self.win.focus_set()
def try_to_close(self):
if self.win is not None and self.win.winfo_exists():
self.win.lift()
else:
self.destroy()
Upvotes: 1