英文:
How to pass values from a linked menu item in python tkinter?
问题
To create a variable to hold and pass the label of the item selected from a drop-down menu in tkinter, you can use the following code:
import tkinter as tk
def selection_changed(event):
selected_label = selection.get()
print(f"Selected label: {selected_label}")
root = tk.Tk()
root.geometry("200x170")
selection = tk.StringVar(root)
selection.set("Select an item") # Set an initial value
options = ["Option 1", "Option 2", "Option 3"]
option_menu = tk.OptionMenu(root, selection, *options)
option_menu.pack()
selection.trace("w", selection_changed)
root.mainloop()
As for sending a second variable into a function in tkinter at the same time, you can modify the selection_changed
function to accept both the selected label and your spare variable:
def selection_changed(event):
selected_label = selection.get()
spare_variable = "Your spare variable here" # Replace with your actual spare variable
print(f"Selected label: {selected_label}")
print(f"Spare variable: {spare_variable}")
Then, when you call the selection_changed
function, you can pass your spare variable along with the selected label.
英文:
How to create a variable to hold and pass label of the item selected from a drop down menu? While I'm here, may I ask how to send a second (spare) variable into a function in tkinter at the same time. I'm not using classes or "OptionMenu".
Here's what I have...
## In a tkinter I have this...
import tkinter as tk
from tkinter import Toplevel, Button, Tk, Menu, Frame
root = Tk()
xr, yr = 200, 170
rg = str(xr) + "x" + str(yr) # concatinating
root.geometry(rg)
selection = tk.StringVar(root)
print(f"Before option menu selected, selection.get() = {selection.get()}")
def confirm_stage(*args):
global selection
print(f"selection.get(): {selection.get()}")
print(f"selection: {selection}") # Gives PY_VAR0, How to 'decode' PY_VAR0 ?
# print(f"*selection: {*selection}") # gives and error. Cant use '*' in f-strings
print(f"selection[0]: {selection[0]}") # gives and error: 'StringVar' object is not subscriptable
menubar = Menu(root)
stage_menu_item = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Stage", menu=stage_menu_item) # Shows the caption
stage_menu_item.add_command(label="1", command = confirm_stage)
stage_menu_item.add_command(label="2", command = confirm_stage)
root.config(menu=menubar)
root.mainloop()
The "confirm_stage" appears to offer no argument to the called function. It surely can't be that each single item selected has to point to a new separate and unique function specifically written for each item in the menu, although it would work, the code would be unwieldy.
I've seen references to StringVar() which I don't fully understand, and tried to apply it but no joy, and then how would one pass a useful second accompanying variable?
UPDATE 2: - Stripped down code. I need to get the label of the menu item clicked on.
import tkinter as tk
from tkinter import Toplevel, Button, Tk, Menu, Frame
root = Tk()
root.geometry("200x170")
def donation_fn(selection):
a= clicked_r.get()
print(f"a= {a}")
print(f"selection= {selection}")
b= clicked_m.get()
print(f"b= {b}")
print(f"selection= {selection}")
menubar = Menu(root)
clicked_r = tk.StringVar(root)
clicked_m = tk.StringVar(menubar)
list=['1 donation', '2 donations', '3 donations']
donation = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Donations", menu=donation) # Shows the caption
for _ in list: donation.add_command(label=_, command = lambda: donation_fn(clicked_m.get()))
# port_item.add_command(label=list, command = lambda: None)
root.config(menu=menubar)
root.mainloop()
答案1
得分: 1
如果你只想将菜单文本传递给回调函数,并且不希望在每次调用`.add_command()`时都这样做,那么你可以创建一个继承自`tk.Menu`的自定义类,并且重写类方法`add_command()`。在重写的`add_command()`方法内部,当执行时,你可以将菜单文本传递给指定的回调函数。
```python
import tkinter as tk
class MyMenu(tk.Menu):
def add_command(self, **kwargs):
callback = kwargs.pop('command', None)
text = kwargs.get('label')
# 将菜单文本传递给指定的回调函数
super().add_command(**kwargs, command=(lambda: callback(text)) if callback else None)
root = tk.Tk()
xr, yr = 200, 170
root.geometry(f"{xr}x{yr}")
def confirm_stage(menu_text):
print(menu_text)
menubar = tk.Menu(root)
# 使用MyMenu而不是tk.Menu
stage_menu_item = MyMenu(menubar, tearoff=0)
menubar.add_cascade(label="Stage", menu=stage_menu_item)
stage_menu_item.add_command(label="1", command=confirm_stage)
stage_menu_item.add_command(label="2", command=confirm_stage)
root.config(menu=menubar)
root.mainloop()
英文:
If you just want to pass the menu text to the callback and don't want to do it in every call of .add_command()
, then you can create a custom class inheriting from tk.Menu
and override the class method add_command()
. Inside the override add_command()
, you can pass the menu text to the given callback when it is being executed.
import tkinter as tk
class MyMenu(tk.Menu):
def add_command(self, **kwargs):
callback = kwargs.pop('command', None)
text = kwargs.get('label')
# pass the menu text to the given callback
super().add_command(**kwargs, command=(lambda: callback(text)) if callback else None)
root = tk.Tk()
xr, yr = 200, 170
root.geometry(f"{xr}x{yr}")
def confirm_stage(menu_text):
print(menu_text)
menubar = tk.Menu(root)
# Use MyMenu instead of tk.Menu
stage_menu_item = MyMenu(menubar, tearoff=0)
menubar.add_cascade(label="Stage", menu=stage_menu_item)
stage_menu_item.add_command(label="1", command=confirm_stage)
stage_menu_item.add_command(label="2", command=confirm_stage)
root.config(menu=menubar)
root.mainloop()
答案2
得分: 0
这是您想要的吗?
import tkinter as tk
from tkinter import Toplevel, Button, Tk, Menu, Frame
root = Tk()
xr, yr = 200, 170
rg = str(xr) + "x" + str(yr) # 连接字符串
root.geometry(rg)
def confirm_stage(var):
print(var)
menubar = Menu(root)
stage_menu_item = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Stage", menu=stage_menu_item)
stage_menu_item.add_command(label="1", command=lambda: confirm_stage(1))
stage_menu_item.add_command(label="2", command=lambda: confirm_stage(2))
root.config(menu=menubar)
root.mainloop()
如果需要进一步的帮助,请告诉我。
英文:
Is this what you want?
import tkinter as tk
from tkinter import Toplevel, Button, Tk, Menu, Frame
root = Tk()
xr, yr = 200, 170
rg = str(xr) + "x" + str(yr) # concatinating
root.geometry(rg)
# selection = tk.StringVar()
# print(f"Before option menu selected, selection.get() = {selection.get()}")
# def confirm_stage(*args):
# global selection
# print(f"selection.get(): {selection.get()}")
# print(f"selection: {selection}") # Gives PY_VAR0, How to 'decode' PY_VAR0 ?
# # print(f"*selection: {*selection}") # gives and error. Cant use '*' in f-strings
# print(f"selection[0]: {selection[0]}") # gives and error: 'StringVar' object is not subscriptable
def confirm_stage(var):
print(var)
menubar = Menu(root)
stage_menu_item = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Stage", menu=stage_menu_item) # Shows the caption
# stage_menu_item.add_command(label="1", command = confirm_stage)
# stage_menu_item.add_command(label="2", command = confirm_stage)
stage_menu_item.add_command(label="1", command = lambda: confirm_stage(1))
stage_menu_item.add_command(label="2", command = lambda: confirm_stage(2))
root.config(menu=menubar)
root.mainloop()
答案3
得分: 0
以下是翻译好的部分:
上面提到的“lambda”解决方案,
...
stage_menu_item.add_command(label="1", command = lambda: confirm_stage(1))
...
似乎适用于静态参数,但如果您尝试在循环中使用它,例如:
...
for _x in range(5):
stage_menu_item.add_command(label='Menu'+str(_x), command=lambda: confirm_stage(str(_x)))
...
它不起作用。“_x”始终为“4”,无论您调用哪个菜单项。不知道为什么。
对我而言唯一有效的方法是:
def _set(x:str):
return lambda: confirm_stage(x)
...
for _x in range(5):
stage_menu_item.add_command(label=str(_x), command=_set(str(_x)))
这将产生所需的结果:“0”,“1”,“2”,“3”,“4”
如果有人能告诉我为什么上述简单解决方案(不使用_set函数)不起作用,请继续。
我忘了提到我用tk.Menu替换了MyMenu,因为我不喜欢那种方法。
英文:
The above mentioned "lambda" only solution,
...
stage_menu_item.add_command(label="1", command = lambda: confirm_stage(1))
...
seems to work with static parameters, but if you try it with a loop, eg:
...
for _x in range(5):
stage_menu_item.add_command(label='Menu'+str(_x), command=lambda: confirm_stage(str(_x)))
...
It doesn't. "_x" is always "4" no matter what menu item you call. Don't know why.
The only way it worked for me was:
def _set(x:str):
return lambda: confirm_stage(x)
...
for _x in range(5):
stage_menu_item.add_command(label=str(_x), command=_set(str(_x)))
Which renders the wanted result of: "0", "1", "2", "3", "4"
If anyone can enlighten me, why the above easy solution (without _set function) is not working, go ahead.
I forgot to mention I replaced the MyMenu with tk.Menu, since I didn't liked that approach.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论