2

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

...
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]])  
4

1 回答 1

3

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

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

正如The TkInter Book所说,update

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

同样,TkInter 参考说:

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

update测试一下,至少在某些情况下,当您从事件循环内部调用时,TkInter 似乎只是忽略了您。大概是为了保护您免受无限递归,但我还没有查看代码来验证这一点。

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

如果您需要从事件回调中触发更新,请调用update_idletasks. 这实际上调用了所有挂起的“空闲”任务,包括重绘,而不调用任何事件回调。(不是“下次我们在事件循环中并且无事可做时更新”。)

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

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

根据你的编辑,事实证明,听起来你有一种相反的问题——你只是在没有告诉 TkInter 做任何事情的情况下改变了一些东西,所以这些改变要等到下一次活动时才会出现循环(这意味着直到你从这个函数返回之后)。但答案基本上是一样的——一种方式是“将您的呼叫替换为updateupdate_idletasks,另一种方式是“添加呼叫update_idletasks”。

于 2012-12-10T05:39:00.997 回答