TkInter keypress, keyrelease events
Я понял, что события нажатия клавиш и keyrelease Tk должны были срабатывать только при нажатии или отпускании клавиши?
Однако со следующим простым кодом, если я удерживаю клавишу "a", я получаю непрерывную последовательность чередующихся событий нажатия клавиш /keyrelease.
Я делаю что-то неправильно или TkInter багги? Это Python2.7 на Linux mint.
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()
Выход при нажатии и удержании "a":
down a
up a
down a
up a
down a
up a
down a
up a
etc...
Ответы
Ответ 1
Хорошо, еще несколько исследований нашли этот полезный пост, который показывает, что это происходит из-за поведения автоповтора X. Вы можете отключить его, используя
os.system('xset r off')
а затем reset, используя "on" в конце вашего script.
Проблема в том, что это глобальное поведение, а не только мой script - который не очень велик, поэтому я надеюсь, что кто-то может придумать лучший способ.
Ответ 2
Автоповторное поведение зависит от системы. В Win7,
down a
down a
down a
...
down a
up a
Это меньше секунды.
Ответ 3
как насчет;
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()
теперь он не будет повторяться.
Ответ 4
Ну, сейчас уже немного поздно, но у меня есть решение, которое работает. Это не здорово, но не требует перезаписи системных настроек os.system, что приятно.
По сути, я делаю класс, который записывает время нажатия клавиш. Я говорю, что клавиша не работает, когда она была нажата в последний короткий промежуток времени (здесь, 0,1 мс). Чтобы получить нажатие, это достаточно просто: если кнопка не зарегистрирована как нажатая, вызвать событие. Для выпусков логика сложнее: если есть подозреваемое событие выпуска, установите таймер на короткое время (здесь,.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
waiting_to_test_release = False
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():
print('press')
on_key_press(event)
self.last_press_time = time.time()
def report_key_release(self, event):
if event.keysym == self.key:
if not self.waiting_to_test_release:
timer = threading.Timer(.1, self.report_key_release_callback, args=[event])
timer.start()
print(time.time())
def report_key_release_callback(self, event):
print(time.time())
print()
if not self.is_pressed():
print('rel')
on_key_release(event)
self.last_release_time = time.time()