首页 > 解决方案 > 从单独的类调用 GUI 方法/子类

问题描述

我正在尝试创建一个脚本来创建一个 GUI 类的实例,它本身具有子类来表示我想要显示的各种页面。

目标是创建一个调用特定 GUI 页面来显示的序列文件,一旦显示该 GUI 页面并单击按钮,它将运行序列文件中的序列,然后指示要显示哪些 GUI 页面。

Seqeuncer 看起来像这样(显示测试页的标准已简化)

import gui

class Sequencer():

    def __init__(self):
        pass

    def run_gui(self):
        # Create instance of the Test GUI
        self.my_gui = gui.TestGUI()
        self.my_gui.mainloop()

    def run_test(self, entry):
if x = 1:
        gui.TestGUI().show_page(PageOne)
if x = 2:
        gui.TestGUI().show_page(PageTwo)

GUI 看起来像:

import sequencer

class TestGUI(tk.Tk):

    def __init__(self):

        # Initialize the container
        tk.Tk.__init__(self)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        # Make the container a fixed size
        tk.Tk.resizable(self, False, False)

        # Set up the pages for the GUI
        self.pages = {}
        list_of_pages = [
            PageOne,
            PageTwo
        ]
        for P in list_of_pages:
            frame = P(container, self)
            self.pages[P] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        # Set the Main Page
        self.show_page(MainPage)

    def show_page(self, page):

        frame = self.pages[page]
        frame.tkraise()

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)

        entry = tk.Entry(self, width=40, font="Arial 16", justify="center")
        entry.place(relx=0.5, rely=0.5, anchor="center")

        # Create Binding for the Return Key
        entry.bind("<Return>", lambda event: sequencer.Sequencer().run_test(entry.get()))

class PageTwo(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)

然后,我创建了一个顶级脚本 (main.py),它创建了 Sequencer 的一个实例并运行了 gui。我没有显示应该显示的页面,而是出现错误。

我做错了吗?

标签: pythonpython-2.7tkinter

解决方案


您不应该创建Sequencer. 相反,传递一个引用或为其他类提供访问实例的方法。

我要做的是将音序器传递给您的 GUI,如下所示:

class Sequencer():
    def run_gui(self):
        ...
        self.my_gui = gui.TestGUI(sequencer=self)
        ...

class TestGUI(tk.Tk):
    def __init__(self, sequencer):
        self.sequencer = sequencer
        ...

因为您的每个子页面都被指定TestGUI为控制器的实例,所以您可以通过删除导入来引用现有的排序器,然后使用控制器来获取对排序器的引用:

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        ...
        self.controller = controller
        ...

        entry.bind("<Return>", lambda event: self.controller.sequencer.run_test(entry.get()))

但是,如果替换lambda为适当的函数,代码将更易于阅读和调试。我发现这是一个很好的经验法则,lambda除非你绝对必须,否则永远不要使用。在这种情况下,使用lambda.

例子:

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        ...
        self.entry = tk.Entry(...)
        self.entry.bind("<Return>", self.run_test)
        ...

    def run_test(self):
        data = self.entry.get()
        self.controller.sequencer.run_test(data)

这样,对代码进行调试就变得容易得多,因为您可以在调用之前检查数据run_test。在这个简单的情况下,这可能没有必要,但如果你养成了这样编码的习惯,当你发现自己编写更复杂的命令时它会派上用场。

您还需要更改run_test函数以重用现有的 TestGUI 实例,而不是每次都创建一个新实例。

def run_test(self, entry):
    ...
        self.mygui.show_page(PageOne)
    ...

推荐阅读