【问题标题】:Inheriting from Frame and mainloop on Tkinter application从 Tkinter 应用程序上的 Frame 和 mainloop 继承
【发布时间】:2020-03-01 00:43:17
【问题描述】:

official Python documentation (Python 3.7) 中有以下示例,我试图了解代码的工作原理。我从原始代码中添加了一些 cmets。

import tkinter as tk


class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)  # Initialize the tk.Frame class
        self.master = master  # Is it necessary?
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Hello World\n(click me)"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")

        self.quit = tk.Button(self, text="QUIT", fg="red", command=self.master.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")


def main():
    # Instance of the root window
    root = tk.Tk()
    # Instance of the main frame
    app = Application(master=root)
    # Infinite loop used to run the application
    app.mainloop()  # mainloop() on tk.Tk() instance (root) or tk.Frame() instance (app)?


if __name__ == '__main__':
    main()

我对这段代码有两个问题:

  • 在继承tk.FrameApplication类中用super().__init__(master)初始化tk.Frame类后,self.master已经包含引用到根窗口。我通过前后打印id(self.master) 验证了这一点。那么,self.master = master 有必要吗?为什么要添加它?
  • mainloop()方法被添加到Application类的app实例中,继承tk.Frame .但我可以将 mainloop() 方法添加到 tk.Tk 类的 root 实例中。该应用程序适用于这两种情况。有什么区别?

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    self.master = master 不是从 tkinter 类继承所必需的。在这种情况下是多余的。你也不需要超级大师。只需在此处执行 super().__init__() 即可。

    您不应使用框架内的几何管理器将自身放置在父容器上。而是从课堂外调用它。假设您需要将其从 pack() 更改为 grid(),您必须在类中更改它,而不是简单地更新其在主代码中的位置。

    您的主循环应该引用根实例。

    我会在创建按钮时传递所有初始参数。它只是添加更多的代码行来分别更新每个参数。

    最后一件事。如果您稍后要在代码中编辑变量/小部件,请使用self. 前缀使其成为类属性,但如果不是,则没有理由使用self.,因此我们可以将它们从按钮中删除。

    重做的代码:

    import tkinter as tk
    
    
    class Application(tk.Frame):
        def __init__(self):
            super().__init__()
            tk.Button(self, text="Hello World\n(click me)", command=self.say_hi).pack(side="top")
            tk.Button(self, text="QUIT", fg="red", command=self.master.destroy).pack(side="bottom")
    
        def say_hi(self):
            print("hi there, everyone!")
    
    
    def main():
        root = tk.Tk()
        Application().pack()
        # app = MaxiTeam(root) # not sure what this is unless you meant Application?
        root.mainloop()
    
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

    • “你也不需要超级大师。” 我认为这是个坏建议。虽然在这种特定情况下没有必要,因为默认是将框架放在根窗口中,但如果您希望将您的类放在根以外的任何东西中,那就不是真的了。 python之禅说显式胜于隐式。
    • @BryanOakley 在从 tkinter 小部件继承的类中,除了 super().__init__() 之外,我从来不需要做任何事情。通常我不编写任何其他继承的类,所以我想我不必处理任何重要的情况。你能指出一个重要的例子吗?还有一个被广泛接受的post here 状态“你可以说super().__init__() 而不是super(ChildB, self).__init__(),哪个IMO 更好一些。”我承认我没有深入挖掘,因为它似乎是公认的方法。
    • @Mike-SMT 我不明白 Application 类如何知道谁是根窗口而不传递 root 实例
    • @Mike-SMT:在本例中,在main 中创建一个框架,然后将Application 放在框架内部而不是根目录中。例如lf = tk.LabelFrame(root, text="Something"); Application(lf)。如果您不将master 传递给super.__init(),则应用程序将不在标签框内。
    • 使用super不需要指定子类,但需要传递任何配置选项,否则基类无法看到配置选项。
    猜你喜欢
    • 2011-11-10
    • 2021-04-20
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多