【问题标题】:Calling GUI method/sub-class from separate class从单独的类调用 GUI 方法/子类
【发布时间】:2019-10-22 20:08:47
【问题描述】:

我正在尝试创建一个脚本来创建一个 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)

图形用户界面如下:

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。我没有显示应该显示的页面,而是出现错误。

我做错了吗?

【问题讨论】:

  • “我做错了吗?”:你没有显示Full Tracebackedit你的问题相应地。

标签: python python-2.7 tkinter


【解决方案1】:

您不应创建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)
    ...

【讨论】:

  • 我喜欢这个。这简化了我将定序器传递到 GUI 并从中运行方法的方式。但是,我认为我仍然对用于调用 GUI 的 show_page() 方法以更改显示给操作员的代码的 sn-p 感到困惑?我这样称呼它正确吗?
  • @gerf.merns:你需要把gui.TestGUI().show_page(PageOne)改成self.my_gui.show_page(PageOne)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 2017-11-09
  • 2011-10-24
  • 1970-01-01
相关资源
最近更新 更多