Label text changing when dictionary is updated - python

I'm new to coding and i've been messing around with tkinter.
My labels have text, that is supposed to change when the dictionary values are updated.
An example of my code:
def setit(point, adic,number):
adic[point] = adic[point]+number
dict={'a':4,'b':8,'c':3}
aa=Label(root,text=dict['a']).pack()
bb=Label(root,text=dict['b']).pack()
cc=Label(root,text=dict['c']).pack()
Button(command=setit('a',dict,3)).pack()
When the button is pressed i want both the dictionary and the appropriate Label to update. How would you do that? Preferably without OOP. Thanks!

First of all, there are two problems in your code sample:
1) .pack() returns None, so when you do aa=Label(root,text=dict['a']).pack(), you store None in the variable aa, not the label. You should do:
aa = Label(root,text=dict['a'])
aa.pack()
2) The command option of a button takes a function as argument but you do command=setit('a',dict,3) so you execute the function at the button creation. To pass a function with arguments to a button command, you can use a lambda:
Button(command=lambda: setit('a',dict,3))
Then, to update the label when the value in the dictionary is changed, you can store your labels in a dictionary with the same keys and change the text of the appropriate label with label.configure(text='new value'):
import tkinter as tk
def setit(point, adic, label_dic, number):
adic[point] = adic[point] + number # change the value in the dictionary
label_dic[point].configure(text=adic[point]) # update the label
root = tk.Tk()
dic = {'a': 4, 'b': 8, 'c': 3}
# make a dictionary of labels with keys matching the ones of dic
labels = {key: tk.Label(root, text=dic[key]) for key in dic}
# display the labels
for label in labels.values():
label.pack()
tk.Button(command=lambda: setit('a', dic, labels, 3)).pack()
root.mainloop()

You can use a StringVar instead of specifying the text value. That looks like:
d={'a':StringVar(),'b':StringVar(),'c':StringVar()}
aa=Label(root,textvariable=d['a'])
bb=Label(root,textvariable=d['b'])
cc=Label(root,textvariable=d['c'])
aa.pack()
bb.pack()
cc.pack()
And then whenever you want to change the label, you can do
d['a'].set("new text!")
See here for more info on labels.
Note: dict is a reserved word in python, so it's best to not use that as the name of your variable. Same goes for str, int, etc.

Related

How to add multiple ttk.Entry values to a list or dictionary and use get method to retrieve values

I have a for loop that creates multiple rows and columns of labels and entries from a Treeview selection and sets the entries to current Treeview values.
import tkinter as tk
from tkinter import ttk
allitems = {}
keys = ['UID', 'Col5', ...]
entries = []
selections = trv.selection()
uid = ",".join([str(trv.item(i)['values'][0])
for i in selections])
col5 = ",".join([str(trv.item(i)['values'][5])
for i in selections])
for i in range(0, len(selections)):
l1 = ttk.Label(top, text="UID:")
l1.grid(row=i, column=0, sticky=tk.W)
uidentry = ttk.Entry(top)
uidentry.grid(row=i, column=1)
uidentry.insert(0, uid.split(",")[i])
l2 = ttk.Label(top, text="Col5:")
l2.grid(row=i, column=2, sticky=tk.W)
col5entry = ttk.Entry(top)
col5entry.grid(row=i, column=3)
col5entry.insert(0, col5.split(",")[i])
...
...
get_butt = tk.Button(top, text="Get All")
get_butt.grid(column=6)
There are 7 labels and 7 entry widgets created in this loop. I'm trying to get the values of the entries stored in a dictionary or list temporarily for me to use the get method to create an update function for a button. I've tried some examples I've seen from other posts like
entries.append(uidentry)
entries.append(col5entry)
and doing
for i, j in zip(keys, entries):
allitems.update({i: j})
and adding a function for a button like this
def get_all():
for keys, v in allitems.items():
items = keys, v.get()
print(items)
but it only prints the first set of Keys and entry values.
What I'm wanting to achieve is to have all the uidentry values attach to ['UID'] in order and col5entry values attach to ['Col5'] maybe something kinda like this
{'UID':['E001', 'E002', 'E003', .....]
'Col5':['Stuff1', 'Stuff2', 'Stuff3', .....]}
I'm new to python and really struggling with the logic of how to achieve this properly. Here is a Pastebin of my working code with Treeview set up so you can copy test/ see what I'm working with.
https://pastebin.com/n0DLQ5pY
EDIT: If you test the snippet of the app the event to trigger show_popup is hitting the ENTER key after making selections on Treeview.

