Python tkinter textvariable in label widget - python

I have made a variable called 'localtime2' within my def in the code and then have a label which says 'textvariable=localtime2.' the problem is that it does not display the information about the variable.
localtime2 = time.asctime(time.localtime(time.time()))
tk.Label(roots, font=('arial', 16, 'bold'), textvariable=localtime2, bd=16, anchor="w").grid(row=2, column=0)
This is all I have in the code about this variable and it is not coming up with any error in the terminal. It just doesnt show at all.

Edit: The solution to the original post was using text=localtime2.get() instead of textvariable=localtime2 in the label widget (for some strange reason). However, my original answer is still correct as tkinter variables should be used and so I will keep it up.
You must use tkinter variables in tkinter widgets and not normal python variables. Tkinter variables are slightly different to normal variables and must first be defined as a specific data type. For example, a variable which contains a string must be first created like so:
string_variable = tk.StringVar()
likewise a boolean would be created like so:
boolean_variable = tk.BooleanVar()
Read here for more information on tkinter variables.
These variables are in fact classes so in order to set them use must call the .set() method. Therefore to set a tkinter String variable to "a string" you would use the following code:
string_variable = tk.StringVar() # Create the variable
string_variable.set("a string") # Set the value of the variable
Thus to fix your code you need to make localtime2 a tkinter variable and set it to the time using the .set() method.
Example:
localtime2 = tk.StringVar() # Create the localtime2 string variable
localtime2.set(time.asctime(time.localtime(time.time()))) # Set the variable
tk.Label(roots, font=('arial', 16, 'bold'), textvariable=localtime2, bd=16, anchor="w").grid(row=2, column=0)

Whenever there is a change in a tkinter variable, the update is automatically reflected everywhere. Because of this property you cannot use a normal python variable here.
Try using StringVar() and then setting the variable content using set()

Related

How to make tkinter variables dynamically

Tkinter dynamically made variables are not working properly in checkbutton of menu. They are displaying the wrong image as they were supposed to.
Here's my code:
def checkbutton(self,index,var=None):
self.popup_menu.add_checkbutton(label=self.btns[index]['text'], command = lambda : self.menu(index) , variable=IntVar().set(1))
I'm using direct method variable=IntVar().set(1). I aslo tried making variable like :
currentVar=IntVar()
currentVar.set(1)
But I encountered the same problem.
First variable=IntVar().set(1) will assign None, result of set(1) to variable option. Second dynamically created variable will be garbage collected after the function completes.
You need to create an instance variable:
def checkbutton(self,index,var=None):
var1 = IntVar(value=1)
self.popup_menu.add_checkbutton(label=self.btns[index]['text'], command=lambda: self.menu(index), variable=var1)
# self.varlist should be already created in __init__()
self.varlist.append(var1)

Tkinter StringVar to uppercase

I get the user entry as a StringVar from an Entry box but would like to convert it to uppercase.
I then use the variable in another routine. I have been unable to find the syntax to simply convert 'c6h12' to 'C6H12' when its in a StringVar.
Any help appreciated.
The following snippet does the trick, simply using the StringVar get() method to get the old value, and set() method to update the value after calling upper()
from tkinter import *
root = Tk()
sv = StringVar(value="c6h12")
sv.set(sv.get().upper())
root.mainloop()

Checkbuttons aren't working inside function

