Tkinter Spinbox textvariable argument has no effect. Is there something I missed? - python

I've defined a class with a 'bpm' attribute:
class Section:
def __init__(self, id, bpm, bars, reps, num_tracks):
self.id = id
self.bpm = bpm
self.bars = bars
self.reps = reps
self.num_tracks = num_tracks
then I call the attribute to use it as the textvariable argument on a spinbox, once I've created an instance of my Section class, inside a dictionary:
def add_section():
new_id = next(itertools.count(1))
sections[new_id] = Section(new_id, 120, 1, 2, 1)
print((str(sections[new_id].bpm)))
sections[new_id].label_section_title = Label(root, text="Section {}".format(sections[new_id].id, relief = GROOVE))
sections[new_id].label_section_title.grid(row = 1, column = 4, columnspan = 5)
sections[new_id].label_bpm = Label(root, text="BPM: ")
sections[new_id].label_bpm.grid(row = 2, column = 4)
sections[new_id].bpm_control = Spinbox(root, from_ = 1, to = 999, textvariable = sections[new_id].bpm, command = lambda: sections[new_id].bpm_change(sections[new_id].bpm_control.get()))
sections[new_id].bpm_control.grid(row = 2, column = 5)
I'm able to print the value of sections[new_id].bpm as 120, so I know that works.
But even though I am setting textvariable on the spinbox, I'm just getting a value of 1 on the spinbox when I'd like it to be the 120 from the new instance. Even if I just set textvariable to straight up 120 I still just get a 1 there.

You need to set it as a IntVar() to use
self.bpm = IntVar()
self.bpm.set(bpm) # set value passed in
When getting the value from your spinbox you get either use Spinbox.get() which will return a string of the current value or self.bpm.get() which will be an int value

Related

Make an Entry When a Checkbox is Unchecked in Tkinter

I have a check button that is checked by default. If the user unchecks it, a label and an entry should appear. I tried to do so by using the key binding method; however, it has a drawback which is that if the user checks the checkbox again, the new label and entry won't disappear. How do I solve that problem?
checkButtonVar = IntVar(value = 1)
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar)
labelIsChanceDefault = Label(root, text="Make chance = 0.9?")
labelIsChanceDefault.grid(row=3, column = 0, sticky = 'w')
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
def checkCheckButton(event):
labelChance = Label(root, text = "Enter chance of winning")
labelChance.grid( row = 3, column = 2)
global entryChance
entryChance = Entry(root, borderwidth = 3)
entryChance.grid(row = 3, column = 3)
checkButtonIsChnaceDefault.bind('<Button-1>', checkCheckButton)
Here's a screenshot of the program to make things clear.
You don't need to bind the Check-button. Use command option. And setting offvalue and onvalue can control the appearance.
See the tkinter.Checkbutton
checkButtonVar = IntVar()
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar,offvvalue=0,onvalue=1,command=checkCheckButton)
...
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
#==== Define the widgets here.
labelChance = Label(root, text = "Enter chance of winning")
entryChance = Entry(root, borderwidth = 3)
def checkCheckButton():
if checkButtonVar.get()==0:
labelChance.grid( row = 3, column = 2)
entryChance.grid(row = 3, column = 3)
else:
labelChance.grid_forget()
entryChance.grid_forget()

How to pass string var in callback function using trace() in tkinter

