Python: removing a TKinter frame - python

I want to remove a frame from my interface when a specific button is clicked.
This is the invoked callback function
def removeMyself(self):
del self
However, it doesn't remove itself. I'm probably just deleting the object in python without updating the interface ?
thanks
Update
self.itemFrame = tk.Frame(parent)
self.itemFrame.pack(expand=False, side=tk.TOP)
removeB = tk.Button(self.itemFrame, text="Remove", width=10, command=self.removeIsosurface)
def removeIsosurface(self):
self.itemFrame.Destroy()
Error message:
AttributeError: Frame instance has no attribute 'Destroy'

To remove, call either frm.pack_forget() or frm.grid_forget() depending on whether the frame was packed or grided.
Then call frm.destroy() if you aren't going to use it again, or hold onto the reference and repack or regrid when you want to show it again.

del does not delete anything. del something just removes something from the local scope. And although if something was the only reference to an object, it may allow the object it to be garbage collected in the future, don't even think of using del to delete objects!!! And since self is just a normal variables, del self does nothing, except of course stopping the rest of the method from accessing the instance (so at the end of the method, it's actually like pass).
The exact way to remove a widget from the GUI depends on what geometry manager you use. If you used .grid(), you can use .grid_forget(). Note that this still doesn't destroy the widget - quite the contrary, you can go on and .grid() it again! - but that doesn't make any difference.

Let's say you're making a class. You have to do a couple of things special here:
The frame you want to destroy has to be an instance variable
You have to write a callback (which you did)
So, here's how a basic prototype would look.
from Tkinter import Tk, Frame, Button, Label
class GUI:
def __init__(self, root):
self.root = root # root is a passed Tk object
self.button = Button(self.root, text="Push me", command=self.removethis)
self.button.pack()
self.frame = Frame(self.root)
self.frame.pack()
self.label = Label(self.frame, text="I'll be destroyed soon!")
self.label.pack()
def removethis(self):
self.frame.destroy()
root = Tk()
window = GUI(root)
root.mainloop()
Happy hunting!

wont this help : self.destroy()
chk this out : PY cookbook the last para

Related

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.
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.

Displaying only one frame at a time in tkinter

I've been struggling with this for a while. I think I'm missing some simple piece of information and I hope you guys can help clear this up for me.
I'm trying to get tkinter to display different frames which I will eventually place widgets inside of. Here's what I did:
I've made a class that is supposed to initialize the window and make all the different frames the program will run.
I've made a separate class for each frame(I'm intending to have variables associated with the different classes when the program is done), and assigned a variable that will start that class up and make it run it's init function
I ended the StartUp class by telling it to tkraise() the frame I want displayed, and that's where things stop working correctly.
I set each frame to a different color, so when you run this program you will see that they split the screen space up instead of one being raised to the top. What am I missing?
One last point, I am purposely trying to spell everything out in my program, I learn better that way. I left it so I have to type tkinter.blah-blah-blah in front of each tkinter command so I can recognize them easily, and I decided not to have my classes inherit Frame or Tk or anything. I'm trying to understand what I'm doing.
import tkinter
class StartUp:
def __init__(self):
self.root = tkinter.Tk()
self.root.geometry('300x300')
self.container = tkinter.Frame(master=self.root, bg='blue')
self.container.pack(side='top', fill='both', expand=True)
self.page1 = Page1(self)
self.page2 = Page2(self)
self.page1.main_frame.tkraise()
class Page1():
def __init__(self, parent):
self.main_frame = tkinter.Frame(master=parent.container, bg='green')
self.main_frame.pack(side='top', fill='both', expand=True)
class Page2():
def __init__(self, parent):
self.main_frame = tkinter.Frame(master=parent.container, bg='yellow')
self.main_frame.pack(side='top', fill='both', expand=True)
boot_up = StartUp()
boot_up.root.mainloop()
When you do pack(side='top', ...), top doesn't refer to the top of the containing widget, it refers to the top of any empty space in the containing widget. Page initially takes up all of the space, and then when you pack Page2, it goes below Page1 rather than being layered on top of it.
If you are using the strategy of raising one window above another, you need to either use grid or place to layer the widgets on top of each other. The layering is something pack simply can't do.
Your other choice is to call pack_forget on the current window before calling pack on the new windowl

Method runs upon it being addressed as event handler

