Dynamic Addition of Option Menu tKinter Python - python

I'm quite new to python. I have a requirement where I have to read a data file and based on the number of records inside the file, I have to create the same number of option menus related to that data. But option menu's options can be fetched from simple list. Please find the code below.
import tkinter as tk
from tkinter import *
root=tk.Tk()
root.title("GridAssign")
Grids=('Grid1','Grid2','Grid3','Grid4','Grid5')
file=open(Datafilepath,"r")
ing=file.read().splitlines()
print (len(ing))
variable = StringVar(root)
variable.set(Grids[0])
for i in range(len(ing)):
label = tk.Label(root,text=ing[i])
label.grid(row=i,pady=3,sticky=W)
w=OptionMenu (root, variable, *tuple(Grids)))
w.grid(row=i,column=2,pady=3,sticky=E)
root.mainloop()
The above code is able to give me n number of option menus but if I choose one value in one option menu other option menu's value also changes. Can someone please let me know how to achieve this.
Thanks,
Santty.

This is happening because each of your OptionMenu are using the same StringVar. So naturally when one OptionMenu makes a change to that StringVar, the other menus also reflect that change.
To prevent this you can use a separate StringVar for each menu:
import tkinter as tk
from tkinter import *
root=tk.Tk()
root.title("GridAssign")
Grids=('Grid1','Grid2','Grid3','Grid4','Grid5')
file=open(Datafilepath,"r")
ing=file.read().splitlines()
print (len(ing))
variable_dict = {}
for i in range(len(ing)):
variable = StringVar(root)
variable.set(Grids[0])
variable_dict[i] = variable
label = tk.Label(root,text=ing[i])
label.grid(row=i,pady=3,sticky=W)
w=OptionMenu (root, variable, *tuple(Grids)))
w.grid(row=i,column=2,pady=3,sticky=E)
root.mainloop()
You can then access each of the StringVars through the dictionary variable_dict

Related

Unable to update Label text in Python Tkinter without calling pack() again

from tkinter import *
from tkinter.ttk import *
root = Tk()
first_run = True
def update(txt):
global first_run
text1 = Label(root, text='')
if first_run:
text1.pack()
text1['text'] = txt
first_run = False
update('1')
update('2')
update('3')
root.mainloop()
When I run this, the text stays at '1', and the following 2 function calls are ignored. I find out that only if I use pack() again then it will be updated, but it creates a duplicate label and I do not want that.
Of course, I know that I am supposed to use a StringVar, but I have been using this method for all other widgets (buttons, label frames etc) and all of them works. I do not know why this particular case does not work.
Running on Python 3.9.9 on Windows 11
You aren't updating the label, you are creating a new label each time the function is called. To update any widget, use the configure method. For that, you need to create the label outside of the function (or, leave it in the function but add logic so that it's only created once). Usually it's best to create it outside the function so that the function is only responsible for the update.
from tkinter import *
from tkinter.ttk import *
root = Tk()
def update(txt):
text1.configure(text=txt)
text1 = Label(root, text='')
text1.pack()
update('1')
update('2')
update('3')
root.mainloop()
Note: since you call your function multiple times before the window is drawn you'll only see the final value. There are plenty of solutions to that on this site. Without knowing more about what your real program looks like it's hard to recommend the best solution to that problem.

Update on the fly a ttk.OptionMenu without affecting its previous callback/command

I am doing a large GUI with different ttk.OptionMenu widgets that need to be updated often depending on the interaction with the user. Each time the user selects another value from the menu, there is a function callback by the widget via the command input. The command works fine until I need to update the possible values within the OptionMenu widget. After updating using add_command, my previous callback does not work anymore.
Is there any way of updating the possible inputs of a ttk.OptionMenu without affecting its original callback? Let me put a dummy example to illustrate my problem. My original code would be like
from tkinter import *
from tkinter import filedialog, messagebox, ttk
def printing(variable,*args):
print('ok')
if variable:
print(variable)
root=Tk()
List=['Madrid', 'Paris', 'Brussels']
variable = StringVar()
optionmenu = ttk.OptionMenu(root,variable,'', *List,
command=printing)
optionmenu.pack()
root.mainloop()
Then the user would update the list dynamically, and the menu needs to be updated on the fly, using:
newList = ['Madrid', 'Paris', 'Brussels', 'London']
menu = optionmenu["menu"]
menu.delete(0, "end")
for string in newlist:
menu.add_command(label=string,
command=lambda value=string: variable.set(value))
but doing this operation, the callback printing would not work anymore. Also important to mention that one clicked in one option it should become the value showed by the OptionMenu ( so the StringVar variable is settled to that input)
I hope it is clear
There is an internal class _setit in tkinter module which is used by OptionMenu internally to populate the values. You can use this class as below:
from tkinter import filedialog, messagebox, ttk, _setit
...
for value in newList:
menu.add_command(label=value, command=_setit(variable, value, printing))

