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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22698980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 01:27:08  来源:igfitidea点击:

Python: Tkinter: Why is it root.mainloop() and not app.mainloop()

pythonooptkinter

提问by Nuuk

I'm a new member to Stack Overflow. I found this thread, but was not allowed to comment or ask questions on it, so I thought I'd just reference it here: How can I make a in interactive list in Python's Tkinter complete with buttons that can edit those listings?

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

Could somebody explain to me why the very last line is root.mainloop()? Being a novice with Python, and coming from a background that's procedural-oriented with no object-orient experience, I would have thought it would have been app.mainloop().

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

In fact app = App(root) , app is never used again in the rest of the code! I'm having trouble understanding why root.mainloop() still works.

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

采纳答案by Bryan Oakley

I'm not sure if you'll find this answer satisfying, but you call root.mainloop()because rootis the object that has the mainloopmethod. In the code you've given, Apphas no mainloopfunction.

我不确定你是否会发现这个答案令人满意,但你打电话root.mainloop()是因为root是具有该mainloop方法的对象。在您给出的代码中,App没有任何mainloop功能。

In simpler terms, this is just how tkinter works -- you always end your script by calling the mainloopmethod of the root window. When that method returns, your program will exit.

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

Let's start at the beginning. The simplest, non-OO Tkinter program is going to look like the following example. Note that this is a python 2.x example, and I do not use a global import since I think global imports are bad.

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

import Tkinter as tk
root = tk.Tk()
<your widgets go here>
root.mainloop()

Many people find that a pure procedural style is not an effective way to write code, so they might choose to write this in an object-oriented style. It's natural to think of "the app" as a singleton object. There are many ways to do this -- the one in your question is, unfortunately, not one of the clearer ways to do it.

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

A slightly better way, IMO, would be to structure the code like this:

IMO 稍微好一点的方法是像这样构造代码:

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

In this case, mainloopis still being called, though now it's a method of Appsince Appinherits from Tk. It is conceptually the same as root.mainloop()since in this case, appisthe root window even though it goes by a different name.

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

So, in both cases, mainloopis a method that belongs to the root window. And in both cases, it must be called for the GUI to function properly.

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

There is a third variation which is what the code you picked is using. And with this variation, there are several ways to implement it. The variation is your question uses a class to define the GUI, but does notinherit from Tk. This is perfectly fine, but you still must call mainloopat some point. Since you don't create (or inherit) a mainloopfunction in your class, you must call the one associated with the root window. The variations I speak of are how and where the instance of Appis added to the root window, and how mainloopis ultimately called.

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

Personally I prefer that Appinherits from Frame, and that you pack the app outsidethe definition of the app. The template I use looks like this:

我个人更喜欢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()

In this final example, appand rootare two completely different objects. apprepresents a frame that exists insidethe root window. Frames are commonly used this way, as a container for groups of other widgets.

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

So, in all cases, mainloopmust be called. whereit is called, and how, depends a bit on your coding style. Some people prefer to inherit from the root window, some don't. In either case, you must call the mainloopfunction of the root window.

所以,在所有情况下,都mainloop必须被调用。它在哪里以及如何调用,在某种程度上取决于您的编码风格。有些人喜欢从根窗口继承,有些人不喜欢。无论哪种情况,都必须调用mainloop根窗口的函数。

回答by Two-Bit Alchemist

The Appobject is just your app code, and the reason you call App(root)is to make an instance with your class, which then has access to your root window.

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

It receives this reference in the __init__method:

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

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

You can see the entire definition of the Appobject (given by the block beginning with class App:), and it doesn't even have a mainloopmethod, so to start the main Tkinter loop, you have to call it on the root window.

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

In the example in the Python2 documentation, they docall it as you suspected should be done, but note that their example class subclasses the Tk object Frame. In your example code, Appis an old-style class that doesn't inherit anything.

Python2 文档中示例中,他们确实如您所想的那样称呼它,但请注意,他们的示例类是 Tk 对象的子类Frame。在您的示例代码中,App是一个不继承任何内容的旧式类。

回答by III

I tested both like you see:

我像你看到的一样测试了两者:

One is written with "app." + ".pack()"and one calls "mainframe." + ".grid()"

一种是用“app”写的+ ".pack()"和一个叫"mainframe"。+ ".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()

This instance works fine with python 2.7. In that test even app. can handle "mainloop()" That script opens 2 windows, one after another (if you close the first one) and the first programm is formatted, didn't tryed to write the colum=3... stuff in the pack() clamps.

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

I still started the Tkinter so don't fight me, just trying.. Hope I could help to answer your question. All the best, Ingo

我仍然启动了 Tkinter,所以不要与我对抗,只是尝试.. 希望我能帮助回答您的问题。一切顺利,英戈