Python MWC 模式 GUI - 来自控制器的菜单栏命令 class

Python MWC pattern GUI - Menubar command from controller class

我正在尝试构建一个数据分析工具。我预计这种应用程序会变得很大,所以我遵循 MVC 模式来尽可能地组织它。

我的结果保存在 .csv 文件中,因此目标应该是将它们“导入”到 GUI 中。我想使用“CTRL + O”作为快捷键打开这些文件,当然也可以使用菜单栏中的相应选项。

现在进入实际问题: 点击“CTRL + O”时调用的函数在控制器 class 中并且按预期工作,我可以打开一堆文件并且列表保存每个名称。但是当使用菜单栏时,我不知道如何实现“command=”选项。

这是我的代码:

import tkinter as tk
from tkinter.filedialog import askopenfilename
from tkinter.constants import ANCHOR, TRUE
from tkinter import Label, filedialog
from tkinter import ttk


class Model():
    # more to come
    pass

class View:

    def __init__(self, view):

        self.view = view
        self.view.title("analyzer")
        self.view.geometry("640x480")
        self.view.resizable(False, False)

        # menubar
        self.menubar = tk.Menu(self.view)
        self.view.config(menu=self.menubar)
        self.filemenu = tk.Menu(self.menubar, tearoff=False)

        self.menubar.add_cascade(label="File", menu=self.filemenu)
        
        self.filemenu.add_command(label="Open", accelerator="Ctrl+O", command=Controller.get_open_filename())
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Remove", accelerator="Ctrl+R")
        self.filemenu.add_command(label="Information", accelerator="Ctrl+I")
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Exit", accelerator="Ctrl+E", command=self.view.quit)


class Controller:

    def __init__(self):
        self.root = tk.Tk()
        self.view = View(self.root)

        # keybindings / shortcuts
        self.root.bind_all("<Control-e>", lambda event: self.root.quit())
        self.root.bind_all("<Control-o>", lambda event: self.get_open_filename())

        self.list_of_files = []
       
        
    def run(self):
        self.root.mainloop()


    def get_open_filename(self):
        self.filename = askopenfilename(title="Select data file", filetypes=(("csv files", "*.csv"), ("all files", "*.*")))
        self.list_of_files.append(self.filename)


        print(self.list_of_files)


if __name__ == "__main__":
    c = Controller()
    c.run()

如果有人能给我提示,我将不胜感激,希望我做错了。 谢谢!

您正在尝试从视图对象调用控制器函数,但视图不知道控制器具有该函数。它不知道控制器的存在。

可能有比这更好的方法,但您可以将函数作为参数传递给 View 的构造函数。 通过将 get_open_filename() 函数作为参数传递给 View 的构造函数,您可以将其用作命令。

注意:我调用了参数 func 这样您就可以看到我在做什么。不过我建议给它起一个更好的名字。

import tkinter as tk
from tkinter.filedialog import askopenfilename
from tkinter.constants import ANCHOR, TRUE
from tkinter import Label, filedialog
from tkinter import ttk


class Model():
    # more to come
    pass

class View:

    def __init__(self, view, func):

        self.view = view
        self.view.title("analyzer")
        self.view.geometry("640x480")
        self.view.resizable(False, False)

        # menubar
        self.menubar = tk.Menu(self.view)
        self.view.config(menu=self.menubar)
        self.filemenu = tk.Menu(self.menubar, tearoff=False)

        self.menubar.add_cascade(label="File", menu=self.filemenu)
        
        self.filemenu.add_command(label="Open", accelerator="Ctrl+O", command=func)
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Remove", accelerator="Ctrl+R")
        self.filemenu.add_command(label="Information", accelerator="Ctrl+I")
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Exit", accelerator="Ctrl+E", command=self.view.quit)


class Controller:

    def __init__(self):
        self.root = tk.Tk()
        self.view = View(self.root, lambda: self.get_open_filename())

        # keybindings / shortcuts
        self.root.bind_all("<Control-e>", lambda event: self.root.quit())
        self.root.bind_all("<Control-o>", lambda event: self.get_open_filename())

        self.list_of_files = []
       
        
    def run(self):
        self.root.mainloop()


    def get_open_filename(self):
        self.filename = askopenfilename(title="Select data file", filetypes=(("csv files", "*.csv"), ("all files", "*.*")))
        self.list_of_files.append(self.filename)


        print(self.list_of_files)


if __name__ == "__main__":
    c = Controller()
    c.run()