TkInter按键,键盘释放事件

时间:2014-11-30 16:19:43

标签: python tkinter

据我所知Tk按键和键释放事件只是在实际按下或释放按键时触发?

然而,如果我按下" a"密钥我得到一系列连续的按键/密钥释放事件。

我做错了什么还是TkInter越野车?这是关于Linux的Python2.7。

from Tkinter import *
def keyup(e):
    print 'up', e.char
def keydown(e):
    print 'down', e.char

root = Tk()
frame = Frame(root, width=100, height=100)
frame.bind("<KeyPress>", keydown)
frame.bind("<KeyRelease>", keyup)
frame.pack()
frame.focus_set()
root.mainloop()

按住&#34; a&#34;:

时的输出
down a
up a
down a
up a
down a
up a
down a
up a
etc...

5 个答案:

答案 0 :(得分:16)

好的更多研究发现this helpful post表明这是由于X的自动重复行为而发生的。您可以使用

禁用此功能
os.system('xset r off')

然后使用脚本末尾的“on”重置它。 问题是这是全局行为 - 不仅仅是我的脚本 - 这不是很好,所以我希望有人能想出更好的方法。

答案 1 :(得分:3)

自动重复行为取决于系统。在Win7中,

down a
down a
down a
...
down a
up a

这不到一秒钟。

答案 2 :(得分:1)

怎么样;

from Tkinter import *

wn = Tk()
wn.title('KeyDetect')

m = 0

def down(e):
    if m == 0:
        print 'Down\n', e.char, '\n', e
        global m
        m = 1

def up(e):
    if m == 1:
        print 'Up\n', e.char, '\n', e
        global m
        m = 0

wn.bind('<KeyPress>', down)
wn.bind('<KeyRelease>', up)

wn.mainloop()

现在它不会重演。

答案 3 :(得分:1)

嗯,这有点迟了,但是我有一个可行的解决方案。这不是很好,但是它不需要os.system覆盖系统设置,这很好。

基本上,我制作了一个记录按键时间的类。我说是在最近的短时间内(这里是.1ms)按下了一个键。要获得按下,这很容易:如果按键未注册为按下,则触发事件。对于发行版,逻辑更难:如果存在可疑的发行事件,则将计时器设置为短时间(此处为.1s),然后检查以确保密钥没有按下。

验证了新闻稿或发布稿后,请在代码中调用on_key_press或on_key_release方法。对于这些,只需按照您最初想要的方式实现即可

我知道这并不完美,但希望对您有帮助!

代码如下:

您要在其中初始化按键事件的地方:

key_tracker = KeyTracker()
window.bind_all('<KeyPress>', key_tracker.report_key_press)
window.bind_all('<KeyRelease>', key_tracker.report_key_release)
key_tracker.track('space')

这是我自定义的KeyTracker类:​​

class KeyTracker():
    key = ''
    last_press_time = 0
    last_release_time = 0

    def track(self, key):
        self.key = key

    def is_pressed(self):
        return time.time() - self.last_press_time < .1

    def report_key_press(self, event):
        if event.keysym == self.key:
            if not self.is_pressed():
                on_key_press(event)
            self.last_press_time = time.time()

    def report_key_release(self, event):
        if event.keysym == self.key:
            timer = threading.Timer(.1, self.report_key_release_callback, args=[event])
            timer.start()

    def report_key_release_callback(self, event):
        if not self.is_pressed():
            on_key_release(event)
        self.last_release_time = time.time()

答案 4 :(得分:0)

诀窍是跟踪一个键有一个键按下的事实,哪些键当前被按下,以及不再有键按下的事实。一直无视键盘中继器。

这个小原型应该涵盖所有基础:

#Key press prototype
#Tracks keys as pressed, ignoring the keyboard repeater
#Current keys down are kept in a dictionary.
#That a key is pressed is flagged, and the last key pressed is tracked

import tkinter

winWid = 640
winHei = 480
keyDown = False
lastKey = "none"
keyChange = keyDown
keyList = {}

def onKeyDown(event):
    global keyDown, lastKey, keyList
    if (event.char in keyList) != True:
        keyList[event.char] = "down"
        print(keyList)
    keyDown = True
    lastKey = event.char

def onKeyUp(event):
    global keyDown
    if (event.char in keyList) == True:
        keyList.pop(event.char)
    if len(keyList) == 0:
        keyDown = False
    print(keyList)
    
#onTimer is present to show keyboard action as it happens. 
#It is not needed to track the key changes, and it can be 
#removed.
def onTimer(): 
    global keyChange, timerhandle
    if keyDown != keyChange:
        keyChange = keyDown
        if keyDown:
            print("Key down, last key pressed - " + lastKey)
        else:
            print("Key up, last key pressed - " + lastKey)
    timerhandle = window.after(20,onTimer)
    
def onShutdown():
    window.after_cancel(timerhandle)
    window.destroy()    

window = tkinter.Tk()
frame = tkinter.Canvas(window, width=winWid, height=winHei, bg="black")
frame.pack()

frame.bind("<KeyPress>", onKeyDown)
frame.bind("<KeyRelease>", onKeyUp)
frame.focus_set()

timerhandle = window.after(20,onTimer)
window.protocol("WM_DELETE_WINDOW",onShutdown)
window.mainloop()
相关问题