更改一个 OptionMenu 会更改第二个
Changing one OptionMenu changes the second one
在我下面的代码中,我有两个选项菜单,它们填充了相同的列表。在最终应用程序中,列表是通过导入 .csv 文件生成的。
用户应该能够select列表中的两个条目。
现在的问题是,改变第一个选项菜单,会改变第二个选项菜单。
然而,第二个按预期工作。
估计update_file_list_selection()
和lambda
函数实现的不好
import tkinter as tk
from tkinter import ttk
class File_Selection():
def __init__(self, frame, text):
self.frame = frame
self.text = text
self.label_file = tk.Label(self.frame, text=text)
self.label_file.pack()
self.variable_file = tk.StringVar(self.frame)
self.option_list = ["no file loaded"]
self.variable_file.set(self.option_list[0])
self.optionmenu_file = tk.OptionMenu(self.frame, self.variable_file,
*self.option_list)
self.optionmenu_file.pack()
class View:
def __init__(self, view, update_list):
self.view = view
self.view.title("Test")
self.view.geometry("320x240")
self.view.resizable(False, False)
self.frame = tk.Frame(self.view)
self.frame.pack()
self.button = tk.Button(self.frame, text="Update", command=update_list)
self.button.pack()
self.file_one = File_Selection(self.frame, "File 1")
self.file_two = File_Selection(self.frame, "File 2")
class Controller:
def __init__(self):
self.root = tk.Tk()
self.view = View(self.root, lambda: self.update_file_list_selection())
self.files = ["File 1", "File 2", "File 3", "File 4"]
def run(self):
self.root.mainloop()
def update_file_list_selection(self):
self.active_file_selection = [self.view.file_one, self.view.file_two]
for file_selection in self.active_file_selection:
self.menu = file_selection.optionmenu_file["menu"]
self.menu.delete(0, "end")
for x in self.files:
file_selection.option_list.append(x)
self.menu.add_command(label=x,
command=lambda value=x: file_selection.variable_file.set(value))
file_selection.variable_file.set(self.files[0])
if __name__ == "__main__":
c = Controller()
c.run()
I guess the function update_file_list_selection() and lambda function is implemented badly.
猜对了。
原因是使用 lambda
的一个常见问题 - 当您使用 command=lambda value=x: file_selection.variable_file.set(value)
时,file_selection
的值将不是循环中的值,它将结束是最后一次设置该变量的值。您可以通过将值绑定到 lambda
作为默认参数来解决此问题:
self.menu.add_command(label=x, command=lambda value=x, fs=file_selection: fs.variable_file.set(value))
以上将确保在 lambda
正文中,fs
将在创建菜单项时设置为 file_selection
的值,而不是在选择项目的时间。
您仍然会得到 OptionMenu
项,它们的行为与正常的 OptionMenu
项不完全相同,但在这个特定示例中,这似乎并不重要,因为您不没有一个 command
与整个 OptionMenu
关联。
在我下面的代码中,我有两个选项菜单,它们填充了相同的列表。在最终应用程序中,列表是通过导入 .csv 文件生成的。
用户应该能够select列表中的两个条目。
现在的问题是,改变第一个选项菜单,会改变第二个选项菜单。 然而,第二个按预期工作。
估计update_file_list_selection()
和lambda
函数实现的不好
import tkinter as tk
from tkinter import ttk
class File_Selection():
def __init__(self, frame, text):
self.frame = frame
self.text = text
self.label_file = tk.Label(self.frame, text=text)
self.label_file.pack()
self.variable_file = tk.StringVar(self.frame)
self.option_list = ["no file loaded"]
self.variable_file.set(self.option_list[0])
self.optionmenu_file = tk.OptionMenu(self.frame, self.variable_file,
*self.option_list)
self.optionmenu_file.pack()
class View:
def __init__(self, view, update_list):
self.view = view
self.view.title("Test")
self.view.geometry("320x240")
self.view.resizable(False, False)
self.frame = tk.Frame(self.view)
self.frame.pack()
self.button = tk.Button(self.frame, text="Update", command=update_list)
self.button.pack()
self.file_one = File_Selection(self.frame, "File 1")
self.file_two = File_Selection(self.frame, "File 2")
class Controller:
def __init__(self):
self.root = tk.Tk()
self.view = View(self.root, lambda: self.update_file_list_selection())
self.files = ["File 1", "File 2", "File 3", "File 4"]
def run(self):
self.root.mainloop()
def update_file_list_selection(self):
self.active_file_selection = [self.view.file_one, self.view.file_two]
for file_selection in self.active_file_selection:
self.menu = file_selection.optionmenu_file["menu"]
self.menu.delete(0, "end")
for x in self.files:
file_selection.option_list.append(x)
self.menu.add_command(label=x,
command=lambda value=x: file_selection.variable_file.set(value))
file_selection.variable_file.set(self.files[0])
if __name__ == "__main__":
c = Controller()
c.run()
I guess the function update_file_list_selection() and lambda function is implemented badly.
猜对了。
原因是使用 lambda
的一个常见问题 - 当您使用 command=lambda value=x: file_selection.variable_file.set(value)
时,file_selection
的值将不是循环中的值,它将结束是最后一次设置该变量的值。您可以通过将值绑定到 lambda
作为默认参数来解决此问题:
self.menu.add_command(label=x, command=lambda value=x, fs=file_selection: fs.variable_file.set(value))
以上将确保在 lambda
正文中,fs
将在创建菜单项时设置为 file_selection
的值,而不是在选择项目的时间。
您仍然会得到 OptionMenu
项,它们的行为与正常的 OptionMenu
项不完全相同,但在这个特定示例中,这似乎并不重要,因为您不没有一个 command
与整个 OptionMenu
关联。