I am new with python and trying to create two entry widgets to evaluate the data as soon as the user typed in the entry box. How to pass the string var into a function callback so that it will return exactly which entry box has changed. Now the callback function just returns the first entry box (entry1).
Here is my code:
import tkinter
from tkinter import StringVar
main_wd = tkinter.Tk()
my_var1 = StringVar()
my_var2 = StringVar()
def my_callback(var):
print("Traced variables {}".format(var.get())
my_var1.trace('write', my_callback(my_var1))
my_var2.trace('write', my_callback(my_var2))
entry1 = tkinter.Entry(main_wd, textvariable = my_var1).pack(padx = 5, pady = 5)
entry2 = tkinter.Entry(main_wd, textvariable = my_var2).pack(padx = 5, pady = 5)
main_wd.mainloop()
To being in with, the usage of trace is wrong, meaning, the positional argument passed is wrong, it has to be 'w' instead of 'write'. Then next your calling the function when you use (), so you need to use lambda for that. So you trace would be like:
my_var1.trace('w', lambda *_,var=my_var1: my_callback(*_,var=var)) #*_ are the other arguments, like varname,value,mode ?
my_var2.trace('w', lambda *_,var=my_var2: my_callback(*_,var=var))
Then your function would be like:
def my_callback(*args,var):
print("Traced variables {}".format(var.get()))
TIP:
Its better for entry1 and entry2 to not be None, so say:
entry1 = tkinter.Entry(main_wd, textvariable = my_var1)
entry1.pack(padx = 5, pady = 5)
entry2 = tkinter.Entry(main_wd, textvariable = my_var2)
entry2.pack(padx = 5, pady = 5)
When saying pack() on same line as the declaration, it will return what the last method returns. In this case, pack() returns None. So to make those entry widgets reusable, pack() them on separate line. Same applies to grid() and place().
Final Code:
import tkinter
from tkinter import StringVar
main_wd = tkinter.Tk()
my_var1 = StringVar()
my_var2 = StringVar()
def my_callback(*args,var):
print("Traced variables {}".format(var.get()))
my_var1.trace('w', lambda *_,var=my_var1: my_callback(*_,var=var))
my_var2.trace('w', lambda *_,var=my_var2: my_callback(*_,var=var))
entry1 = tkinter.Entry(main_wd, textvariable = my_var1)
entry1.pack(padx = 5, pady = 5)
entry2 = tkinter.Entry(main_wd, textvariable = my_var2)
entry2.pack(padx = 5, pady = 5)
main_wd.mainloop()

Python Tkinter Number of Button changes based on selected RadioButton

EDIT: I tried to edit it based on one suggestion that it needs to be tied to a function. But still not working properly. Thank you very much!
Hope you can help me. Saw related questions but not exactly the same. Thank you very much!
I have a radiobutton. Based on the selected value, the number of buttons will change. However, the number of buttons dont change. The number just based on the default value of the radiobutton (i tried changing it).
import tkinter
from tkinter import *
root = Tk()
TIME_SUBFRAME = root
#dont mind much this part, this is just the popup window that will show after I click the buttons dependent on the radiobutton
def month():
CAL_WINDOW = Toplevel(TIME_SUBFRAME) #other parts removed
#this is the part that I would want to be dependent on the radiobutton
ONLY_MONTH = Button(TIME_SUBFRAME, text='Month', command=month)
START_MONTH = Button(TIME_SUBFRAME, text='Start Month', command=month)
END_MONTH = Button(TIME_SUBFRAME, text='End Month', command=month)
def sing_month():
START_MONTH.destroy()
END_MONTH.destroy()
ONLY_MONTH.grid(row = 3, column = 2, columnspan = 2)
def mult_month():
ONLY_MONTH.destroy()
START_MONTH.grid(row = 3, column = 2)
END_MONTH.grid(row = 3, column = 3)
#Radiobuttons for timepoint selection type
YRTYPE = IntVar(TIME_SUBFRAME, 1)
SING_MONTH = Radiobutton(TIME_SUBFRAME, text = "Single Month", command = sing_month, variable = YRTYPE, value = 1)
MULT_MONTH = Radiobutton(TIME_SUBFRAME, text = "Multiple Months", command = mult_month, variable = YRTYPE, value = 2)
SING_MONTH.grid(row = 2, column = 2, padx = 10, pady = 10)
MULT_MONTH.grid(row = 2, column = 3, padx = 10, pady = 10)
root.mainloop()
The radiobutton numbers needs to checked their value when a function is called.You have declared checking statement in the current running block, which will return initial value of your radiobuttons.
The values needs to be checked when user checks the radiobutton.So, we need an extra button widget commanded with a function that checks the value of both radiobuttons and performs the related actions.
The radiobutton will not check the values automatically, it needs to be checked by function.
Here's your Solution,
import tkinter
from tkinter import *
root = Tk()
TIME_SUBFRAME = root
#dont mind much this part, this is just the popup window that will show after I click the buttons dependent on the radiobutton
def month():
CAL_WINDOW = Toplevel(TIME_SUBFRAME) #other parts removed
#this is the part that I would want to be dependent on the radiobutton
ONLY_MONTH = Button(TIME_SUBFRAME, text='Month', command=month)
START_MONTH = Button(TIME_SUBFRAME, text='Start Month', command=month)
END_MONTH = Button(TIME_SUBFRAME, text='End Month', command=month)
def sing_month():
START_MONTH.grid_remove()
END_MONTH.grid_remove()
ONLY_MONTH.grid(row = 3, column = 2, columnspan = 2)
def mult_month():
ONLY_MONTH.grid_remove()
START_MONTH.grid(row = 3, column = 2)
END_MONTH.grid(row = 3, column = 3)
#Radiobuttons for timepoint selection type
YRTYPE = IntVar(TIME_SUBFRAME, 1)
SING_MONTH = Radiobutton(TIME_SUBFRAME, text = "Single Month", command = sing_month, variable = YRTYPE, value = 1)
MULT_MONTH = Radiobutton(TIME_SUBFRAME, text = "Multiple Months", command = mult_month, variable = YRTYPE, value = 2)
SING_MONTH.grid(row = 2, column = 2, padx = 10, pady = 10)
MULT_MONTH.grid(row = 2, column = 3, padx = 10, pady = 10)
root.mainloop()

How to save an entry in Tkinter to later use in a calculation, then print the answer inside the Tkinter window

I am trying to make a program which calculates 3-4 values using some user inputted values
I have tried making a function which saves the entries into variables, and making the variables global but that didn't work
from tkinter import *
from math import *
root = Tk()
label1 = Label(root, text = "Enter value for length ")
label1.grid(columnspan = 2, sticky = "W")
length = Entry(root)
length.grid(row = 0, column = 2)
label2 = Label(root, text = "Enter value for volume ")
label2.grid(columnspan = 2, sticky = "W")
volume = Entry(root)
volume.grid(row = 1, column = 2)
label3 = Label(root, text = "Enter value for the thickness of the cylinder ")
label3.grid(columnspan = 2, sticky = "W")
thickness = Entry(root)
thickness.grid(row = 2, column = 2)
label4 = Label(root, text = "Enter value for starting temperature ")
label4.grid(columnspan = 2, sticky = "W")
st_T = Entry(root)
st_T.grid(row = 3, column = 2)
label5 = Label(root, text = "Enter value for finishing temperature ")
label5.grid(columnspan = 2, sticky = "W")
end_T = Entry(root)
end_T.grid(row = 4, column = 2)
def save():
v = volume.get()
l = length.get()
w = thickness.get()
t0 = st_T.get()
t1 = end_T.get()
global values
values = [v, l, w, t1, t0]
Button(root, text = "Submit", command = save).grid(row = 6, column = 0)
root.mainloop()
I know the current code isn't very pretty and is very inefficient but the error keeps saying that v is not defined
You might consider declaring a variable, or a an instance of a context object (that you will define) at global scope to store your user inputs.
Then you will be able to read the user inputs later in another function.
Do not forget to use the keyword 'global' before modifying the global object in a different scope (like in a function). Have a look here : https://www.geeksforgeeks.org/global-keyword-in-python/
By example you could declare your global object/variable/whatever you need, along with your root Tkinter object.

Saving variables from entry widgets

I want to have the text input of this entry box save to a list and then be printed. I cannot have it save the input upon the button press and it just prints the placeholder variable.
names = []
from tkinter import*
class Trip:
def __init__(self, parent):
E_name = "q"
self.En_name = "g"
self.En_name = str(self.En_name)
self.go = Frame(parent, width = 500, height = 450, bg = "snow", pady = 30, padx = 10)
self.go.grid(row = 1, column = 0)
self.go.grid_propagate(0) # to reserve space required for frame
self.tet = Frame(parent, width = 500, height = 450, bg = "snow")
name = Label(self.go, text = "Name:", bg = "snow")
name.grid(row = 1, column = 0, sticky = E)
self.E_name = Entry(self.go, width = 40, textvariable = self.En_name)
self.E_name.grid(row = 1, column = 1, sticky = W, pady = 4)
menuButton = Button(self.go, text = "Continue", command = self.breakeverything)
menuButton.grid(row = 8, column = 1, pady = 4)
def breakeverything(self):
names.append(self.En_name)
print (names[0])
self.E_name.delete(0, "end")
#main routine
if __name__ == "__main__":
root = Tk()
root.title("Traveller Details")
play = Trip(root)
root.geometry("500x450+0+0")
root.mainloop()
A textvariable is supposed to be a tkinter.StringVar(), not a primitive string. Your application looks simple enough that it shouldn't even need it. Take out self.En_name, take out the textvariable, and just retrieve the current value of the Entry widget in breakeverything() (which should no longer be an appropriate name):
def breakeverything(self):
names.append(self.E_name.get())
print(names[-1]) # printing the last name in the list seems more useful
self.E_name.delete(0, "end")
I would also recommend moving names into Trip.__init__ and making it an instance variable like everything else, with self.names = []. It'll make it easier to keep track of scopes.
You're using textvariable incorrectly (you must use one of the special Tkinter variables such as StringVar), but you don't need to use it at all. Simply save a reference to the widget, then call the get method when you want the value:
self.E_name = Entry(self.go, width = 40)
...
print("you entered: " + self.E_name.get())
If you insist o using textvariable, use a StringVar and then call the get method on that instead:
self.En_name = StringVar()
self.E_name = Entry(..., textvariable=self.En_name)
...
print("you entered: " + self.En_name.get())

Categories