我希望我的Tkinter(Tk 8.6)程序在程序启动时保持Shift时表现不同。
我知道如何检查鼠标和键盘事件中的state
属性,但即使用户没有引起任何事件,我的检测也需要工作。
我尝试了<Configure>
和<FocusIn>
个事件,但他们的state
属性始终为'??'
。我尝试生成虚拟事件,但其state
属性始终为0
。
有没有办法从Tk解释器查询此信息?
答案 0 :(得分:0)
A window can only receive key events when it's focused:
KeyPress和KeyRelease事件被发送到当前具有键盘焦点的窗口。
Widget.focus_set()
已证明失败。这是有意识地阻止focus stealing的努力。要覆盖此内容,使用Widget.focus_force()
(委托给focus -force
)。
请注意用户需要在用于启动应用程序的Enter或鼠标单击后按Shift键 - 否则,它被视为该输入的一部分。在Windows中,我向Spy ++确认应用程序的窗口在这种情况下永远不会收到键盘事件,即使它得到了关注。 .Net's logic to get key state delegates to GetKeyState
也通过窗口消息判断。
然后:
<KeyPress-Shift_L>
和/或<KeyPress-Shift_R>
来检测Shift键的按下(“Shift
”不起作用,它只能是修饰符。)unbind
按键处理程序重复KeyPress
个事件。概念验证应用:
import Tkinter as tkinter
class HoldKeyDetect(object):
def __init__(self, widget, keys, handler=None):
"""Detect holding `keys` in `widget`"""
self.widget = widget
self.handler = handler
self.binds = {}
for key in keys:
evid = '<KeyPress-%s>'%key
self.binds[evid] = widget.bind(evid,self.keypress)
def __del__(self):
try: self.unbind()
except tkinter.TclError: pass #app has been destroyed
def unbind(self):
while True:
try: evid,fid = self.binds.popitem()
except KeyError: break
self.widget.unbind(evid, fid)
def keypress(self,e):
try:
if self.handler:
self.handler(e)
finally:
self.unbind()
class App(object):
def __init__(self,root):
self.root = root
root.focus_force()
self.h = HoldKeyDetect(root,("Shift_L","Shift_R"),self.set_mode)
root.after(1000, # larger than keypress repeat interval + code overhead
self.continue_)
self.mode = False
def go(self):
self.root.mainloop()
def set_mode(self,_):
print "Shift mode set"
self.mode = True
def continue_(self):
del self.h
print "Mode=", self.mode
self.root.destroy()
if __name__ == '__main__':
App(tkinter.Tk()).go()