How to get the value of radiobutton in Tkinter?

I'd like to get the value as text and not integer on my raddiobutton.
I have a frame, named "printers_frame" in which I created radio buttons with a list of printers on the computer of the user.
According to the printer choosen (radiobutton), I will print files on this specific printer.
I followed this tips but I want to do the same with String, not Integer.
Here is the code to create the radio button:
print_variable = StringVar()
for p in printers:
Radiobutton(printers_frame, text = p[2], variable = print_variable, value = p[2], wraplength=int(WIDTH/3)-10, justify="left", bg=BACKGROUND).pack(side = TOP, anchor = W)
Can you help?
Thanks a lot!
Can't you just take the integer value, and convert it with str()?
You can save that in a variable, and use it however you want.
Hopefully, this helps.
Edit:
Say the value of the RadioButton is RadioButton().
You can just do str(RadioButton).
Edit: You can use the StrVar() function in tkinter. You assign your Radio Button to that variable, and then you can use the value as a string.
Then pass the variable with the string when you are initializing your Radio Button. Pass it to a parameter called variable.
So, your radio button would be:
radio_variable = IntVar()
button = RadioButton(master, ..., variable = radio_variable)
Hopefully this helps!

How to dynamically create widgets without specific class instantiation in Tkinter?

I am trying to create dynamically a certain amount of widgets, and then be able to modify them.
For example, I need some Checkboxes :
# Class level lists to store the CheckButtons and their values
self.checkbutton_list = []
self.checkbutton_values_list = []
# With self.amount_of_widgets an integer
for i in range(0, self.amount_of_widgets):
# We create the value of the current CheckButton, default is 0
self.checkbutton_values_list.append(IntVar())
# We create the CheckButton and append it to our list
self.checkbutton_list.append(Checkbutton(self.canvasR,
text="rtest : " + str(i),
variable=self.checkbutton_values_list[i],
onvalue=1,
offvalue=0,
height=1,
width=10))
# As there is a lot of CheckButtons, they have to be browsable inside the canvas
# named canvasR, which has a scrollbar. To browse the created CheckButtons in the
# canva, we need to use the create_window function :
self.canvasR.create_window(x, y, window=self.comp_checkbutton_list[i])
y = y + 100
This generation works well, and I am able, to create all the desired widgets at their desired positions, and have them stored into the dedicated lists. For example I do something similar to create blank images ( I want to update those images later ) :
for i in range(0, self.amount_of_widgets):
# With default photo a PhotoImage object stored at class level
self.photo_list.append(self.default_photo)
self.photo_area_list.append(self.canvasR.create_image(x, y,
image=self.photo_list[i],
anchor=NW))
y = y + 100
The issue is I fail to update the created widgets, if I try to call .itemconfig() like in the following code, I am getting a _tkinter.TclError: invalid boolean operator in tag search expression :
for i in range(0, self.max_image_displayed):
self.canvasR.itemconfig(self.checkbutton_list[i], fill='black', text='')
I understand that it may not work because each widget does not specifically exist for the main class, because they have not been explicitly created inside the class. Only the list storing them does exist in this scope.
But I am not going to declare thousands of CheckBoxes or Images fields, one by one, by hand in my code like :
self.area1 = self.canvasR.create_image(0, 0, image=self.photoimage1, anchor=NW)
self.area_list.append(self.area1)
self.area2 = self.canvasR.create_image(0, 100, image=self.photoimage2, anchor=NW)
self.area_list.append(self.area2)
# ...
self.area9999 = self.canvasR.create_image(0, 0, image=self.photoimage999, anchor=NW)
self.area_list.append(self.area9999)
What could I do?
The issue is I fail to update the created widgets, if I try to call .itemconfig() like in the following code, i am getting a _tkinter.TclError: invalid boolean operator in tag search expression
When you call self.canvasR.itemconfig, the first argument needs to be identifier of an individual item on the canvas, or a tag. However, you're passing in self.defaultPhoto which is definitely not an item identifier or a tag.
In other words, what you pass to itemconfig should be the same as what is returned by self.canvasR.create_image(...) rather than the image itself, if your goal is to modify the canvas item created by create_image.

