I’m trying to test the existence of a toplevel using the winfo_exists() method made available by Tkinter.
However, I cannot test the existence of a Toplevel by passing the name of this to winfo_exists() method.
I enclose a script to better clarify what I would like to do. When you open the app, four buttons are shown. Pressing on the first appears a mask where we can, by pressing the relevant buttons, see the execution of both the winfo_exists() method and the winfo_children() method.
Selecting a Toplevel to test using the radiobox on the right happens that if the relative Toplevel is open the function work fine, otherwise generates the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/home/bc/Desktop/simple_app.py", line 113, in on_test_exist
if self.nametowidget(DICT_TOPLEVELS[self.option.get()]).winfo_exists():
File "/usr/lib/python3.7/tkinter/__init__.py", line 1353, in nametowidget
w = w.children[n]
KeyError: 'toptwo'
Do you have any suggestions?
Basically in an application with many Toplevels, how do you see if a certain Toplevel is open?
Thank you for your attention.
#!/usr/bin/python3
import sys
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
DICT_TOPLEVELS = {0:".topone",
1:".toptwo",
2:".topthree"}
class Main(ttk.Frame):
def __init__(self, parent, ):
super().__init__(name="main")
self.parent = parent
self.init_ui()
def init_ui(self):
f0 = tk.Frame(self)
bts = [("Top One", 4, self.on_open_one, "<Alt-o>"),
("Top Two", 4, self.on_open_two, "<Alt-t>"),
("Top Three", 5, self.on_open_three, "<Alt-w>"),
("Close", 0, self.parent.on_exit, "<Alt-c>")]
for btn in bts:
ttk.Button(f0,
text=btn[0],
underline=btn[1],
command = btn[2]).pack(fill=tk.X, padx=5, pady=5)
self.parent.bind(btn[3], btn[2])
f0.pack()
def on_open_one(self, evt=None):
obj = TopOne(self)
obj.on_open()
def on_open_two(self, evt=None):
obj = TopTwo(self)
obj.on_open()
def on_open_three(self, evt=None):
obj = TopThree(self)
obj.on_open()
class TopOne(tk.Toplevel):
def __init__(self, parent,):
super().__init__(name="topone")
self.parent = parent
self.minsize(200, 100)
self.voices = ('topone','toptwo','topthree')
self.option = tk.IntVar()
self.init_ui()
def init_ui(self):
f0 = tk.Frame(self, bg='SlateGray4', padx=5,pady=5)
f1 = tk.Frame(f0,)
bts = [("Call winfo_exists", 7, self.on_winfo_exists, "<Alt-c>"),
("Get winfo_children", 0, self.on_get_winfo_children, "<Alt-g>"),
("Test exist", 0, self.on_test_exist, "<Alt-t>"),
("Close", 0, self.master.on_exit, "<Alt-c>")]
for btn in bts:
ttk.Button(f1,
text=btn[0],
underline=btn[1],
command = btn[2]).pack(fill=tk.X, padx=5, pady=5)
self.parent.bind(btn[3], btn[2])
f2 = tk.Frame(f0,)
ttk.Label(f2, text="Toplevels:").pack()
for index, text in enumerate(self.voices):
ttk.Radiobutton(f2,
text=text,
variable=self.option,
value=index,).pack()
f0.pack(fill=tk.BOTH, expand=1, padx=5, pady=5)
f2.pack(side=tk.RIGHT, fill=tk.Y, padx=5, pady=5, expand=0)
f1.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5, expand=0)
def on_open(self):
msg = "{0}".format(self.winfo_name().title())
self.title(msg)
def on_winfo_exists(self, evt=None):
for obj in self.nametowidget(".").winfo_children():
if self.nametowidget(obj).winfo_exists():
print("{0} is exist!".format(self.nametowidget(obj).winfo_name()))
def on_get_winfo_children(self, evt=None):
for obj in self.nametowidget(".").winfo_children():
print(self.master.nametowidget(obj))
def on_test_exist(self):
print("You have selected to test if {0} Toplevel exist.".format(DICT_TOPLEVELS[self.option.get()]),)
if self.nametowidget(DICT_TOPLEVELS[self.option.get()]).winfo_exists():
print("Well Toplevel named {0} exists!".format(self.nametowidget(DICT_TOPLEVELS[self.option.get()]).winfo_name()))
else:
print("I’m sorry but Toplevel named {0} doesn’t exist!".format(DICT_TOPLEVELS[self.option.get()]))
class TopTwo(tk.Toplevel):
def __init__(self, parent,):
super().__init__(name="toptwo")
self.parent = parent
self.minsize(200, 100)
self.init_ui()
def init_ui(self):
f = tk.Frame(self, bg='DarkSeaGreen4', padx=5,pady=5)
f.pack(fill=tk.BOTH, expand=1, padx=5, pady=5)
def on_open(self):
msg = "{0}".format(self.winfo_name().title())
self.title(msg)
class TopThree(tk.Toplevel):
def __init__(self, parent,):
super().__init__(name="topthree")
self.parent = parent
self.minsize(200, 100)
self.init_ui()
def init_ui(self):
f = tk.Frame(self, bg='DarkSeaGreen3', padx=5,pady=5)
f.pack(fill=tk.BOTH, expand=1, padx=5, pady=5)
def on_open(self):
msg = "{0}".format(self.winfo_name().title())
self.title(msg)
class App(tk.Tk):
"""Main Application start here"""
def __init__(self,):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
#self.resizable(width=False, height=False)
self.geometry('400x200')
self.title("Simple App")
Main(self).pack(fill=tk.BOTH, expand=1)
def on_exit(self):
msg = "Do you want to quit?"
if messagebox.askokcancel(self.title(), msg, parent=self):
self.destroy()
def main():
app = App()
app.mainloop()
if __name__ == '__main__':
main()
