Python:Tkinter:为什么是root.mainloop()而不是app.mainloop()

Nuu*_*uuk 3 python oop tkinter

我是Stack Overflow的新成员。我找到了这个线程,但不允许对此发表评论或提出问题,所以我想在这里引用它:如何在Python的Tkinter中创建一个交互式列表,并带有可以编辑这些列表的按钮?

from tkinter import *
import os
import easygui as eg

class App:

    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        # character box
        Label(frame, text = "Characters Editor").grid(row = 0, column = 0, rowspan = 1, columnspan = 2)
        charbox = Listbox(frame)
        for chars in []:
            charbox.insert(END, chars)
        charbox.grid(row = 1, column = 0, rowspan = 5)
        charadd = Button(frame, text = "   Add   ", command = self.addchar).grid(row = 1, column = 1)
        charremove = Button(frame, text = "Remove", command = self.removechar).grid(row = 2, column = 1)
        charedit = Button(frame, text = "    Edit    ", command = self.editchar).grid(row = 3, column = 1)

    def addchar(self):
        print("not implemented yet")
    def removechar(self):
        print("not implemented yet")
    def editchar(self):
        print("not implemented yet")


root = Tk()
root.wm_title("IA Development Kit")
app = App(root)
root.mainloop()
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释为什么最后一行是root.mainloop()吗?作为Python的新手,并且来自没有面向对象经验的面向过程的背景,所以我认为它应该是app.mainloop()。

实际上app = App(root),在其余的代码中再也不会使用app了!我无法理解为什么root.mainloop()仍然有效。

Bry*_*ley 5

我不确定您是否会找到满意的答案,但您root.mainloop()之所以打电话是因为root具有该mainloop方法的对象。在您提供的代码中,App没有任何mainloop功能。

简单来说,这就是tkinter的工作方式-您始终通过调用mainloop根窗口的方法来结束脚本。当该方法返回时,您的程序将退出。

让我们从头开始。最简单的非OO Tkinter程序将类似于以下示例。请注意,这是一个python 2.x示例,并且我不使用全局导入,因为我认为全局导入是不好的。

import Tkinter as tk
root = tk.Tk()
<your widgets go here>
root.mainloop()
Run Code Online (Sandbox Code Playgroud)

许多人发现纯粹的过程样式不是编写代码的有效方法,因此他们可能选择以面向对象的样式编写。将“应用程序”视为一个单例对象是很自然的。有很多方法可以做到这一点-不幸的是,您所提出的问题不是更清晰的方法之一。

IMO更好的方法是构造如下代码:

class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        <your widgets go here>
app = App()
app.mainloop()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,mainloop仍然被调用,尽管现在这是App因为从App继承的方法Tk。这是概念上相同root.mainloop(),因为在这种情况下,app 根窗口,即使它的推移,不同的名称。

因此,在两种情况下mainloop都是属于根窗口的方法。在这两种情况下,都必须调用它才能使GUI正常运行。

第三种变化是您选择的代码正在使用的代码。有了这种变体,有几种方法可以实现它。变化是你的问题使用一个类来定义GUI,但并没有继承Tk。很好,但是您仍然必须mainloop在某个时候打电话。由于您没有mainloop在类中创建(或继承)函数,因此必须调用与根窗口关联的函数。我讲的变化是实例的App添加方式和位置以及在根窗口中的位置,以及mainloop最终被调用的方式。

就我个人而言,我更喜欢App从继承Frame,并且将应用打包在应用定义之外。我使用的模板如下所示:

class App(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        <your widgets go here>

if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    app.pack(fill="both", expand=True)
    root.mainloop()
Run Code Online (Sandbox Code Playgroud)

在最后一个示例中,approot是两个完全不同的对象。app表示存在一个帧内部根窗口。框架通常以这种方式使用,作为其他小部件组的容器。

因此,在任何情况下都mainloop必须调用。在那里它被称为,以及如何,取决于你的编码风格有点。有些人喜欢从根窗口继承,有些则不然。无论哪种情况,都必须调用mainloop根窗口的功能。