更改一个 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 关联。