I'm learning Tkinter and I'm pretty new to programming.
I'm trying to create a window containing a frame, containing a button that deletes the frame containing the button. This is what I've written so far:
class Menu(Frame):
def __init__(self, master):
super(Menu, self).__init__(master)
self.pack()
self.create_bttn()
def create_bttn(self):
self.b1 = Button(self, text ="Instruktioner")
self.b1["command"] = self.instructions()
self.b1.pack()
def instructions(self):
self.pack_forget()
This code seems to create the frame and the button, then delete them again, without me calling the instructions method! I don't understand why and how to avoid this. I'd appreciate any help.
When you instantiate your Menu object, it calls to create_bttn() and this last method calls self.instructions(). You may want to modify some of the following lines:
self.b1["command"] = self.instructions()
or inside the instructions method
self.pack_forget()
Edit
Try replacing this
self.b1["command"] = self.instructions()
with
self.b1["command"] = self.instructions # without ()
Stop calling it yourself.
self.b1["command"] = self.instructions

How to test to see if a top-level window is open?

I'm feeling somewhat like Python programming may not be my thing....
I have created a tkinter GUI that uses a button callback to open another window (other searches say this window should be a top-level window) and it works pretty good, how-ever each time the button is pressed it opens another identical (as far as I can tell) window.
Question: how can I test to see if a window (opened with the button) already exists and thus prevent duplicates from being generated???
NOTE: I am not (yet) a OOP programmer so please avoid that paradigm if possible...
regards,
Bill W.
I am not (yet) a OOP programmer so please avoid that paradigm if possible...
Sooner or later, you'll have to understand object-oriented programming if you want to program in Python successfully. The alternative (global variables and functions everywhere) is not definitely a good approach. Even Tkinter has lots of classes with its respective methods, so it looks like it is necessary for your purpose.
Back to your question, a solution could be setting the Toplevel window as an attribute of a class where you wrap all your application, and only open a new window if this attribute is None. To set this attribute to None when you close the window, you can use the protocol method to set a callback.
This is a small working example where you can see how it would work:
import Tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.button = tk.Button(self, text="Open a new window", command=self.openwindow)
self.button.pack()
self.toplevel = None
def openwindow(self):
if self.toplevel is None:
self.toplevel = tk.Toplevel(self)
self.toplevel.protocol('WM_DELETE_WINDOW', self.removewindow)
def removewindow(self):
self.toplevel.destroy()
self.toplevel = None
app = App()
app.mainloop()
You can use this method winfo_exists() to check if the window exists.
if the return value is 0, it means the window doesn't exist.
if the return value is 1, it means the window exists.
Sample Code...
from tkinter import *
mainWindow = Tk()
mainWindow.title("This is main Window")
# create a top-level window
newWindow = Toplevel(mainWindow)
newWindow.title("This is Toplevel window")
print("Before destroying window = " + str(newWindow.winfo_exists()))
newWindow.destroy()
print("After destroying window = " + str(newWindow.winfo_exists()))
mainloop()
Output is...
# Before destroying window = 1
# After destroying window = 0

Change label text from variable

I am trying to write a program that has twenty five buttons, when one is pressed, it will read from a text file, store it in a variable, then make the text of the label at the bottom of the page change to the text of the text file. Here is my code so far:
from Tkinter import*
box1 = 'C:/Users/Geekman2/Documents/Tests/box1.txt'
var = StringVar()
var.set("man")
def openfile(filename):
filetxt = (open(filename,"r").read())
#filetxt.set(iletxt)
print filetxt
return filetxt
def Box1():
openfile(box1)
openfile(box1)
donut = Tk()
donut.geometry('450x450')
cupcake = Button(donut,text = "Box #1", command= Box1 )
cupcake.pack()
Whatsin = Label(donut,textvariable = var)
Whatsin.pack(side =BOTTOM)
donut.mainloop()
These two lines are giving me trouble, whenever I uncomment them and try to run the program I get the error "AttributeError: 'NoneType' object has no attribute 'tk'"
var = Stringvar()
var.set("man")
Can anyone tell me what might be the cause of this? I know what the error means, but as far as I can tell it doesn't apply in this situation
You need to instantiate an instance of Tk before you can use StringVar. Move donut = Tk() before your lines and it should work.
StringVar (as well as other Tkinter variable) are wrappers around Tcl variable1.
Your error come from creating a StringVar before the Tcl interpreter is initialized.
Thus you might call Tk()(which perform such initialisation) before creating your variables.
If you look at StringVar constructor signature: __init__(self, master=None, value=None, name=None) you see that as other Tkinter objects, the constructor accepts a master as first argument. This master is essentially needed to access the Tcl interpreter. If not provided, there is a fallback to a global Tkinter.Tk instance _default_root, which is None in your case. Asking the Tcl interpreter (field named tk) on it raise the AttributeError.
Note that for widgets, not providing master lead to the creation of a default one, but not on variables.
1 the whole Tkinter toolkit is a wrapper around a Tcl toolkit called Tk. Tcl variables allow to be traced, ie bind callback on variable change. Tk heavily use this mechanism and thus, Tkinter has to provide access to Tcl variables.

Categories