I have a simple ui, which should print every key that I've pressed.
I need to generate signal once per real key-press.
How can I achieve that?
In default, tkinter generates signal once, than waits about 0.5 sec and starts generate signal in loop, until KeyRelease event happens.
if __name__ == '__main__':
from tkinter import Tk, Frame
root = Tk()
frame = Frame(root, width=200, height=200, bg="white")
frame.pack()
def key_handler(event):
print(event.char, event.keysym, event.keycode)
return 'break'
root.bind('<Key>', key_handler)
root.mainloop()
Using 'break' at the end of the bond function doesn't stop the next event-call.
In addition (bc this is a minor question, which is too small for separate post), how can I create these key sequences?:
- "Shift" and some digit
- some digit and '+' or '-' symbol
UPD: I don't really want to do this:
def key_handler(event):
global eve
if eve != event.keysym:
eve = event.keysym
print(event.char, event.keysym, event.keycode)
because signal still process when I want to remove it at all. But, I don't really know how much affect does Dummy signal on the program in total, so may be this solution makes sense?
UPD with some solutions from users:
I've append the answer in question body because I've accidentally closed the question before adding my answer, so here it is:
Here is the example with bind/unbind solution:
class KeyHandler:
def __init__(self, key: str):
self.func_id = root.bind(f'<KeyPress-{key}>', self.key_press)
root.bind(f'<KeyRelease-{key}>', self.key_release)
def key_release(self, event: Event):
print('released', event.char)
self.func_id = root.bind(f'{event.char}', self.key_press)
def key_press(self, event: Event):
print('pressed', event.char)
root.unbind(f'{event.char}', self.func_id)
KeyHandler('1')
KeyHandler('2')
KeyHandler('3')
KeyHandler('4')
root.mainloop()
And here is the example with simple state check solution (handling all events which are connected with current key, may cause event spam):
keys = []
def key_handler(event: Event):
global keys
if event.type is EventType.KeyPress:
if not (event.keycode in keys):
keys.append(event.keycode)
print('pressed', event.char)
elif event.type is EventType.KeyRelease:
if event.keycode in keys:
print('released', event.char)
keys.remove(event.keycode)
root.bind('<KeyPress-9>', lambda e: key_handler(e))
root.bind('<KeyRelease-9>', lambda e: key_handler(e))
The problem is that tkinter can't distinguish between a single press and press-and-hold. At least, not on some systems. It could be that it's your keyboard that is passing multiple events to tkinter. That is to say, tkinter has no way to guarantee you'll only get a single press and release when the user holds a key down.
You're going to have to come up with some sort of logic to decide what is a unique, intentional keypress and what is not. You can either only report when a keypress is different from the one before, or only report a keypress if some time passes between identical keypresses, or something like that.
Without knowing what you expect to happen when a user presses and holds a key for an extended amount of time, it's hard to be more specific.