How to determine if tkinter Toplevel widget exists.?
Question:
I have a need to destroy a Toplevel
widget if it already exists before creating it. I’ve researched this and every response I can find here and elsewhere suggest using winfo_exists
; however, the following code demonstrates that doesn’t work. It fails with the error: object has no attribute ‘toplevel’
I can use a brute force try:/except: to destroy the widget, but surely there’s a better way.
BTW: I am on Windows 10 running Python 3.11.1
# does_widger_exists.py
import tkinter as tk
class TL_GUI:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x100')
self.root.title('Tkinter Test')
button0 = tk.Button(self.root,text='Create Toplevel',command=self.makeToplevel).pack(pady=20)
self.root.mainloop()
def makeToplevel(self):
if tk.Toplevel.winfo_exists(self.toplevel):
self.toplevel.destroy()
self.toplevel = tk.Toplevel(self.root)
self.toplevel.geometry('500x100')
self.toplevel.title('I am a TopLevel')
text0 = tk.Label(self.toplevel,text='Hello World',height=1,width=25,borderwidth=5).pack()
if __name__ == '__main__':
TL_GUI()
Answers:
You’ll need to initialize self.toplevel
to some value in your __init__
method so the first call to makeToplevel
doesn’t fail when it gets to the conditional; as written, self.toplevel
doesn’t exist when the check is first run. With this fix, subsequent calls to makeToplevel
will work as expected
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x100')
self.root.title('Tkinter Test')
self.toplevel = None # initialize this instance variable
button0 = tk.Button(
self.root,
text='Create Toplevel',
command=self.makeToplevel
).pack(pady=20)
self.root.mainloop()
You should also update the condition checked by the if
statement as follows:
def makeToplevel(self):
if self.toplevel and self.toplevel.winfo_exists(): # make this change
self.toplevel.destroy()
self.toplevel = tk.Toplevel(self.root)
self.toplevel.geometry('500x100')
self.toplevel.title('I am a TopLevel')
text0 = tk.Label(
self.toplevel,
text='Hello World',
height=1,
width=25,
borderwidth=5
).pack()
Oh, and one final note: using pack()
like you are on button0
and text0
can cause trouble if you’re not careful! As written, button0
and text0
will both always evaluate to None
since that’s the value returned by pack()
. If you want to refer to these widgets anywhere else, you should pack()
them on a separate line, e.g.:
button0 = tk.Button(...) # now 'button0' is equal to the Button object, not None
button0.pack(...)
text0 = tk.Label(...) # now 'text0' is equal to the Label object, not None
text0.pack(...)
I have a need to destroy a Toplevel
widget if it already exists before creating it. I’ve researched this and every response I can find here and elsewhere suggest using winfo_exists
; however, the following code demonstrates that doesn’t work. It fails with the error: object has no attribute ‘toplevel’
I can use a brute force try:/except: to destroy the widget, but surely there’s a better way.
BTW: I am on Windows 10 running Python 3.11.1
# does_widger_exists.py
import tkinter as tk
class TL_GUI:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x100')
self.root.title('Tkinter Test')
button0 = tk.Button(self.root,text='Create Toplevel',command=self.makeToplevel).pack(pady=20)
self.root.mainloop()
def makeToplevel(self):
if tk.Toplevel.winfo_exists(self.toplevel):
self.toplevel.destroy()
self.toplevel = tk.Toplevel(self.root)
self.toplevel.geometry('500x100')
self.toplevel.title('I am a TopLevel')
text0 = tk.Label(self.toplevel,text='Hello World',height=1,width=25,borderwidth=5).pack()
if __name__ == '__main__':
TL_GUI()
You’ll need to initialize self.toplevel
to some value in your __init__
method so the first call to makeToplevel
doesn’t fail when it gets to the conditional; as written, self.toplevel
doesn’t exist when the check is first run. With this fix, subsequent calls to makeToplevel
will work as expected
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x100')
self.root.title('Tkinter Test')
self.toplevel = None # initialize this instance variable
button0 = tk.Button(
self.root,
text='Create Toplevel',
command=self.makeToplevel
).pack(pady=20)
self.root.mainloop()
You should also update the condition checked by the if
statement as follows:
def makeToplevel(self):
if self.toplevel and self.toplevel.winfo_exists(): # make this change
self.toplevel.destroy()
self.toplevel = tk.Toplevel(self.root)
self.toplevel.geometry('500x100')
self.toplevel.title('I am a TopLevel')
text0 = tk.Label(
self.toplevel,
text='Hello World',
height=1,
width=25,
borderwidth=5
).pack()
Oh, and one final note: using pack()
like you are on button0
and text0
can cause trouble if you’re not careful! As written, button0
and text0
will both always evaluate to None
since that’s the value returned by pack()
. If you want to refer to these widgets anywhere else, you should pack()
them on a separate line, e.g.:
button0 = tk.Button(...) # now 'button0' is equal to the Button object, not None
button0.pack(...)
text0 = tk.Label(...) # now 'text0' is equal to the Label object, not None
text0.pack(...)