2011-12-30 71 views
35

我见过的每一个tkinter教程都声称,必须调用tkinter.mainloop来绘制要绘制的窗口和要处理的事件,并且即使在hello world程序中它们也总是调用此函数。但是,当我在交互式shell中尝试这些时,无需调用mainloop即可正确绘制窗口。在tkinter中嵌入matplotlib图形的This example会生成一个相对复杂的应用程序,并带有用于在tkinter窗口中平移,缩放和调整图形大小的按钮,并且,如果您移除对mainloop的调用并在交互式shell中运行代码,当然,如果我在交互式shell外运行脚本(在主循环被移除的情况下),程序结束得太快以至于看不到会发生什么,但是如果我添加一个调用input来保持程序打开一切正常(我正在运行python 3.2.2在linux上)。什么时候需要在Tkinter应用程序中调用mainloop?

那么,mainloop究竟做了什么,以及何时需要调用它?

编辑: 为了澄清,如果我打通GNOME终端输入而不必调用主循环

$python3 
>>> import tkinter 
>>> root = tkinter.Tk() 

一个窗口立即出现,和更复杂的Tkinter功能似乎工作以及(例如,向窗口添加按钮)。在IDLE中,调用mainloop是必要的。我的理解是,除非主循环被调用,否则不应该绘制任何事件,也不应处理任何事件。

回答

38

你主要问题的答案是,当你准备好你的应用程序运行时,你必须调用一次mainloop一次。

mainloop比一个无限循环,看起来大致是这样的(这些都不是这些方法的实际名称,名称仅仅用来说明这一点)没有更多:

while True: 
    event=wait_for_event() 
    event.process() 
    if main_window_has_been_destroyed(): 
     break 

在这种情况下,“事件”意味着用户交互(鼠标点击,按键等)以及来自工具包或OS /窗口管理器的绘制或重新绘制小部件的请求。如果该循环未运行,则不会处理事件。如果事件没有得到处理,屏幕上就不会显示任何内容,并且程序可能会退出,除非您有自己的无限循环运行。

那么,为什么你不需要交互调用呢?这只是一种方便,否则一旦您呼叫mainloop,将不可能输入任何命令,因为mainloop直到主窗口被销毁。

7

将程序与交互式GUI进行比较,以计算第百个斐波纳契数。后面的所有程序都必须按顺序经过一系列步骤,从上到下。这套步骤及其排序可以事先知道,无论您运行程序多少次,它都会保持不变。

但是GUI程序是不同的:在任何特定的时刻,它必须能够处理各种不同类型的事件和交互。这个要求通常使用称为事件循环的编程构造来实现。事件循环是程序的中央控制结构。它等待事件发生,然后分派适当的处理程序。

你没有提到你正在使用哪个交互式shell,但我猜它是空闲的。 IDLE本身是一个Tkinter程序,它已经有一个事件循环。所以可能你在shell中键入的Tkinter代码已经绑定到IDLE的事件循环。

+0

对不起,我应该提到:我只是用标准Python壳(未IDLE)在GNOME终端(其显然写入C)。就我所知,除了我自己的代码之外,没有什么东西可以做任何影响tkinter的东西。 – James 2011-12-30 21:38:45

+1

我刚刚在IDLE中尝试过同样的事情,而且我没有得到相同的行为 - 直到我调用mainloop时才会出现窗口。 – James 2011-12-30 21:46:38

-3

我已经决定,我不会直接在我的脚本的任何地方直接粘贴一个调用mainloop,我只是将它添加为atexit的一部分 - 也就是说,当Python解释器决定是时候开始关闭的时候,将进入Tk的主循环。这样就可以防止它完成关停序列,直到用户实际上告诉Tk的退出(即,在Mac上的命令-Q,或通过单击Windows中的红色的X)。

from Tkinter import Tk 
root = Tk() 

import atexit 
atexit.register(root.mainloop) 

似乎有无需从系统命令行调用mainloop。 Python解释器会在没有它的情况下继续运行,因为它正在等待您的进一步输入(直到您运行exit())。

+1

_“在我看来,调用mainloop所做的唯一的事情是阻止你的应用程序自动关闭”_:这是一个不正确的评估。它管理事件队列,这远远不止是阻止应用程序退出。另外,你甚至没有按照你自己的想法做:你实际上是在调用'mainloop()',而不是在退出时调用。 – 2016-03-07 15:20:31

+1

@BryanOakley - 哎呀,我已经修复了对''mainloop()'的意外调用 - 现在它只是注册了,因为它应该是。无论如何,我相信你是不正确的。在你的回答中,你说你不需要在交互式交互中调用mainloop这一事实“仅仅是一种方便”。呃,什么?如果这是一件方便的事情,那么无论是交互式解释器还是“Tkinter”模块都必须包含允许这样做的特殊代码。我不相信代码存在。没有说明它的文档。你说的负担就是证明主循环是神奇的。 – ArtOfWarfare 2016-03-07 15:29:39

+0

我从来没有听说过atexit,我很高兴我找到了这个答案,因为它允许我在单元测试期间调用一个'Tk()'应用程序,而无需手动关闭应用程序。 – 2017-02-21 10:07:03

-3

如下:

from tkinter import * 

tk = Tk() 
canvas = Canvas(tk, width=500, height=500) 
canvas.pack() 
canvas.create_line(0, 0, 500, 500) 

mainloop() 
相关问题