How to make each radiobutton unique from the others in tkinter

I have a window in Tkinter that looks like this:
When i click on a button in the first row, it stays. However, when i click on a button in the second row, it unselects the one i chose above.
I want it to be able to only select one option per row. Is there something I'm missing? When it's done, I want to be able to iterate over the rows and get the value of the boxes, but I'm not sure how to do that either.
The code for that section is:
for i in studentList:
Label(left,text=i[0][::]+' ' + i[1][::],fg='black',bg='#dbdbdb',font=('Arial',11,'bold')).grid(row=counter,column=0,pady=13,sticky='news')
P = Radiobutton(right,text='Present',bg='#56ab32',fg='black',value='P'+str(counter),indicatoron = 0,font=('Arial',12,'bold'))
P.grid(row=counter,column=0,pady=10,padx=20,sticky='news')
L = Radiobutton(right,text='Leave',bg='#e6a800',fg='white',indicatoron = 0,value='L'+str(counter),font=('Arial',12,'bold'))
L.grid(row=counter,column=1,pady=10,padx=20,sticky='news')
Radiobutton(right,text='Absent',bg='#bd2900',fg='white',indicatoron = 0,value='A'+str(counter),font=('Arial',12,'bold')).grid(row=counter,column=2,pady=10,padx=20,sticky='news')
counter+=1
Radiobuttons work by assigning two or more radiobuttons the same instance of one of tkinter's special variable objects -- usuallyStringVar or IntVar. This sharing of a variable is what makes a group of radiobuttons work as a set, since the variable can only hold a single value.
Because you aren't assigning a variable, tkinter is using a default variable which is the same for every button. Thus, all buttons are acting as a single set.
To make your code work, each row needs to use it's own instance of StringVar. It would look something like this:
vars = []
for i in studentList:
var = StringVar()
vars.append(var)
...
Radiobutton(right, variable=var, ...)
Radiobutton(right, variable=var, ...)
Radiobutton(right, variable=var, ...)
...
With the above, you can get the choice of each row by getting the value of the variable for that row. For example, the first row would be vars[0].get(), the second row would be vars[1].get() and so on.

Set OptionMenu by index

I'm trying to set the value in an OptionMenu by the index of the options, and not use the actual option value itself.
For example, if my OptionMenu has options ["one", "two", "three"], I want to be able to set it to "one" by writing My_Option_Menu.set(options[0]), not My_Option_Menu.set("one")
The OptionMenu is dynamically populated by a list depending on what two other OptionMenus are set to, which is why I want to refer to the options by index and not actual value. Does the OptionMenu object have a way to return the list of options that are currently populated so that my options[0] method above will work?
The simplest way to do this is to keep a copy of the list used to define the optionmenu. Then you can use the index to get the value from the list and assign it to the associated variable.
For example:
options = ["one","two","three"]
...
self.menuVar = tk.StringVar(master)
self.optionMenu = tk.OptionMenu(master, self.menuVar, *options)
...
self.menuVar.set(options[0])
Another option is to get the menu object associate with the widget, and use menu commands to get the text at the given index, and use that to set the variable:
value = self.optionMenu["menu"].entrycget(0, "label")
self.menuVar.set(value)

Categories

Resources