Обработка одновременного нажатия двух клавиш
Я кажется немного понял на что python ругается, но до сих пор ломаю голову.
RuntimeWarning: coroutine 'move_ka' was never awaited self.tk.mainloop(n)
сам код небольшой, признаюсь(я еще никогда не работал с этой библиотекой)
Почему она мне понадобилась?
Потому что когда я нажимаю две клавиши то ничего не происходит, так как работает только если одну клаву нажму (из кода сразу видно)
from tkinter import Tk, Canvas, PhotoImage
root = Tk()
root.geometry('700x500')
root.resizable(False,False)
canvas = Canvas(root, width=300, height=400)
canvas.pack()
my_obj = PhotoImage(file= здесь моя картинка)
id_img = canvas.create_image(50,50,anchor='c',image=my_obj) #Создаем картинку
async def move_ka(event):
if event.keysym == 'Left':
canvas.move(id_img, -4, 0)
async def move_ka2(event):
if event.keysym == 'Right':
canvas.move(id_img, 4, 0)
canvas.bind_all('<KeyPress-Left>', move_ka) #При нажатии вызываем функцию
canvas.bind_all('<KeyPress-Right>', move_ka2)
root.mainloop()
Сразу скажу что я думаю это происходит из-за root.mainloop() подскажите пожалуйста, НО другие ссылки прошу не кидать, я гуглил более часа!
Ответы (1 шт):
Почему она мне понадобилась?
Потому что когда я нажимаю две клавиши то ничего не происходит, так как работает только если одну клаву нажму (из кода сразу видно)
Во-первых, Tkinter сам по себе не умеет работать с асинхронными функциями, но просто замена обычных обработчиков на асинхронные тут и не поможет. В лучшем случае при одновременном зажатии кнопок доска будет "дергаться" вправо-влево, в худшем - последняя зажатая клавиша будет постоянно генерировать повторяющиеся события нажатия и доска будет двигаться по последней нажатой клавише.
Чтобы решить проблему, нужно отслеживать отдельно события нажатия и отпускания клавиш (т.е., если две кнопки были нажаты, но не были отпущены, значит в данный момент они нажаты вместе).
В данном случае можно в глобальных переменных хранить состояния клавиш, периодически их проверять, от их состояния менять скорость движения, например, при нажатой кнопке "влево" вычитать из скорости 4, при нажатой кнопке "вправо" - прибавлять 4, потом перемещать доску на полученное в сумме значение. В итоге, при одновременном зажатии кнопок "вправо" и "влево" скорость будет равна нулю, доска никуда не будет двигаться.
from tkinter import Tk, Canvas, PhotoImage
root = Tk()
root.geometry('700x500')
root.resizable(False,False)
canvas = Canvas(root, width=300, height=400)
canvas.pack()
# my_obj = PhotoImage(file= здесь моя картинка)
# id_img = canvas.create_image(50,50,anchor='c',image=my_obj) #Создаем картинку
id_img = canvas.create_rectangle(50, 50, 100, 60)
# Клавиши изначально не нажаты
left = False
right = False
def left_pressed(event):
global left
left = True
def left_released(event):
global left
left = False
def right_pressed(event):
global right
right = True
def right_released(event):
global right
right = False
def move():
# Периодически перемещаем доску на vel (скорость)
vel = -4 * left + 4 * right # (нажатая клавиша "Влево" добавляет к скорости -4, "Вправо" - +4)
canvas.move(id_img, vel, 0)
root.after(50, move) # Повторить перемещение через 50 мс
move()
canvas.bind_all('<KeyPress-Left>', left_pressed)
canvas.bind_all('<KeyRelease-Left>', left_released)
canvas.bind_all('<KeyPress-Right>', right_pressed)
canvas.bind_all('<KeyRelease-Right>', right_released)
root.mainloop()
Более универсально - запоминать вообще все нажатые или отпущенные клавиши в множестве: при нажатии добавлять в множество, при отпускании - удалять из него. Скорость вычисляем через наличие "Left" или "Right" в этом множестве.
...
# Клавиши изначально не нажаты
pressed_keys = set()
def key_pressed(event):
pressed_keys.add(event.keysym)
def key_released(event):
pressed_keys.remove(event.keysym)
def move():
vel = -4 * ("Left" in pressed_keys) + 4 * ("Right" in pressed_keys)
canvas.move(id_img, vel, 0)
root.after(50, move) # Повторить перемещение через 50 мс
move()
canvas.bind_all('<KeyPress>', key_pressed)
canvas.bind_all('<KeyRelease>', key_released)
root.mainloop()