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)
Related
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.
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()
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.
I have a class with a member self.checkbutton (using the TkInter CheckButton), created in the init function with:
self.checkbutton = Checkbutton(self.frame, variable=self.value, command=self.get_entry_and_execute, onvalue="1", offvalue="0")
Now, instead of clicking on the checkbutton in my frame, I want to set it in my code. So, from somewhere in my code, I call setvalue("1") calling this function:
def setvalue(self, value):
if (value == "1"):
print "SELECTING CHECKBUTTON"
self.checkbutton.select()
# self.checkbutton.set(value=1)
Now, when I do this, actually, I can see that the associated "self.get_entry_and_execute" function is called and it even changes some background color. But, the checkbutton remains unchecked (i.e. an empty field without the "V" symbol).
Weirly, when I add the command
self.checkbutton.set(value=1)
, the code complains: AttributeError: Checkbutton instance has no attribute 'set'
but now the checkbutton does get checked!
I am assuming that because of this error, python puts the checkbutton in the correct state (=1) even though the "set" function does not exist. My question is: how can I correctly make python put the "V" inside the checkbutton box? (I.e, something like a "redraw" function).
According to your code, self.value is an instance of a variable class, so all what you need to do is to replace self.checkbutton.set(value=1) by self.value.set(value=1)
I'm trying to generalise a function in my script by sending in the Class' attribute through the function call to an outside function, but since I have to call the attribute self.attribute_name inside the class and object_name.attribute.name outside it, I either get an error that no self.attribute_nameexists outside the code or that no object_name.attribute.nameexists inside. The part of my code concerned is as follows(this is just a fragment of the full code with many parts omitted):
class My_Window:
self.get_info_box = Entry(root)
self.entry_button = Button(root, text="Choose", command =lambda: self.retrieve_input(self.get_info_box, solitaire.cards))
def retrieve_input(self, box, entity):
self.user_input = box.get()
entity = input_check(box)
def input_check(which_box): # Function outside class
my_window.which_box.delete(0, "end") # This is want I would like to do if it worked
return 0
my_window = My_Window()
Something in the back of my head tells me it might be possible to use lambda again to accomplish this but I'm still not sure how to use them properly and I couldn't find any active questions covering this specific case.
Anyone have any ideas how to work this out?
I think what you want is
def input_check(which_box):
getattr(my_window,which_box).delete(0, "end")
return 0
input_check("get_info_box")
but its hard to tell for sure
Try it without the my_window.
def input_check(which_box):
which_box.delete(0, "end")
return 0
Incidentally, entity = input_check(box) won't cause solitaire.cards to retain the value returned by input_check, because assignment doesn't propagate upwards like that. If you want to change solitaire.cards, you'll need to do solitaire.cards = input_check(box) instead. If solitaire isn't visible inside retrieve_input, then you'll need to make it an attribute of self.