Basically I have a bunch of checkbuttons, with some on and some off by default. I'm having an issue where if I put the checkbuttons inside the function they aren't on by default like they should be.
Here's the working code:
from tkinter import *
root = Tk()
integer = IntVar(value=1)
Checkbutton(root, text="Should be on by default", variable=integer).grid()
root.mainloop()
Here's the not working code:
from tkinter import *
root = Tk()
def main():
integer = IntVar(value=1)
Checkbutton(root, text="Should be on by default", variable=integer).grid()
main()
root.mainloop()
Can anyone explain to me why this is?
By the time you see the window, integer no longer exists and the checkbox shows as unchecked for lack of a variable to store its state.
Compare:
from tkinter import *
root = Tk()
def main():
global integer
integer = IntVar(value=1)
Checkbutton(root, text="Should be on by default", variable=integer).grid()
main()
root.mainloop()
The global integer tells Python that this integer should be defined at the 'global' level and thus it stays around after the function.
By the way, it's bad practice to name a variable after its type - try picking a name that represents what its value means, instead of describing its type.
You shared some additional code with a similar problem (only repeating the elements that matter):
from tkinter import *
def change_job_skills(name):
top_window = Toplevel(root)
# ..
skill_dictionary = {}
# ..
row_ = 2
column_ = 0
# ..
job_focuses_dictionary = {}
for key in sorted(job_focuses_dictionary.keys()):
Checkbutton(top_window, text=key.strip(""),
variable=job_focuses_dictionary[key]).grid(row=row_, column=column_, sticky=W)
# ..
# no definition was provided of actually_change_job_skills, but it's not important here
Button(top_window, text='Submit',
command=lambda: [actually_change_job_skills(skill_dictionary, name),
top_window.destroy()]).grid(row=0, column=0, sticky=W)
# no reference is made to `job_focuses_dictionary` in a way that survives the function
root = Tk()
change_job_skills("Community Engagement")
root.mainloop()
Although both skill_dictionary and job_focuses_dictionary are used in the code of change_job_skills, skill_dictionary is used in the definition of a lambda function, which is then passed as the command argument for Button. Since the button will need to call that function later, a reference to the lambda is saved inside it and since the function body of the lambda references skill_dictionary, the dictionary survives the function returning.
However, job_focuses_dictionary is only referenced as job_focuses_dictionary[key], retrieving a value from it - the dictionary itself isn't passed to anything that maintains a reference to it outside the function, so when the function returns, the dictionary is garbage-collected.
Same problem, but a bit harder to spot. (#acw1668 pointed it out in the comments as well)
Note that I also renamed your parameter Name to name, you should reserve capitalised names for types and lowercase names for variables, in line with Python standard naming, which helps future you and others more quickly read and understand your code. Nothing to do with the problem though.

Refer to tkinter widget by its instance

I am learning Python w/ Tkinter and I recently learned the difference between the reference and the name/instance of a widget. The reference is the string you assign to a widget (which can be changed later on), but the name seems to be the actual identity of the widget (which is immutable). Essentially it seems as though the reference is a nickname of a widget because it can change overtime and be different depending on who you are talking to, while the actual name of the widget on the widget's drivers license is always the same. Specifically, in this line of code...
sample_frame = Frame(root, name = 'frame1', bg = 'blue', height = 50, width = '50')
"sample frame" is the reference, while 'frame1' is the name.
Unless I specifically assign the string 'frame1' as the name of this frame, python automatically generates a number sequence as its name. In order to view the name of any widget you just have to add...
print(str(sample_frame))
(the output in this example is .frame1)
So in Tkinter if I wanted to place this frame in my GUI i would have to pack/grid/place it in the following line like so...
sample_frame.pack()
But what I would like to do is call the pack method on this frame widget by its name rather than its reference. Something like this...
frame1.pack() #or
.frame1.pack() #because of that period
The problem is that Python claims frame1 was never defined, and .frame1 is invalid syntax. Does anybody know how to do something like this? Thanks.
For broader context I am doing this because I iterated the creation of 21 different frames and placed them in a 3x7 grid. Because of this all 21 frames have an identical reference. BUT, I made sure to make the name of each frame corresponds with its position.
The name= option sets the name of the widget within the Tcl environment that actually implements the GUI - it has no effect on the Python side. The only reason I can think of for doing this is that it might make Tcl error messages somewhat easier to read (the auto-generated widget name that you'd otherwise get is not particularly meaningful).
As always, the proper way to deal with multiple objects created in a loop is to store them in a container of some sort. In your case, it could be a 21 element list, a nested list (widget[row][column]), or perhaps a dict indexed by tuples (widget[row, column]).
While I fully agree with jasonharper's answer that you should keep a proper reference to the widgets and I do not recommend using what I'm about to explain, there actually is a way to achieve what you're asking. There's a widget method called nametowidget(), which returns the widget object when you give it a name. Note that you should call the method on the object (Tk, Toplevel, Frame) that contains the widget you're looking for.
So following your example, this works:
from tkinter import *
root = Tk()
sample_frame = Frame(root, name = 'frame1', bg = 'blue', height = 50, width = '50')
root.nametowidget('frame1').pack()
root.mainloop()
And if you would do the same with a button inside the frame you should do:
sample_button = Button(sample_frame, text='Button', name='button1')
sample_frame.nametowidget('button1').pack()

How to access IntVar or StringVar or DoubleVar or BooleanVar from its master

my code looks like this
root = Tk()
a = IntVar(root)
later in my code i cannot access 'a' but i can access 'root'
I tried
root.getvar('a')
root.children
root.client()
root.slaves()
root.getint(0)
and none of them is or contains 'a'
and I need value from 'a'
how can I get it
You cannot get a tkinter variable given only the root window, or the master of a widget. At least, not without a lot of work. Tkinter simply doesn't keep track of these variables for you.
To gain access to the variable, you must do the same with it as you do with any other python variable or object: you need to make it global, or a class or instance variable, or you need to pass it to the function that needs access.

Categories

Resources