Как я могу добиться ГЛАДКОГО движения элемента холста в Tkinter?

Я пытаюсь поиграть с событиями, управляемыми клавиатурой, в Tkinter, чтобы я мог перемещать объект вокруг виджета холста. Вверх, вниз, влево и вправо работают нормально, но когда я пытаюсь запрограммировать две клавиши вместе, движение не является плавным диагональным движением. Кроме того, всякий раз, когда нажимается клавиша, объект перемещается, затем происходит небольшая задержка, а затем он движется плавно. Как я могу добиться плавного движения В МОМЕНТ нажатия клавиши и как я могу добиться плавного диагонального движения?

Это код до сих пор:

from tkinter import *

x = 10
y = 10
a = 100
b = 100

def change_coord(event):
        if event.keysym == 'Up':
            canvas1.move(rect, 0,-5)
        if event.keysym == 'Up' and 'Right':
            canvas1.move(rect, 5,-5)
        if event.keysym == 'Up' and 'Left':
            canvas1.move(rect, -5,-5)
        if event.keysym == 'Down':
            canvas1.move(rect, 0,5)
        if event.keysym == 'Down' and 'Right':
            canvas1.move(rect, 5,5)
        if event.keysym == 'Down' and 'Left':
            canvas1.move(rect, -5,5)
        if event.keysym == 'Right':
            canvas1.move(rect, 5,0)
        if event.keysym == 'Left':
            canvas1.move(rect, -5,0)

window = Tk()
window.geometry("400x200")

#canvas and drawing
canvas1=Canvas(window, height = 200, width = 400)
canvas1.grid(row=0, column=0, sticky=W)
coord = [x, y, a, b]
rect = canvas1.create_rectangle(*coord, outline="#fb0", fill="#fb0")

#capturing keyboard inputs and assigning to function
window.bind_all('<Up>', change_coord)
window.bind_all('<Down>', change_coord)
window.bind_all('<Left>', change_coord)
window.bind_all('<Right>', change_coord)
window.mainloop()

Большое спасибо!

ИЗМЕНИТЬ:

Спасибо за все ваши предложения. Я пытался реализовать цикл анимации, чтобы обойти небольшую задержку после нажатия клавиши со стрелкой, но теперь застрял. Мой НОВЫЙ код показан ниже, но запуск программы не приводит к перемещению элемента холста. Во-первых, верна ли идея цикла анимации, а во-вторых, где мне вызвать функцию «переместить», чтобы элемент двигался. Пожалуйста, помогите - спасибо!

from tkinter import *

x = 10
y = 10
a = 100
b = 100
direction = None

def move():
    global x_vel
    global y_vel
    global direction
    if direction is not None:
        canvas1.move(rect, x_vel,y_vel)
        after(33,move)

def on_keypress(event):
    global direction
    global x_vel
    global y_vel
    if event.keysym == "Left":
        direction == "left"
        x_vel = -5
        y_vel = 0
    if event.keysym == "Right":
        direction == "right"
        x_vel = 5
        y_vel = 0
    if event.keysym == "Down":
        direction == "down"
        x_vel = 0
        y_vel = 5
    if event.keysym == "Up":
        direction == "up"
        x_vel = 0
        y_vel = -5

def on_keyrelease(event):
    global direction
    direction = None


window = Tk()
window.geometry("400x200")

#canvas and drawing
canvas1=Canvas(window, height = 200, width = 400)
canvas1.grid(row=0, column=0, sticky=W)
coord = [x, y, a, b]
rect = canvas1.create_rectangle(*coord, outline="#fb0", fill="#fb0")

#capturing keyboard inputs and assigning to function
window.bind_all('<KeyPress>', on_keypress)
window.bind_all('<KeyRelease>', on_keyrelease)
window.mainloop()

person sw123456    schedule 30.09.2014    source источник
comment
Создайте переменные velocity_x и velocity_y, которые определяют, насколько прямоугольник должен перемещаться в каждом кадре. События Keydown и keyup должны изменять скорость, а не позицию. Между прочим, event.keysym == 'Down' and 'Right' делает не то, что вы думаете; a == b and c эквивалентно (a == b) and c, а не a == (b and c) или a == (b + c).   -  person Kevin    schedule 30.09.2014
comment
Задержка между первым действием и плавными движениями, вероятно, связана с драйвером клавиатуры. Когда вы нажимаете клавишу, драйвер некоторое время ждет, прежде чем передать событие клавиши, связанное с этой клавишей. Этот параметр называется Задержка повтора в Windows и Задержка клавиатуры в Linux. Вы можете попытаться изменить эти значения, но это может повлиять на удобство использования клавиатуры для других приложений. Обычный обходной путь — запустить таймер зацикливания при нажатии клавиши и остановить его при нажатии кнопки KeyRelease.   -  person FabienAndre    schedule 30.09.2014
comment
Спасибо, парни. Кевин, корю себя за свою школьную ошибку в использовании И! Я идиот. Что касается скорости, а не положения, не могли бы вы добавить пример, чтобы показать, что вы имеете в виду, потому что разве значения 5 и -5 в любом случае не действуют как скорость? Увеличение или уменьшение этих значений изменит скорость объекта? Извините, если я туплю. Спасибо, Фабьен-Андре. Ценить это   -  person sw123456    schedule 30.09.2014
comment
ФабьенАндре, здесь я дерзок, но не могли бы вы привести пример времени зацикливания, логика имеет смысл, но ее трудно реализовать правильно. Я добавил цикл while при нажатии, который прерывается при выпуске, но моя программа продолжает зависать. Извините и заранее спасибо.   -  person sw123456    schedule 30.09.2014
comment
Никаких бесконечных циклов, пожалуйста. У вас нет возможности получать новые события, пока вы не покинете обработчик событий, поэтому он никогда не вернется.   -  person user3757614    schedule 01.10.2014


Ответы (1)


Привязка к основным клавишам - неправильный способ сделать это. Вместо этого привяжите к нажатой клавише и отпусканию клавиши и используйте это для создания словаря нажатых клавиш. Каждые N мс запускайте функцию, которая использует этот словарь, чтобы определить, как перемещать объект. (Я не уверен, что таймер Tkinter обладает достаточным качеством, чтобы сделать это правильно.)

Обязательно очистите словарь, если программа теряет фокус.

person user3757614    schedule 30.09.2014