How do I get an attribute from a Combobox and put it into a variable?

I'm making a project in Tkinter Python and I want users to select an attribute from a Combobox widget and press a button and that attribute will be stored in a variable. I've searched all over the web, but I can't make heads or tails of the code and have no idea how to store this attribute. Can someone tell me how to do this
I've tried the .get thing... (module? widget?) but that is not working and as I said, the internet ain't no help.
This is my basic code with the window and the Combobox:
from tkinter import *
from tkinter import ttk
master = Tk()
ver = ttk.Combobox(master, state="readonly", values=["test1", "test2"]).pack()
Button(master, text="Run").pack()
master.mainloop()
I want to be able to store the selected item in the Combobox and put it in a variable.
pack returns None if you want to assign to a variable, you must do it on a separate line.
If you want action, Button requires a command key word arg to which you assign a callback.
After you have fixed the mistakes, you can use the get method on the Combobox:
import tkinter as tk
from tkinter import ttk
def print_selected():
print(combo.get())
master = tk.Tk()
combo = ttk.Combobox(master, state="readonly", values=["test1", "test2"])
combo.pack()
tk.Button(master, text="Run", command=print_selected).pack()
master.mainloop()

How can I get the selected value of a combobox (and store it in a variable)?

I've been wondering how can I get the current value of a combobox (not the current()) and preferably store it to my variable 'listvalue'. I've been searching for a while but never found anything that I wanted.
Here's the sample code:
FontList1['values'] = ("Courier","Courier New","Times New Roman","Comic Sans MS")
FontList1.set(TypeFace)
print(listvalue)
FontList1.pack(side="right")
Why not store the selected font in a tkinter StringVar?
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
selectedFontVar = tk.StringVar()
FontList1 = ttk.Combobox(root,textvariable=selectedFontVar,postcommand=displayFont)
FontList1['values'] = ("Courier","Courier New","Times New Roman","Comic Sans MS")
FontList1.pack()
SelectedFont = tk.Entry(root,textvariable=selectedFontVar)
SelectedFont.pack()
root.mainloop()
If you want to get the selected font, you can just call `selectedFontVar.get()' which will return whatever is selected in the combobox.
Advantage of a StringVar is that is is automatically updated when the combobox changes and this change can 'cascade' down to other widgets that also use the same stringvar. Like SelectedFont in my example.

Checkbutton in tkinter is not storing values into variables

I'm just doing my first steps in tkinter and I'm stuck trying to figure out why this code is not working:
from tkinter import *
from tkinter import ttk
root = Tk()
spam = StringVar()
checkbutton = ttk.Checkbutton(
root, text="SPAM?", variable=spam, onvalue="Yes, SPAM!", offvalue="Boo, SPAM!")
checkbutton.pack()
print(spam.get())
root.mainloop()
The variable spam is empty, no matter if my checkbutton is checked or unchecked. Looking at the examples and documentation was a dead end too. Why is my variable still empty?
Replace:
print(spam.get())
with:
checkbutton['command'] = lambda arg=spam: print(arg.get())
In order to see that the variable indeed does store the values.
The problem is when your print is called spam.get() equals "" as:
spam = StringVar()
is identical to:
spam = StringVar(value="")
The checkbutton is initially on a default neither-on, nor-off state(as spam is neither the off nor the on value), but it's hard to notice for the ttk version(if at all), replace:
checkbutton = ttk.Checkbutton(...
with:
checkbutton = Checkbutton(...
to use the default Checkbutton from tkinter, it is much more distinctively displayed.
Also further note that the Checkbutton requires being used in order to call spam.set(checkbutton['onvalue']) or spam.set(checkbutton['offvalue']).

Categories