[Matplotlib-users] Key Press and Key Release Events in TkInter

Gregory Key gregk3172 at outlook.com
Fri Feb 3 13:40:55 EST 2017


Sorry about that! The line 'timer1.add_callback(scroll)' has to be in
the on_key_pressed function.

Here is the code that really does work on my machine:

"""
Created on Thu Feb  2 07:22:19 2017
adapted from a matplotlib example
"""

import matplotlib
matplotlib.use('tkagg')
import matplotlib.pyplot as plt

key_pressed = 0
key_released = 0


def on_key_press(event):
    """
    Look for a right or left arrow key.
    If it is the first key press start the timer.
    Increment the key_pressed counter.
    """
    global key_pressed
    global key_released

    if event.key not in ('right', 'left'):
        return
    if key_pressed is 0:
        print('starting timer')
        timer1.start(interval=30)
        timer1.add_callback(scroll)
    key_pressed += 1
    print('\ninside onpress')
    print('key_pressed =', key_pressed)
    print('key_released =', key_released)


def on_key_release(event):
    """
    All this does is increment the key_released counter.
    """
    global key_pressed
    global key_released

    if event.key not in ('right', 'left'):
        return
    key_released += 1
    print('\ninside onrelease')
    print('key_pressed =', key_pressed)
    print('key_released =', key_released)


def scroll():
    """
    Scroll the data cursor or something
    """
    global key_pressed
    global key_released

    print('\ninside scroll')
    print('key_pressed =', key_pressed)
    print('key_released =', key_released)
    if key_pressed is key_released:
        print('\ntimer stopped')
        key_pressed = 0      # reset the counters for next keypress
        key_released = 0
        # returning False stops the timer
        return False

fig = plt.figure()
fig.canvas.mpl_connect('key_press_event', on_key_press)
fig.canvas.mpl_connect('key_release_event', on_key_release)
timer1 = fig.canvas.new_timer()
# This has to be reset inside the on_key_press function
#timer1.add_callback(scroll) 

plt.show()

