我想让tkinter的event_generate
与update
一起进行原子单元测试。
以下代码无法正常工作。 'BackSpace事件已生成。'没有打印。我的理解是event_generate
将事件放在tkinter的事件队列中,然后update
应该清除并执行队列中的所有事件。
class UpdWin(tk.Tk):
def __init__(self):
super().__init__()
self.bind('<BackSpace>',
lambda event: print(event.keysym, 'event generated.'))
app = UpdWin()
app.event_generate('<BackSpace>')
app.update() # Update doesn't work if placed here
但是,以下代码确实打印了“BackSpace事件生成”。事件队列中的事件在__init__
期间被清除并执行。在此之后,主代码将事件放入tkinter的队列中。
class UpdWin(tk.Tk):
def __init__(self):
super().__init__()
self.bind('<BackSpace>',
lambda event: print(event.keysym, 'event generated.'))
self.update() # Update works if placed here
app = UpdWin()
app.event_generate('<BackSpace>')
我的第一个想法是,我对update
命令的理解必定是错误的。 Lundh,Shipman和TclCmd手册页都有update
的不同条目。
处理所有待处理事件,调用事件回调,完成任何挂起的几何管理,根据需要重绘小部件,以及调用所有待处理的空闲任务。 Lundh (1999)
此方法强制更新显示。 Shipman (New Mexico Tech)
此命令用于通过重复进入事件循环使应用程序“更新”,直到处理完所有待处理事件(包括空闲回调)。 TclCmd man page
由此我怀疑是一个无证的计时问题,我尝试了第三个位置来进行更新命令。以下代码也有效。
class UpdWin(tk.Tk):
def __init__(self):
super().__init__()
self.bind('<BackSpace>',
lambda event: print(event.keysym, 'event generated.'))
app = UpdWin()
app.update() # Update works if placed here
app.event_generate('<BackSpace>')
为什么tkinter的update
在event_generate
之前调用时有效,但之后没有?
修改
以下代码将打印“BackSpace事件生成”。如果app.update
处于位置1
它将打印“FocusIn事件生成”。如果app.update
处于第2位。
注意:Bryan Oakley的回答表明这种影响可能取决于机器。
import tkinter as tk
app = tk.Tk()
# app.update() # Position 1
app.bind('<FocusIn>', lambda event: print('FocusIn event generated.'))
app.bind('<BackSpace>', lambda event: print(event.keysym, 'event generated.'))
app.event_generate('<BackSpace>')
app.update() # Position 2
以下使用when='tail'
的代码从不打印“生成的BackSpace事件”。 app.update
是在第1位还是第2位。
import tkinter as tk
app = tk.Tk()
app.update() # Position 1
app.bind('<FocusIn>', lambda event: print('<FocusIn> event generated.'))
app.bind('<BackSpace>', lambda event: print(event.keysym, 'event generated.'))
app.event_generate('<BackSpace>', when="tail")
# app.update() # Position 2
答案 0 :(得分:2)
我无法复制您的观察结果,所以我无法肯定地说明发生了什么。显然有一些代码丢失了,这可能也会受到您运行的平台以及启动程序的影响。
但是,我认为问题归结为三个因素:
event_generate
会立即处理该事件的所有处理程序(即:update
并且mainloop
不需要本身)update()
之前调用event_generate
时,未绘制窗口,并且未绘制窗口时操作系统或窗口管理器不会给它键盘焦点。 情况可能并非完全如此 - 因为您告诉它哪个窗口是接收事件,焦点可能不是一个考虑因素。然而,窗户的可见性仍然可以发挥作用。可能是tkinter逻辑说忽略不可见窗口上的事件。您的窗口管理器/操作系统也可能没有在前端运行程序 - 键盘焦点可能在某个其他应用程序上,直到您手动单击窗口(例如,这似乎是OSX上的行为)。 / p>
您可以尝试将when
参数用于event_generate
。这使您可以处理处理程序,直到处理完任何其他排队事件。这样做,然后调用update()
,也许您的代码可以正常工作。例如:
app.event_generate('<Backspace>`, when="tail")
app.update()
在尝试生成活动之前,您可能还会尝试通过调用app.focus_force()
强制将应用置于前台。
生成键盘事件时,您可能还想先生成<FocusIn>
事件。当您开始生成事件时,您需要确保您生成的事件的行为与用户生成的事件尽可能相似,这意味着您需要了解可见性,键盘焦点和鼠标焦点。很多年前,当我走这条路时,我记得在处理按钮时必须生成<Enter>
和<Leave>
事件,例如,因为内置绑定有时依赖于这些设置按钮的状态“有效的”。
event_generate
命令的权威文档是Tcl/Tk man page。