Tkinter的奇怪函数行为

时间:2012-12-10 05:03:41

标签: python tkinter

我们在事件回调中有一些代码如下:

...
self.position.side = -self.position.side
self.update_with_board() # displays self.position graphically
ai_move = self.brain.get_move(self.position)
...

立即调用update(),但在ai_move行之前不会影响GUI。

然而,当我这样做时:

...
self.position.side = -self.position.side
self.update_with_board() # displays self.position graphically
raw_input()
ai_move = self.brain.get_move(self.position)
...

它会在请求输入时立即以图形方式更新。我不知道该怎么做:也许是时髦的懒惰评价或者我不知道的tkinter调度事项?如何让GUI按指定顺序更新而不是延迟?

编辑:对不起,我没有使用内置的update()方法,而是我定义绘制的方法。我将其重命名为update_with_board(),并看到相同的行为。

def update_with_board(self):
    for i in range(8):
        for j in range(8):
            color = "gray" if (i+j) % 2 else "white"
            self.canvas.create_rectangle(self.square * i, self.square * j, self.square * (i+1), self.square * (j+1), fill=color)
            if self.position.board[8 * j + i] in self.ims.keys():
                self.canvas.create_image(self.square * i + self.square/2,
                self.square * j + self.square/2, image = self.ims[self.position.board[8 * j + i]])  

1 个答案:

答案 0 :(得分:3)

做更多的研究,我很确定我的评论是正确的。

每次通过事件循环时,UI都会根据需要更新所有小部件。调用update基本上只是强制它现在运行事件循环。所以,如果你正处于一个事件回调的中间,你会递归地进入事件循环,这是一个非常糟糕的事情,并且可以导致无限递归。

正如The TkInter Book所说,update

  

处理所有待处理事件,调用事件回调,完成任何挂起的几何管理,根据需要重绘小部件,并调用所有挂起的空闲任务。应谨慎使用此方法,因为如果从错误的位置(例如,从事件回调中调用,或者从可以以任何方式从事件回调中调用的函数等)调用它,可能会导致非常讨厌的竞争条件)。如有疑问,请改用update_idletasks。

同样,the TkInter reference说:

  

此方法强制更新显示。只有当您知道自己在做什么时才应该使用它,因为它可能导致不可预测的行为或循环。永远不应该从事件回调或从事件回调中调用的函数调用它。

测试事情,似乎至少在某些情况下,当你从事件循环中调用update时,TkInter会忽略你。大概是为了保护你免受无限递归,但我没有看过代码来验证它。

无论如何,这不是你想要的功能,所以它为什么没有做到没有记录的功能并不重要。

如果您需要在事件回调中触发更新,请致电update_idletasks。这实际上调用所有待处理的“空闲”任务,包括重绘,而不调用任何事件回调。 (不是“下次我们在事件循环中更新而没有别的事情可做”。)

同时,在事件回调中调用raw_input会更糟。您正在阻止终端输入上的主事件循环。除非这只是你为调试目的所做的事情,否则这是一个非常糟糕的主意。即使出于调试目的,测试也是一件非常奇怪的事情,无论发生什么都与正常行为无关,这是完全可信的。

有关更多背景信息,请参阅问题TkInter: How do widgets update,或在此网站上搜索update_idletasks,或查看右侧的一些相关链接(至少有两个相关链接)。< / p>

基于你的编辑,事实证明,这听起来像你有一些相反的问题 - 你只是在不告诉TkInter对它做任何事情而改变事情,所以改变不会' t显示直到下一次通过事件循环(这意味着直到你从这个函数返回后)。但答案基本相同 - 一种方式是“将update替换为update_idletasks”,另一种方式是“添加对update_idletasks的调用”。

相关问题