2017-06-09 7 views
1

Ich versuche, einen Ball zu animieren, das wird vorwärts bewegen. Wenn der Benutzer die Taste nach oben oder unten drückt, sollte er sich entsprechend bewegen.Tkinter .after() reagiert nicht auf Tastendruck schnell genug

try: 
    import tkinter as tk 
except ImportError: 
    import Tkinter as tk 


class Movement: 
    def __init__(self, _frame, _canvas): 
     self.frame = _frame 
     self.canvas = _canvas 
     self.x = 10 
     self.y = 150 
     self.count = 0 
     self.update() 

     self.frame.bind_all("<Up>", lambda event: self.move_up()) 
     self.frame.bind_all("<Down>", lambda event: self.move_down()) 

     pass 

    def move_up(self): 
     self.y -= 10 
     pass 

    def move_down(self): 
     self.y += 10 
     pass 



    def update(self): 
     canvas.delete("obj") 
     self.count += 10 
     x2 = self.x + 50 
     y2 = self.y + 50 

     self.canvas.create_oval(self.x + self.count, self.y, x2 + self.count, y2, fill="red", tag="obj") 

     root.after(1000, self.update) 
     pass 


root = tk.Tk() 
width = 400 
height = 400 
canvas = tk.Canvas(root, width=width, height=height) 
frame = tk.Frame(root, width=width, height=height) 
if __name__ == '__main__': 
    Movement(frame, canvas) 
    canvas.grid() 
    root.mainloop() 

Es gibt jedoch ein Problem. Angesichts der Tatsache, dass der Ball sich alle 1 Sekunde bewegt, reagiert er nicht schnell genug auf den Tastendruck. Wenn Sie auf den Aufwärts-Kick klicken, wird der Bildschirm nach einer Sekunde aktualisiert.

Ich weiß, dass es eine Funktion .move() in Tkinter gibt. Aus vielen Gründen kann ich das jedoch nicht verwenden.

Mein Hauptanliegen ist das Intervall, das der Bildschirm benötigt, um aktualisiert zu werden.

+1

So eine kleinere Anzahl an 'after' passieren, dann. – Kevin

+0

Dann wird sich der Ball schneller bewegen, was ich nicht will. –

+0

Wenn Sie ein Spiel machen Tkinter ist schrecklich - Pygame ist viel besser und ist relativ einfach –

Antwort

0

Von dem, was ich verstehe, möchten Sie in der Lage sein, die Zeitschaltuhr gleichmäßig vorwärts zu bewegen, aber auch in der Lage sein, an irgendeinem Punkt auch außerhalb des Timers auf und ab zu bewegen.

um dies zu bewerkstelligen, habe ich den Timer auf seine eigene Funktion verschoben und den Up-Down-Funktionen erlaubt, die Objekt-Destroy/Create-Funktion aufzurufen.

Ich habe den Code aktualisiert, um das widerzuspiegeln.

Werfen Sie einen Blick auf diesen Code und lassen Sie mich wissen, wenn es hilft.

try: 
    import tkinter as tk 
except ImportError: 
    import Tkinter as tk 

class Movement: 
    def __init__(self, _frame, _canvas): 
     self.frame = _frame 
     self.canvas = _canvas 
     self.x = 10 
     self.y = 150 
     self.count = 0 
     self.object_timer() 

     self.frame.bind_all("<Up>",lambda event: self.move_up()) 
     self.frame.bind_all("<Down>",lambda event: self.move_down()) 

    def move_up(self): 
     self.y -= 10 
     self.update() 

    def move_down(self): 
     self.y += 10 
     self.update() 

    def update(self): 
     canvas.delete("obj") 
     x2 = self.x + 50 
     y2 = self.y + 50 
     self.canvas.create_oval(self.x + self.count, self.y, x2 + self.count, y2, fill="red", tag="obj") 

    def object_timer(self): 
     self.update() 
     self.count += 10 
     root.after(1000, self.object_timer) 

root = tk.Tk() 
width = 400 
height = 400 
canvas = tk.Canvas(root, width=width, height=height) 
frame = tk.Frame(root, width=width, height=height) 
if __name__ == '__main__': 
    Movement(frame, canvas) 
    canvas.grid() 
    root.mainloop() 
+0

Wenn meine Antwort Ihnen geholfen hat, denken Sie bitte daran, meine Antwort zu akzeptieren, indem Sie das Kontrollkästchen rechts neben meiner Antwort aktivieren :) –

+0

Aber das bewegt es auch diagonal. Was ich erreichen wollte, ist, dass die X-Achse beim Hochfahren einfrieren sollte. –

+0

@Cast Fellow: Ich habe gerade meine Antwort bearbeitet, um zu reflektieren, was Sie wollen. Dies sollte aufhören, den Ball nach rechts zu bewegen, bis der Timer läuft. –

0

Es ist alles nur Mathe. Du kannst das Update doppelt so oft aufrufen und den Ball halb so weit bewegen, wenn du den Ball mit der gleichen Geschwindigkeit weiterlaufen lassen willst, während du schneller auf Tasten drücken kannst.

Zum Beispiel, anstatt 10 Pixel pro Sekunde zu bewegen, muss es sich alle zehntel Sekunde um 1 Pixel bewegen. Das Endergebnis ist immer noch 10 Pixel pro Sekunde. Die Animation wird flüssiger und schneller auf Tastenanschläge reagieren.


Übrigens ist es nicht notwendig, das Oval bei jeder Iteration zu löschen und neu zu erstellen. Es ist möglich, Objekte auf der Leinwand zu verschieben. Das Löschen und erneute Erstellen führt schließlich zu Leistungsproblemen bei der internen Implementierung der Zeichenfläche. Jedes Objekt, das Sie erstellen, erhält eine neue eindeutige ID, und die Zeichenfläche wird langsamer, wenn eine große Anzahl von IDs vorhanden ist. Die Zeichenfläche verwendet keine ID.

Ich würde auch empfehlen, lambda zu verwenden. Wenn Sie es nicht benötigen, fügt es Komplexität hinzu, ohne einen Wert hinzuzufügen. Fügen Sie einfach einen zusätzlichen Parameter zu move_up und move_down:

self.frame.bind_all("<Up>",self.move_up) 
self.frame.bind_all("<Down>", self.move_down) 
... 
def move_up(self, event=None): 
    ... 
def move_down(self, event=None): 
    ... 
Verwandte Themen