TkInter keypress, keyrelease events

后端 未结 4 1785
野性不改
野性不改 2020-12-01 11:52

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

However with the following simple c

相关标签:
4条回答
  • 2020-12-01 12:29

    Autorepeat behavior is system dependent. In Win7,

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

    This is for less than a second.

    0 讨论(0)
  • 2020-12-01 12:32

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

    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.

    0 讨论(0)
  • 2020-12-01 12:35

    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.

    0 讨论(0)
  • 2020-12-01 12:45

    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.

    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.

    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

    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:

    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()
    
    0 讨论(0)
提交回复
热议问题