python mainloop大型程序里面放在哪里,关于python:我什么时候需要在Tkinter应用程序中调用mainloop?...

每个tkinter教程我都看到声称必须调用tkinter.mainloop来绘制窗口和要处理的事件,并且它们总是调用此函数,即使在hello world程序中也是如此。但是,当我在交互式shell中尝试这些时,无需调用mainloop即可正确绘制窗口。这个在tkinter中嵌入matplotlib图形的例子产生了一个相对复杂的应用程序,带有用于在tkinter窗口内平移,缩放和调整绘图大小的按钮,再次,如果你删除对mainloop的调用并在交互式shell中运行代码,这一切都有效。 。当然,如果我在交互式shell之外运行脚本(删除了mainloop),程序结束得太快就看不到会发生什么,但如果我添加一个对input的调用来保持程序打开一切正常(我是在Linux上运行python 3.2.2)。

那么mainloop到底做了什么,什么时候需要调用呢?

编辑:

为了澄清,如果我打开GNOME终端并输入

$python3

>>> import tkinter

>>> root = tkinter.Tk()

一个窗口立即出现,而不必调用mainloop,更复杂的tkinter功能似乎也可以工作(例如,向窗口添加按钮)。在IDLE中,需要调用mainloop。我的理解是,在调用mainloop之前,不应绘制任何内容,也不应处理任何事件。

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

mainloop只是一个看起来大致相似的无限循环(那些不是方法的实际名称,名称仅用于说明这一点):

while True:

event=wait_for_event()

event.process()

if main_window_has_been_destroyed():

break

在此上下文中,"事件"表示用户交互(鼠标单击,按键等)以及来自工具箱或OS /窗口管理器的绘制或重绘窗口小部件的请求。如果该循环未运行,则不会处理事件。如果事件没有得到处理,屏幕上不会显示任何内容,除非你有自己的无限循环运行,否则你的程序可能会退出。

那么,为什么不需要以交互方式调用它?这只是一个方便,因为否则一旦你调用mainloop就不可能输入任何命令,因为mainloop一直运行直到主窗口被销毁。

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

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

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

对不起,我应该提到:我只是在GNOME终端中使用标准的python shell(不是IDLE)(显然是用C语言编写的)。因此,据我所知,除了我自己的代码之外什么也不应该做任何影响tkinter的事情。

我刚刚在IDLE中尝试了同样的事情,并且我没有得到相同的行为 - 在我调用mainloop之前没有窗口出现。

如下:

from tkinter import *

tk = Tk()

canvas = Canvas(tk, width=500, height=500)

canvas.pack()

canvas.create_line(0, 0, 500, 500)

mainloop()

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

from Tkinter import Tk

root = Tk()

import atexit

atexit.register(root.mainloop)

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

"在我看来,调用mainloop的唯一办法就是阻止你的应用程序自动关闭":这是一个不正确的评估。它管理事件队列,这远远不仅仅是阻止应用程序退出。而且,你甚至没有做你认为你正在做的事情:你实际上是立即而不是在退出时调用mainloop()。

@BryanOakley - 哎呀,我已经修复了对mainloop()的意外调用 - 现在它只是注册了,因为它应该是。无论如何,我相信你是不正确的。在你的回答中,你说你不需要在交互式交互中调用mainloop是"只是方便"。呃,什么?如果这是一件方便的事情,那么交互式解释器或Tkinter模块必须包含允许这样的特殊代码。我不相信代码存在。没有任何文档说明它的确如此。正如你所说,你需要证明mainloop是神奇的。

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

如果我的代码或解释有问题,请解释一下。令人讨厌的是,很多人都选择了我的方法,据我所知这是最好的方法。

@ArtOfWarfare:我意识到我在最后几条评论中留下了你。内部tkinter和tcl / tk代码确实具有处理交互式使用的特殊代码。有一个名为tcl_interactive的全局tcl变量可以控制此行为。这是在cpython / Modules / _tk??inter.c中设置的,它还有一些基于是否设置的条件代码。您需要自己逐步完成代码,以确切了解交互式使用与非交互式的不同之处。无论如何,有一个交互式使用的特殊代码路径。

此外,您可以在python的Modules / _tk??inter.c中查找mainloop(特别是_tkinter_tkapp_mainloop_impl)的定义,其中您可以看到mainloop所做的远不止"阻止您的应用程序关闭"。它确实是一个处理事件的循环,同时还检查每个事件之间的其他事物(例如窗口被销毁)。我不确定这是否能满足您的所有顾虑。

@BryanOakley - 道歉。但是如果你的脚本必须在最后调用mainloop,那么使用atexit.register调用它来调用它有什么问题?我已经删除了mainloop什么都不做的说法。

我会说这是因为那不是atexit的用途。 atexit用于在程序完成后应运行的代码。根据文档:"atexit模块定义了一个注册清理函数的函数"。 mainloop不是清理功能,它是正在运行的应用程序的组成部分。人们可以争辩说,因为它有效,所以这样做是没有害处的。但是,我们应该努力使代码更加清晰,其中包括不将功能用于不是为其设计的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值