tkinter radiobutton not updating variable - python

--UPDATE:
I changed
variable=self.optionVal.get()
to
variable=self.optionVal
But nothing changed.Also I wonder why it automatically call self.selected while compiling?
----Original:
I'm trying to get familiar with radiobutton, but I don't think I understand how radiobutton works. Here's a brief code for demonstration:
self.optionVal = StringVar()
for text, val in OPTIONS:
print(text,val)
radioButton = Radiobutton(self,
text=text,
value=val,
variable=self.optionVal.get(),
command = self.selected())
radioButton.pack(anchor=W)
def selected(self):
print("this option is :"+self.optionVal.get())
In my opinion this should work like once I choose certain button, and it prints out "this option is *the value*", however now what it does is once compiled, it prints out everything, and the self.optionVal.get() is blankspace, as if value wasn't set to that variable.
I wonder what happens to my code,
Many thanks in advance.

AHA! I beleive I've figured it out. I had the exact same issue. make sure you are assigning a master to the IntVar like self.rbv=tk.IntVar(master) #or 'root' or whatever you are using):
import Tkinter as tk
import ttk
class My_GUI:
def __init__(self,master):
self.master=master
master.title("TestRadio")
self.rbv=tk.IntVar(master)#<--- HERE! notice I specify 'master'
self.rb1=tk.Radiobutton(master,text="Radio1",variable=self.rbv,value=0,indicatoron=False,command=self.onRadioChange)
self.rb1.pack(side='left')
self.rb2=tk.Radiobutton(master,text="Radio2",variable=self.rbv,value=1,indicatoron=False,command=self.onRadioChange)
self.rb2.pack(side='left')
self.rb3=tk.Radiobutton(master,text="Radio3",variable=self.rbv,value=2,indicatoron=False,command=self.onRadioChange)
self.rb3.pack(side='left')
def onRadioChange(self,event=None):
print self.rbv.get()
root=tk.Tk()
gui=My_GUI(root)
root.mainloop()
try running that, click the different buttons (they are radiobuttons but with indicatoron=False) and you will see it prints correctly changed values!

You're very close. Just take out the .get() from self.optionVal.get(). The Radiobutton constructor is expecting a traced variable, you're giving it the result of evaluating that variable instead.

You need to:
Remove the .get() from the variable=self.optionVal argument in the constructor the button. You want to pass the variable, not the evaluated value of the variable; and
Remove the parenthesis from command=self.selected() and use command=self.selected instead. The parenthesis says "call this function now and use the return value as the callback". Instead, you want to use the function itself as the callback. To better understand this, you need to study closures: a function can return a function (and, if that was the case, that would be used as your callback).
EDIT: A quick reminder, also: Python is not compiled, but interpreted. Your callback is being called while the script is being interpreted.

def view(interface):
choice = interface.v.get()
if choice == 0:
output = "0"
elif choice == 1:
output = "1"
elif choice == 2:
output = "2"
elif choice == 3:
output = "3"
else:
output = "Invalid selection"
return tk.messagebox.showinfo('PythonGuides', f'You Selected {output}.')
class Start:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('500x500')
self.root.resizable(False, False)
self.root.title('find out the degree of severity')
self.v = tk.IntVar()
dolori_ossa = {"nessun dolore": 0,
"dolori articolari": 1,
"frattura composta": 2,
"frattura scomposta": 3}
for (txt, val) in dolori_ossa.items():
tk.Radiobutton(self.root,
text=txt,
variable=self.v,
value=val,
command=lambda:view(self)
).pack()

Related

Change text of a specific tkinter Label using function with arguments

