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.
Related
I have no problem with binding ctrl-h. However, when I do the ctrl-h, I notice that the last character is also removed from the entry. I think this might be the default ctrl-h binding of python. How can I disable that?
---Update---
I have added the return 'break' thing. But it still doesn't work. The last character is immediately removed before the askstring dialog shows up. Here is the code that is bound.
def replace(self):
target = simpledialog.askstring(title = 'Replace', prompt = 'Replace Target')
if not target:
return 'break'
withValue = simpledialog.askstring(title = 'Replace', prompt = 'Replace With')
if not withValue:
return 'break'
for entry in self.entries.values():
setEntry(entry, entry.get().replace(target, withValue))
return 'break'
By the way I bind it with the master not the entry because I have a lot of entries. Binding with the master is way easier.
This is how I bind it.
self.master.bind('<Control-h>', lambda event: self.replace())
self.master is defined here:
class Generator(Frame):
def __init__(self, master):
Frame.__init__(self, master)
## init variables
self.master = master
This is what I pass in.
root = Tk()
gui = Generator(root)
gui.pack()
root.title('Generator')
root.mainloop()
Because you are binding to the root window rather than an individual widget, there's nothing you can do in your function. Bindings are processed in this order:
bindings on a specific widget
bindings on a widget class
bindings on the toplevel window in which the widget exists
bindings on the special tag "all"
If at any time in the processing of those bindings a function returns the string "break", no further processing will happen. Thus, if you have a binding on a specific widget and return "break", the default class binding won't be processed. However, if you return "break" from a binding to the root window, that binding isn't processed until after the class binding. Therefore, it's impossible for this sort of binding to prevent the default behavior.
However, tkinter bindings are remarkably customizable, so there are solutions. Given that you potentially want to inhibit the default behavior, the most straight-forward solution is to either bind to the class so that you completely replace the default behavior, or bind to each widget individually so that you can prevent the class binding from happening.
If you really want the binding to be universal by binding to the root window, then the easiest solution might be to change the order of processing for all widgets that have default bindings for control-h.
For example, to move the handling of root-level bindings before class-level bindings, you can do something like this:
entry = tk.Entry(root)
bindtags = entry.bindtags()
entry.bindtags((bindtags[2], bindtags[0], bindtags[1], bindtags[3]))
For more information on exactly how bindings are processed, you might want to look at the following questions:
Basic query regarding bindtags in tkinter
How to bind self events in Tkinter Text widget after it will binded by Text widget?
Here is a simple example that binds to the root window, but changes the bind tags so that the default binding can be defeated by returning "break":
import tkinter as tk
def custom_backspace(event):
entry.insert("insert", "<backspace>")
return "break"
root = tk.Tk()
entry = tk.Entry(root)
entry.pack(fill="x")
bindtags = entry.bindtags()
entry.bindtags((bindtags[2], bindtags[0], bindtags[1], bindtags[3]))
root.bind("<Control-h>", custom_backspace)
root.mainloop()
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.
If I want to create a Tkinter GUI simply with statements, I can do this:
from Tkinter import *
root = Tk()
root.title("Test Window")
tkFrame = Frame(root)
tkButton = Button(tkFrame)
[...]
The documentation, however, advises that Tkinter be used with a class definition, subclassing a Frame widget:
class App(Frame):
[...]
I would like to understand why that is so. Why can't we subclass the Frame's container, the window? It appears that is what is done with statements in the first example, so why not in a class definition?
EDIT (following Bryan Oakley's answer):
I would like to instantiate at the highest level of Tkinter, which I assume to be Tk() (though I have come across references stating Frame is the top level, but never mind). Indeed, the following will create a window:
from Tkinter import *
class Application(Tk):
pass
app = Application()
app.mainloop()
...but as soon as I try to add widgets I either get errors or two windows, with the widgets in a new window, depending on how I structure the code. Here's a basic example that will produce a second window with the button:
from Tkinter import *
class Application(Tk):
tkBtn = Button()
tkBtn.pack()
app = Application()
app.mainloop()
Anything more, using self, __init__, etc., produces errors. Could someone point me to working code that instantiates Tkinter at the highest level? Just like all the Frame subclasses I'm seeing, but at the highest level?
There is nothing that says a tkinter class must inherit from a frame. You can inherit from any of the tkinter widgets, or any other classs. If you have found documentation that states otherwise, that documentation is wrong. Using Frame is a logical choice since it is designed to be a container of other widgets, but it is not the only choice.
Personally I inherit from a frame because I find it convenient. Some of my GUIs need the ability to open more than one identical window. By having my main code in a Frame I am able to create multiple windows simply by creating multiple instances of the frame, and packing them in Toplevel widgets.
When you inherit from Tk, you can only have a single instance. In the real world that's usually enough, and there's absolutely nothing wrong with doing it that way. Since I personally write a fair number of tkinter programs, having them all start out exactly the same is convenient for me.
Another good choice is a Canvas since you can easily add a background image, which is not something you can do with a Frame.
Bottom line: you are absolutely not required to inherit from Frame. Inherit from whatever you want.
(the following was written in response to an edit of the original question)
In reference to this code:
from Tkinter import *
class Application(Tk):
tkBtn = Button()
tkBtn.pack()
app = Application()
app.mainloop()
The reason you see two windows is that you're not creating the class properly. You need to call the __init__ method of the superclass before creating widgets, because that's what actually creates the root window. Because you don't, you end up with two windows. You get one that is created implicitly when you add a button to a not-yet-constructed root window, and you get another when your subclass finishes initializing.
The solution is to not take shortcuts, and instead initialize the class properly:
from Tkinter import *
class Application(Tk):
def __init__(self):
Tk.__init__(self)
tkBtn = Button()
tkBtn.pack()
app = Application()
app.mainloop()
Note that this isn't a tkinter-specific problem. When subclassing, unless you have explicit reasons to do otherwise, you always should call the __init__ method of the superclass.
You asked for working examples, here are a couple:
https://stackoverflow.com/a/22424245/7432
https://stackoverflow.com/a/11405393/7432
You might also want to read the responses in the question Inheriting from Frame or not in a Tkinter application
I am currently studying a text to try and teach myself more about TkInter as I'm trying to improve my Python 3 programming. The text can be found here, if necessary: http://www.ferg.org/thinking_in_tkinter/all_programs.html
In the section labelled "tt040.py" there is an example code, part of it is:
self.button1 = Button(self.myContainer1)
self.button1["text"] = "Hello, World!" ### (1)
self.button1["background"] = "green" ### (1)
self.button1.pack()
self.button2 = Button(self.myContainer1)
self.button2.configure(text="Off to join the circus!") ### (2)
self.button2.configure(background="tan") ### (2)
self.button2.pack()
self.button3 = Button(self.myContainer1)
self.button3.configure(text="Join me?", background="cyan") ### (3)
self.button3.pack()
The explanation for this part of the code is :
"(2) For button2, the process is essentially the same as for button1, but instead of accessing the button's dictionary, we use the button's built-in "configure" method.
(3) For button3, we see that the configure method can take multiple keyword arguments, so we can set multiple options in a single statement."
What does the explanation actually mean? As in, what is the actual difference (with .pack) or need for the .configure method? What is meant by "the button's dictionary"?
Tkinter objects attribute are not handled through python attribute mechanism (ie you can not do self.button1.text = "hello"). Instead, tkinter provide two ways to alter this attribute:
use the object as a dictionnary: self.button1["text"] = "hello"
use the config method with named argument: self.button1.config(text="hello")
Both are equivalent. Note that you could also have passd such initialisation value through constructor named argument to perform both instanciation an initialisation in one step: self.button1 = Button(self.myContainer1, text="hello")
pack serve a totally different purpose. It is a geometry management instruction. Used without argument button1.pack() ask to place button1 in its parent widget below the precedent sibling (if any). You can use options to specify relative position, or resize behavior.
There are other geometry manager for tkinter: grid and place, see this response for a comparison.
Each widget has a dictionary of attributes (text, background, ...). You can access it using the regular dictionary syntax, as in self.button1["text"] = "Hello, World!" or using the configure method that you see in the other examples. That's just to set up the looks and behaviour of the widget.
Once you're done, you call pack to let Tkinter now that the widget is ready to be used. Then it will be displayed, etc.
You can see this by executing Tkinter commands step by step in the interpreter, like this:
>>> from Tkinter import *
>>> root = Tk()
>>> bt = Button(root)
>>> bt['text'] = 'hello'
>>> bt.pack()
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