Understanding winfo_exists()

Viewed 46

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

enter image description here

0 Answers
Related