I'm trying to reference a specific tkinter Label in a function based on an argument input. I've tried many things, and found some topics on exec and eval and variable variables, but I want to steer away from bad practices (I don't know how to achieve it through those methods anyway). I feel like I'm missing something extremely basic, but I can't wrap my head around it.
Below is a simplified code of my function:
def myFunction(input_num):
while ArbitraryVariableName == False:
# Do stuff in while loop
if input_num== "1":
self.lbl1["text"] = "New Value 1"
elif input_num == "2":
self.lbl2["text"] = "New Value 2"
elif input_num== "3":
self.lbl3["text"] = "New Value 3"
elif input_num== "4":
self.lbl4["text"] = "New Value 4"
elif input_num== "5":
self.lbl5["text"] = "New Value 5"
# And so forth for 20+ more elif statements
You will notice that the input_num directly relates to the specific tkinter Label name of "lbl + input_num". If it helps, below is the code for one of two of the labels (they all follow a similar pattern):
self.lbl1 = Label(topframe, text="Old Value Test 1")
self.lbl1 .grid(column=1, row=1)
self.lbl2 = Label(topframe, text="Old Value Test 2")
self.lbl2 .grid(column=1, row=2)
# And so forth
Is there a cleaner and less-repetitive way to do this?
You say that you don't want to have to use the eval function, so you could instead use a label list, which makes your code rather a lot shorter:
import tkinter as tk
class example:
def __init__(self, master):
self.master = master
self.lbl1 = tk.Label(self.master, text="Old Value Test 1")
self.lbl1.grid(column=0, row=0)
self.lbl2 = tk.Label(self.master, text="Old Value Test 2")
self.lbl2.grid(column=0, row=1)
self.lbls = [self.lbl1, self.lbl2]
self.myfunction(1)
self.myfunction(2)
def myfunction(self, input_num):
self.lbls[input_num - 1]["text"] = f"New Value {input_num}"
def main():
root = tk.Tk()
example_win = example(root)
root.mainloop()
if __name__ == '__main__':
main()
With this code I did assume you had an integer from the input_num variable, instead of the string you showed in your example.
If you aren't using Python 3 you can't take advantage of the f-string.
Hope this helps,
James

How does stringvar work with textvariable?

I am writing a chess program and I can't get the pieces to output since I changed the text from being defined with text to text variable and now I can't get string working to output the pieces.
I define the buttons in a for loop and it outputs nothing in the squares. The code is
def drawboard(self):
x=0
y=0
for column in range(self.n):
self.changecolours()
x=x+1
y=0
for row in range(self.n):
y=y+1
colour = self.colours[self.colourindex]
pos=(x,9-y)
buttons=(tk.Button(self.boardframe, padx=10, textvariable=lambda position=pos: self.placepieces(position), borderwidth=0, bg=colour, relief="solid", font=self.piecefont, command=lambda position=pos: self.movepiece(position) ))
buttons.grid(column=(x-1), row=(y-1), sticky="W"+"E"+"N"+"S" )
self.changecolours()
#classmethod
def placepieces(cls, position):
black=Black()
white=White()
squareposition=position
icon=tk.Stringvar("")
if squareposition in white.position.values():
for key in white.position:
value=white.position.get(key)
if value==squareposition:
if key.endswith("pawn"):
icon.set(white.pawntype[key])
elif key=="king":
icon.set(white.PIECES.get("KING"))
elif key=="queen":
icon.set(white.PIECES.get("QUEEN"))
elif key.endswith("bishop"):
icon.set(white.PIECES.get("BISHOP"))
elif key.endswith("knight"):
icon.set(white.PIECES.get("KNIGHT"))
else:
icon.set(white.PIECES.get("ROOK"))
else:
pass
elif squareposition in black.position.values():
for key in black.position:
value=black.position.get(key)
if value==squareposition:
if key.endswith("pawn"):
icon.set(black.pawntype.get(key))
elif key=="king":
icon.set(black.PIECES.get("KING"))
elif key=="queen":
icon.set(black.PIECES.get("QUEEN"))
elif key.endswith("bishop"):
icon.set(black.PIECES.get("BISHOP"))
elif key.endswith("knight"):
icon.set(black.PIECES.get("KNIGHT"))
else:
icon.set(black.PIECES.get("ROOK"))
break
else:
pass
else:
icon.set("")
return icon
How does stringvar work with textvariable?
In the case of a Button, you can configure the text to be displayed in one of two ways: with a hard-coded string (eg: text='click me') or with the textvariable attribute.
The textvariable attribute must be set to an instance of one of the special tkinter variable objects StringVar, IntVar, DoubleVar or BooleanVar (eg: var=tk.StringVar(); Button(..., textvariable=var)). When configured with an instance of one of these variables, the text on the button will display whatever the value of the variable is.
Internally, when you specify a textvariable, tkinter will take the string representation of that object and create a tcl variable in the embedded interpreter. So, while it may see to accept a standard variable, command, or even a lambda, it ultimately ends up creating an internal tcl variable with that name, and associates that internal variable with the underlying tcl widget. If you do not use one of the special variables, it is going to be difficult for you to get or set the value of that variable.
For example, consider this set of commands:
var = tk.StringVar(value="hello")
tk.Button(root, textvariable=var)
When that code is run, the text that appears on the button will be hello. If you change the variable at any time (eg: var.set("goodbye")), the button will automatically be changed to show the new value.

Python Tkinter entry not loading content correct

i am facing a problem. I'm runnig this code.
import tkinter as tk
root = tk.Tk()
def check():
if len(e.get().split("a")) > 1:
print("contains a")
e = tk.Entry(frame1)
e.grid(row=4,column=1,columnspan=2,padx = (10,10), pady=(5,10), sticky="w e")
e.bind("<Key>",check)
when i type "a" to the entry I wont get nothing printed. I'll get the result by tiping a second character. I think that it happens because the function gets executed before the content has actualy changed. I tried to add a timer on the beginning of the function but it does nothing.
I want get the result by entering the first "a". What should I do?
I think that it happens because the function gets executed before the content has actualy changed.
You're right. If you want the callback to be able to see the character you just typed, you should create a StringVar and bind to that instead of binding to a "<Key>" event on the widget.
import tkinter as tk
frame1 = tk.Tk()
def check(*args):
if "a" in s.get():
print("contains a")
s = tk.StringVar()
e = tk.Entry(frame1, textvariable=s)
s.trace("w", check)
e.grid(row=4,column=1,columnspan=2,padx = (10,10), pady=(5,10), sticky="w e")
frame1.mainloop()

capturing tkinter checkbox input

I am running a script with tkinter that captures user input and then opens a second and possibly a third window based on the input. The issue I am having is capturing user input from the third and final window. Each window is divided up into it's own python class on execution.
Here is the code that calls the third window, which executes properly:
test_assign = TestAssign(mylist)
Here is the third window code:
class TestAssign:
def __init__(self, mylist):
self.mylist = mylist
self.selected_values = []
self.master = Tk()
for i in range(len(mylist)):
setattr(self, 'item'+mylist[i], IntVar())
ch = Checkbutton(master, text='item'+mylist[i], variable=getattr(self, 'item'+mylist[i])
ch.pack()
b = Button(master, text='Next', command=self.get_selected_values)
b.pack()
mainloop()
def get_selected_values(self):
for i in range(len(self.mylist)):
if getattr(self, 'item'+self.mylist[i]) == 1:
self.selected_values.append(self.mylist[i])
self.master.destroy()
Control then returns to the call point (at least I believe it does). Where I attempt to print the selected values:
test_assign = TestAssign(mylist)
while not test_assign.selected_values:
pass
print test_assign.selected_values
Everytime execution gets to the print statement it prints an empty list whether there are boxes checked or not. If I call dir(test_assign) for testing purposes, the checkbox attrs are there. Not sure why I am not able to capture it like this.
Can anyone see the flaw in my code?
Two things:
1)
ch = Checkbutton(master, text='item'+mylist[i], variable=getattr(self, 'item'+mylist[i])
and
b = Button(master, text='Next', command=self.get_selected_values)
I think master should be self.master (but honestly, that almost certainly just a copy/pasting error.)
2) The important one:
if getattr(self, 'item'+self.mylist[i]) == 1:
should be
if getattr(self, 'item'+self.mylist[i]).get() == 1:
(you need to call get on your IntVars to read the value.)

Combined Event Handling of widgets in TKinter

I am making a GUI Program in Tkinter and am running into problems.What I want to do is draw 2 checkboxes and a button. According to the user input next steps should take place. A part of my code has been shown below :-
CheckVar1 = IntVar()
CheckVar2 = IntVar()
self.C1 = Checkbutton(root, text = "C Classifier", variable = CheckVar1, onvalue = 1, offvalue = 0, height=5,width = 20).grid(row=4)
self.C2 = Checkbutton(root, text = "GClassifier", variable = CheckVar2, onvalue = 1, offvalue = 0, height=5, width = 20).grid(row=5)
self.proceed1 = Button(root,text = "\n Proceed",command = self.proceed(CheckVar1.get(),CheckVar2.get())).grid(row=6)
# where proceed prints the combined values of 2 checkboxes
The error that I am getting is typical ie a default value of both the selected checkboxes gets printed up and then there is no further input. The error that I get is NullType Object is not callable.
I searched on the net and I think the answer is related to lambda events or curry.
Please help ..
You're passing the value of self.proceed(CheckVar1.get(),CheckVar2.get()) to the Button constructor, but presumably what you want is for command to be set to a function which will call self.proceed(CheckVar1.get(),CheckVar2.get()) and return a new, possibly different value every time the button is pressed. You can fix that with a lambda, or by wrapping the call in a short callback function. For example, replace the last line with:
def callback():
return self.proceed(CheckVar1.get(), CheckVar2.get())
self.proceed1 = Button(root, text="\n Proceed", command=callback).grid(row=6)
This is pretty typical Tkinter. Remember: when you see a variable called command in Tkinter, it's looking for a function, not a value.
EDIT: to be clear: you're getting 'NullType Object is not callable' because you've set command to equal the return value of a single call to self.proceed (that's the NullType Object). self.proceed is a function, but its return value is not. What you need is to set command to be a function which calls self.proceed.
Like Peter Milley said, the command option needs a reference to a function (ie: give it a function name (ie: no parenthesis). Don't try to "inline" something, create a special function. Your code will be easier to understand and to maintain.

Categories

Resources