Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tk(), Toplevel() and winfo_toplevel(). Difference between them and how and when to use effectively?

I am trying to understand how a widget is being created. And I found above three functions are getting used in creating a widget, yet I couldn't come up with the difference and the advantage of one over the other. Even though, I had taken a look on this answer that still leaves me with confusion (and it hadn't said anything about winfo_toplevel too).

Here is my code.

from tkinter import *

root = Tk()
root.title("Root widget")
root.mainloop()

window = Toplevel()
window.title("Window widget")
window.mainloop()

On running above code "Root" widget is getting created. On closing "Root", two widgets are created with one titled "Window widget" and other being unwanted. On closing unwanted widget, "Window widget" is also getting destroyed. What is actually happening here and how to overcome?

Another sample:

class ldo(Frame):
    def __init__(self, master = None):
        Frame.__init__(self,master)
        self.grid()
        self.appOutline()

    def appOutline(self):
        top = self.winfo_toplevel()
        self.menuBar = Menu(top)
        top["menu"] = self.menuBar
        self.subMenu1 = Menu(self.menuBar)
        self.menuBar.add_cascade(label = "File", menu = self.subMenu1)

app = ldo()
app.master.title("Sample UI")
app.mainloop()

On the other hand, this code is using winfo_toplevel() where the widget looks perfectly fine. Here, my assumption is, Frame plays a role of creating widget and winfo_toplevel() is an enhancing tool to other tkinter items. But would like to know what it does actually.

However, below snippet is not working:

winf = winfo_Toplevel()
winf.title("Winfo Widget")
winf.mainloop()

And returning such error:

winf = winfo_Toplevel()
NameError: name 'winfo_Toplevel' is not defined

What is the exact difference between Tk(), Toplevel() and winfo_Toplevel(). What and when should one be used effectively. Looking for really a better understanding.

like image 893
cs2612 Avatar asked Jan 16 '18 10:01

cs2612


1 Answers

On running above code "Root" widget is getting created. On closing "Root", two widgets are created with one titled "Window widget" and other being unwanted. On closing unwanted widget, "Window widget" is also getting destroyed. What is actually happening here and how to overcome?

When you create any widget with the absence of an actual Tk() instance, a Tk() instance automatically gets created, thus resulting in an unwanted Toplevel-like widget when the second part of the first code snippet runs. Additionally, when a widget gets created with the absence of master option, it is assumed that the instance is a child of one of the Tk instances, in above case, there's only one, and that's the one that got automatically created. When a parent gets destroyed all widgets that are under it also gets destroyed, so when you close the unwanted widget that is an instance of Tk, the Toplevel instance also gets destroyed as its parent is destroyed.

On the second part, winfo_toplevel refers to the automatically created Tk instance again and creates other children with that automatically created Tk as the parent, which should be technically fine but would be harder to maintain as a code, than the standard ways of creating the same GUI I'd presume.


winf = winfo_Toplevel()
winf.title("Winfo Widget")
winf.mainloop()

In the code piece above, unless imported or otherwise defined winfo_Toplevel has no meaning, first of all, it's not as same as winfo_toplevel as python is case sensitive. Secondly, even if python wasn't case sensitive, it would still throw an error as it is a method and it lacks the first positional argument, which is the object instance to the class of which the winfo_toplevel method is also defined for.

Essentially, you're trying to use a case-insensitive spelling of a method, as if it is a class name such as Toplevel or Tk, which winfo_toplevel has almost nothing to do with.


Examine the following code:

import tkinter as tk

root = tk.Tk()
root.title("This is the actual Tk instance, root")

toplevel = tk.Toplevel(root)
toplevel.title("This is a Toplevel, whose parent is root"),

r_lbl = tk.Label(text="""This label is a children to the default master, 
    as it lacks the first positional argument for an explicit parent 
    assignment.""")

r_lbl2 = tk.Label(r_lbl.winfo_toplevel(), text="""This label checks who the
    toplevel parent for r_lbl is, and then selects that parent as a parent
    to itself.""")

r_lbl3 = tk.Label(root, text="""This label will appear on root, as it's
    explicitly passed as the first positional argument, which is the parent,
    as root.""")

t_lbl = tk.Label(toplevel, text="""This label will appear on toplevel, as it's
    explicitly passed as the first positional argument, which is the parent,
    as toplevel.""")

t_lbl2 = tk.Label(t_lbl.winfo_toplevel(), text="""This label checks who the
    toplevel parent for t_lbl is, and then selects that parent as a parent
    to itself.""")

r_lbl.pack()
r_lbl2.pack()
r_lbl3.pack()
t_lbl.pack()
t_lbl2.pack()
root.mainloop()

In conclusion, Tk, while being a Toplevel widget, is also the tcl interpreter for the entire GUI that runs in a thread. There can be more than one present, which is discouraged as usually multiple instances of it is unjustified, but there also has to be at least one instance present in order to have a GUI.

Toplevel can be considered to be the only visual part of a Tk instance, and it can be used when there is a need for multiple window-like widgets.

Finally, winfo_toplevel is merely a method returns the reference for the Toplevel-like parent that a widget is in, be the parent an instance of a Toplevel or a Tk.

like image 179
Nae Avatar answered Sep 24 '22 01:09

Nae