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

时间:2014-03-27 20:54:25

标签: python oop tkinter

我是Stack Overflow的新成员。 我找到了这个帖子,但是不允许对它发表评论或提问,所以我想我只是在这里引用它:How can I make a in interactive list in Python's Tkinter complete with buttons that can edit those listings?

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()

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

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

3 个答案:

答案 0 :(得分:4)

我不确定您是否会发现此答案令人满意,但您致电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()

许多人发现纯粹的程序风格不是编写代码的有效方式,因此他们可能会选择以面向对象的方式编写代码。很自然地想到了应用程序&#34;作为单身对象。有很多方法可以做到这一点 - 遗憾的是,问题中的一个方法并不是更明确的方法之一。

稍微好一点的方法,IMO,就是构建这样的代码:

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

在这种情况下,仍然会调用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()

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

因此,在所有情况下,都必须调用mainloop在哪里被调用,以及如何,取决于你的编码风格。有些人喜欢从根窗口继承,有些人不喜欢。在任何一种情况下,您都必须调用根窗口的mainloop函数。

答案 1 :(得分:1)

我测试了两个,就像你看到的那样:

一个用“app”编写。 +“。pack()”,一个调用“大型机”。 +“。grid()”

 #-*- coding: utf-8 -*-
#THIS IS THE "MAINFRAME." - PART
from Tkinter import *
import ttk

def show():
    p = password.get() #get password from entry
    print(p)


root = Tk()
root.title("Ingos first program")

mainframe = ttk.Frame(root, padding="30 30 60 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)


password = StringVar() #Password variable
passEntry = Entry(mainframe, textvariable=password, show='*').grid(column=3, row=3, sticky=S)
submit = Button(mainframe, text='Show Console',command=show).grid(column=3, row=4, sticky=S)

root.mainloop()
def show():
    p = password.get() #get password from entry
    print(p)

#THIS IS THE "APP."-PART. BOTH WORKS FINE.
app = Tk()
app.title("Ingos first program")
password = StringVar() #Password variable
passEntry = Entry(app, textvariable=password, show='#').pack()
submit = Button(app, text='Show Console',command=show).pack()

app.mainloop()

这个实例适用于python 2.7。在那个测试甚至应用程序。可以处理“mainloop()” 该脚本打开2个窗口,一个接一个(如果你关闭第一个)并且第一个程序被格式化,没有尝试在pack()clamps中写colum = 3 ... stuff。

我仍然开始使用Tkinter所以不要打我,只是尝试..希望我能帮助回答你的问题。 一切顺利,Ingo

答案 2 :(得分:0)

App对象只是您的应用代码,您调用App(root)的原因是为您的类创建一个实例,然后该类可以访问您的根窗口。

它在__init__方法中接收此引用:

def __init__(self, master):
    # master refers to the root window now
    ...

你可以看到App对象的整个定义(由以class App:开头的块给出),它甚至没有mainloop方法,所以要启动主Tkinter循环,你必须在根窗口调用它。

example in the Python2 documentation中,他们执行调用它,因为您怀疑应该这样做,但请注意他们的示例类是Tk对象Frame的子类。在您的示例代码中,App是一个旧式类,不会继承任何内容。