Tkinter не распознает нажатия клавиш - PullRequest
0 голосов
/ 04 ноября 2019

Я пытаюсь написать программу так, чтобы по экрану двигался автомобиль, а клавиши со стрелками вверх и вниз могли изменять скорость автомобиля. Однако, когда я нажимаю любую клавишу, ни одна из команд не вызывается. Я попытался изменить линии bind_all и focus на self.canvas, но это тоже не сработало. Как я могу это исправить?

class racingCar:
    def __init__(self):
        window = Tk()
        window.title("Racing Car")

        self.cWidth = 500
        self.cHeight = 200
        self.canvas = Canvas(window, width = self.cWidth, height = self.cHeight, bg = "white")
        self.canvas.pack()

        self.x = 0
        self.y = self.cHeight
        self.drawCar(self.x, self.y)

        self.dx = 5
        self.sleepTime = 50
        self.animate()

        window.bind_all("<Up>", self.increaseSpeed)
        window.bind_all("<Down>", self.decreaseSpeed)
        window.focus()

        window.mainloop()

    def drawCar(self, x, y):
        self.canvas.create_rectangle(x, y - 20, x + 50, y - 10, fill = "yellow", tags = "car")
        self.canvas.create_oval(x + 10, y - 10, x + 20, y, fill = "black", tags = "car")
        self.canvas.create_oval(x + 30, y - 10, x + 40, y, fill = "black", tags = "car")
        self.canvas.create_polygon([x + 10, y - 20, x + 20, y - 30, x + 30, y - 30, x + 40, y - 20], fill = "blue", tags = "car")

    def increaseSpeed(self, event):
        print("pressed up")
        self.dx += 2.5

    def decreaseSpeed(self, event):
        print("pressed down")
        if self.dx > 0:
            self.dx -= 2.5

    def animate(self):
        while not self.dx == 0:
            self.canvas.move("car", self.dx, 0)
            self.canvas.after(self.sleepTime)
            self.canvas.update()
            if self.x < self.cWidth + 10:
                self.x += self.dx
            else:
                self.x = -60
                self.canvas.delete("car")
                self.drawCar(self.x, self.y)
racingCar()

1 Ответ

0 голосов
/ 04 ноября 2019

Вы не должны использовать while или sleep в том же потоке, в котором запущен tkinter.

В этом случае при использовании after() он работает точно так же, как sleep.

Поскольку tkinter является однопоточным, эти методы блокируют основной цикл, и больше ничего не может произойти, пока цикл не закончится или не закончится спящий режим. Причина, по которой ваш холст обновляется, заключается в том, что вы вызываете update в цикле while, но ваши события по-прежнему блокируются.

Чтобы исправить это, используйте after(), как это предусмотрено для этого вида цикла в tkinter.

Я обновил ваш код для использования after() и немного его очистил, чтобы более точно следовать руководству по стилю PEP8. дайте мне знать, если у вас есть какие-либо вопросы.

import tkinter as tk


class RacingCar(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Racing Car")

        self.c_width = 500
        self.c_height = 200
        self.canvas = tk.Canvas(self, width=self.c_width, height=self.c_height, bg="white")
        self.canvas.pack()

        self.x = 0
        self.y = self.c_height
        self.draw_car(self.x, self.y)

        self.dx = 5
        self.after_time = 50
        self.animate()

        self.bind("<Up>", self.increase_speed)
        self.bind("<Down>", self.decrease_speed)

    def draw_car(self, x, y):
        self.canvas.create_rectangle(x, y - 20, x + 50, y - 10, fill="yellow", tags="car")
        self.canvas.create_oval(x + 10, y - 10, x + 20, y, fill="black", tags="car")
        self.canvas.create_oval(x + 30, y - 10, x + 40, y, fill="black", tags="car")
        self.canvas.create_polygon([x + 10, y - 20, x + 20, y - 30, x + 30, y - 30, x + 40, y - 20],
                                   fill="blue", tags="car")

    def increase_speed(self, _):
        print("pressed up")
        self.dx += 2.5

    def decrease_speed(self, _):
        print("pressed down")
        if self.dx > 0:
            self.dx -= 2.5

    def animate(self):
        if self.dx != 0:
            self.canvas.move("car", self.dx, 0)
            if self.x < self.c_width + 10:
                self.x += self.dx
            else:
                self.x = -60
                self.canvas.delete("car")
                self.draw_car(self.x, self.y)
            self.after(self.after_time, self.animate)


RacingCar().mainloop()
...