Python TkInter 按键、按键释放事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27215326/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 01:31:44  来源:igfitidea点击:

TkInter keypress, keyrelease events

pythontkinter

提问by lost

I understood that the Tk keypress and keyrelease events were supposed only to fire when the key was actually pressed or released?

我知道 Tk keypress 和 keyrelease 事件应该只在实际按下或释放键时触发?

However with the following simple code, if I hold down the "a" key I get a continual sequence of alternating keypress/keyrelease events.

但是,通过下面的简单代码,如果我按住“a”键,我会得到一个连续的按键/按键释放事件交替序列。

Am I doing something wrong or is TkInter buggy? This is Python2.7 on Linux mint.

我做错了什么还是 TkInter 有问题?这是 Linux mint 上的 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()

Output when pressing and holding "a":

按住“a”时的输出:

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

回答by lost

Ok some more research found this helpful postwhich shows this is occuring because of X's autorepeat behaviour. You can disable this by using

好的,更多的研究发现这个有用的帖子表明这是由于 X 的自动重复行为而发生的。您可以使用禁用此功能

os.system('xset r off')

and then reset it using "on" at the end of your script. The problem is this is global behaviour - not just my script - which isn't great so I'm hoping someone can come up with a better way.

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

回答by Terry Jan Reedy

Autorepeat behavior is system dependent. In Win7,

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

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

This is for less than a second.

这是不到一秒钟。

回答by Terry Jan Reedy

how about;

怎么样;

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()

now it won't repeat.

现在它不会重复了。

回答by Artur Hawkwing

Well, this is a bit late now, but I have a solution that works. It's not great, but it does not require os.system overwriting system settings, which is nice.

好吧,现在有点晚了,但我有一个有效的解决方案。这不是很好,但它不需要 os.system 覆盖系统设置,这很好。

Basically, I make a class that records the timing of key presses. I say that a key is down when it has been pressed in the last short amount of time (here, .1ms). To get a press, it is easy enough: if the key is not registered as pressed, trigger the event. For releases, the logic is harder: if there is a suspected release event, set a timer for a short time (here, .1s) and then check to make sure the key is not down.

基本上,我制作了一个记录按键时间的类。我说一个键在最后很短的时间内被按下时(这里是 0.1 毫秒)。要获得按下,很容易:如果键未注册为按下,则触发事件。对于释放,逻辑更难:如果有一个可疑的释放事件,设置一个很短的时间(这里是 0.1 秒)的计时器,然后检查以确保键没有按下。

Once you have validated a press or release, call the on_key_press or on_key_release methods in your code. As for those, just implement them the way you originally wanted them

验证新闻或发布后,请在代码中调用 on_key_press 或 on_key_release 方法。至于那些,只需按照您最初想要的方式实现它们

I know this is not perfect, but I hope it helps!!

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

Here is the code:

这是代码:

Where you are initializing keypress events:

您在哪里初始化按键事件:

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')

Here is my custom KeyTracker class:

这是我的自定义 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()