On Fri, 2017-02-03 at 18:32 +0000, Gregory Key wrote:
> I got excited too quickly. Searching the internet for 'key debounce
> in
> tkinter' did indeed returned several hits with sample code, some of
> them very elaborate. The problem is none of them worked on my
> computer!
> From Joe's previous comments and the samples I found I finally got
> inspiration. As usual with Python and matplotlib the solution turned
> out to be simple. Using the TkAgg backend on my computer and holding
> down a key fires a continuous stream of key_pressed and key_released
> events as long as the key is down. The solution was to let the first
> key_pressed event start a timer whose callback performs the task I
> want
> done, then I let the automatic key_pressed and key_released events
> just
> increment counters. In the timer callback I check for equality of the
> two counters. After the final key_release the counters will be equal
> so
> I stop the timer and reset the counters. Depending on the timer
> interval and the key repeat rate there are times that the callback
> falls between the key_press and the key_release which causes the
> callback to stop the timer but if the key is still down the next
> key_press event just starts the timer and it's callback again and
> keeps
> going without any noticeable hesitation.
> The Python code that works on my computer is shown below:
> 
> """
> Created on Thu Feb  2 07:22:19 2017
> adapted from a matplotlib example
> """
> 
> import matplotlib
> matplotlib.use('tkagg')
> import matplotlib.pyplot as plt
> 
> key_pressed = 0
> key_released = 0
> 
> 
> def on_key_press(event):
>     """
>     Look for a right or left arrow key.
>     If it is the first key press start the timer.
>     Increment the key_pressed counter.
>     """
>     global key_pressed
>     global key_released
> 
>     if event.key not in ('right', 'left'):
>         return
>     if key_pressed is 0:
>         print('starting timer')
>         timer1.start(interval=30)
>     key_pressed += 1
>     print('\ninside onpress')
>     print('key_pressed =', key_pressed)
>     print('key_released =', key_released)
> 
> 
> def on_key_release(event):
>     """
>     All this does is increment the key_released counter.
>     """
>     global key_pressed
>     global key_released
> 
>     if event.key not in ('right', 'left'):
>         return
>     key_released += 1
>     print('\ninside onrelease')
>     print('key_pressed =', key_pressed)
>     print('key_released =', key_released)
> 
> 
> def scroll():
>     """
>     Scroll the data cursor or something
>     """
>     global key_pressed
>     global key_released
> 
>     print('\ninside scroll')
>     print('key_pressed =', key_pressed)
>     print('key_released =', key_released)
>     if key_pressed is key_released:
>         print('\ntimer stopped')
>         key_pressed = 0      # reset the counters for next keypress
>         key_released = 0
>         # returning False stops the timer
>         return False
> 
> fig = plt.figure()
> fig.canvas.mpl_connect('key_press_event', on_key_press)
> fig.canvas.mpl_connect('key_release_event', on_key_release)
> timer1 = fig.canvas.new_timer()
> timer1.add_callback(scroll)
> 
> plt.show()
> 
> Greg Key
> 
> On Fri, 2017-02-03 at 02:26 +0000, Gregory Key wrote:
> > Bingo! Searching for 'key debounce in tkinter' was what I needed. I
> > think I have found a solution. Thanks!
> > 
> > Greg Key
> > 
> > On Thu, 2017-02-02 at 21:35 +0000, Gregory Key wrote:
> > > So basically in tkinter the key_release_event is useless.
> > > 
> > > Thanks I'll do some experimenting with the information you have
> > > given
> > > me.
> > > 
> > > On Thu, 2017-02-02 at 14:07 -0600, Joe Kington wrote:
> > > > That's a common "gotcha" when trying to detect a held key on a
> > > > keyboard.  Your operating system (or the actual hardware in
> > > > your
> > > > keyboard in some cases) interprets a held key as multiple
> > > > keypresses
> > > > and fires off events accordingly (e.g., that's why holding down
> > > > "a"
> > > > will give "aaaaaaaaa" when typing).
> > > > 
> > > > I think Qt handles this automatically, but I could be wrong. Tk
> > > > doesn't do it automatically.
> > > > 
> > > > Usually, you'd detect a held key by keeping track of the either
> > > > the
> > > > last key press event or the time since the last keypress event.
> > > >  "Debouncing" is the term you'll want to search for.  In
> > > > tkinter,
> > > > you
> > > > can bind a function to fire after idle (effectively checking if
> > > > the
> > > > key was ever released).  Alternatively, for the matplotlib
> > > > side,
> > > > I
> > > > think you can bind to the idle event and do the same thing
> > > > without
> > > > needing to rely on anything tkinter-specific (Untested).
> > > > 
> > > > Hope that helps a bit, anyway.
> > > > -Joe
> > > > 
> > > > On Tue, Jan 31, 2017 at 3:05 PM, Gregory Key <gregk3172 at outlook
> > > > .c
> > > > om
> > > > > 
> > > > 
> > > > wrote:
> > > > > I am running Python 3.5.2 and MatPlotLib 2.0.0 on Ubuntu
> > > > > 16.10.
> > > > > 
> > > > > I am developing a program that uses matplotlib embedded in
> > > > > tkinter
> > > > > to
> > > > > plot vibration data in a bode plot, phase and amplitude
> > > > > versus
> > > > > rotor
> > > > > speed. I adapted the data browser given in the matplotlib
> > > > > documentation
> > > > >             as example 91.2 data_browser.py to browse the
> > > > > data.
> > > > > The
> > > > > browser worked but I wanted to modify it so that holding down
> > > > > the
> > > > > next
> > > > > or previous key would scroll through the data instead of
> > > > > having
> > > > > to
> > > > > continously press and release the keys. My plan was to use
> > > > > the
> > > > > key_press_event to start a timer which would call a scroll
> > > > > method
> > > > > and
> > > > > then use the key_release event to stop the timer and stop
> > > > > scrolling. I
> > > > > couldn't make this scheme work so I did some investigating on
> > > > > the
> > > > > key_press_event and key_release_event in tkinter. I used
> > > > > example
> > > > > 91.5
> > > > > keypress_demo.py given in the matplotlib documentation but I
> > > > > added
> > > > > a
> > > > > key_release_event method to it. What I found was that the key
> > > > > events
> > > > > don't work the way I would expect them to work. If you press
> > > > > and
> > > > > release a key things work as expected. When a key is pressed
> > > > > the
> > > > > key_press_event fires and when it is released the
> > > > > key_release_event
> > > > > fires. If a key is pressed and held however the
> > > > > key_press_event
> > > > > fires
> > > > > followed immediately by a key_release_event even though the
> > > > > key
> > > > > has
> > > > > not
> > > > > been released. As long as the key is held down it will
> > > > > continue
> > > > > to
> > > > > fire
> > > > > key_press_event followed by key_release_event. Is this the
> > > > > way
> > > > > it
> > > > > is
> > > > > supposed to work?
> > > > > 
> > > > > Thanks
> > > > > Greg Key
> > > > > _______________________________________________
> > > > > Matplotlib-users mailing list
> > > > > Matplotlib-users at python.org
> > > > > https://mail.python.org/mailman/listinfo/matplotlib-users
> > > > > 
> > > > 
> > > > 
> > > 
> > > _______________________________________________
> > > Matplotlib-users mailing list
> > > Matplotlib-users at python.org
> > > https://mail.python.org/mailman/listinfo/matplotlib-users
> > 
> > _______________________________________________
> > Matplotlib-users mailing list
> > Matplotlib-users at python.org
> > https://mail.python.org/mailman/listinfo/matplotlib-users
> 
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users at python.org
> https://mail.python.org/mailman/listinfo/matplotlib-users


More information about the Matplotlib-users mailing list