Zeitverzögerung im mainloop()

Fragen zu Tkinter.
Antworten
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Hallo

In meinem sehr simplen Beispielprogramm bewegt sich nach 1 Sekunde ein rotes Rechteck.

Code: Alles auswählen

import time
from tkinter import *


if __name__ == "__main__":

    root = Tk()
    root.attributes("-fullscreen", True)
    root.focus_set()
    root.bind("<Escape>", lambda e: root.quit())

    width = root.winfo_screenwidth()
    height = root.winfo_screenheight()
    center_x = width / 2
    center_y = height / 2

    window = Canvas(root, width=width, height=height, bg="black")
    window.pack()

    a = window.create_rectangle(50, 0, 150, 50, fill='red')

    window.update()
    time.sleep(1)
    window.move(a, 100, 100)

    root.mainloop()
Allerdings habe ich gelesen, dass `time.sleep()` in einem `root.mainloop()` keine gute Idee ist und man stattdessen `root.after()` verwenden soll, aber funktionieren tut beides.

Code: Alles auswählen

from tkinter import *


if __name__ == "__main__":

    root = Tk()
    root.attributes("-fullscreen", True)
    root.focus_set()
    root.bind("<Escape>", lambda e: root.quit())

    width = root.winfo_screenwidth()
    height = root.winfo_screenheight()
    center_x = width / 2
    center_y = height / 2

    window = Canvas(root, width=width, height=height, bg="black")
    window.pack()

    a = window.create_rectangle(50, 0, 150, 50, fill='red')

    window.update()

    root.after(1000, window.move(a, 100, 100))

    root.mainloop()
  1. Warum ist `root.after()` besser als `time.sleep()`?
  2. Warum funktioniert die Verschiebung des Rechtecks nur, wenn `window.update()` vor der Anweisung zum Verschieben des Rechtecks `window.move()` kommt?
Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ad 1. Weil man sich bei `time.sleep()` selbst um die Aktualisierung der GUI kümmern muss damit auch tatsächlich was dargestellt wird, also die `update()`-Methode. Und `update()` selbst aufrufen kann tückisch werden wenn man das in Rückruffunktionen macht und bei dem `update()` dann wieder Rückruffunktionen aufgerufen werden. Da kann man in ”Endlosschleifen” gelangen bei denen die GUI dann nicht mehr reagiert, aber die CPU schön ausgelastet wird.

Ad 2. Falls Du damit das zweite Beispiel mit `after()` meinst: Weil Du das falsch verwendest. Als zweites Argument wird dort ein aufrufbares Objekt erwartet. Du rufst da aber `window.move()` selbst auf und übergibst den Rückgabewert von diesem Aufruf an `after()`. Richtig wäre ``root.after(1000, window.move, a, 100, 100)``, also als zweites Argument die Methode übergeben die nach einer Sekunde aufgerufen werden soll, und danach die Argumente mit denen sie dann aufgerufen werden soll, statt die selbst *gleich* aufzurufen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Atalanttore

Eine mögliche Variante:

Code: Alles auswählen

import tkinter as tk

class Application:

    def __init__(self, app_win):
        self.app_win =  app_win
        self.width = app_win.winfo_screenwidth()
        self.height = app_win.winfo_screenheight()
        self.center_x = self.width / 2
        self.center_y = self.height / 2

        self.window = tk.Canvas(app_win, width=self.width, height=self.height,
            bg='black')
        self.window.pack()
        
        self.rectangle = self.window.create_rectangle(50, 0, 150, 50,
            fill='red')
            
        self.move_rectangle()
        
    def move_rectangle(self):
        self.window.move(self.rectangle, 100, 100)
        self.app_win.after(1000, self.move_rectangle)
           
def main():
    app_win = tk.Tk()
    app_win.attributes("-fullscreen", True)
    app_win.bind("<Escape>", lambda e: app_win.quit())
    
    app = Application(app_win)
    
    app_win.mainloop()
 
if __name__ == '__main__':
    main()
Gruss wuf ;-)
Take it easy Mates!
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Vielen Dank. Die Erklärung und das Codebeispiel sind super. :thumbsup:

Gruß
Atalanttore
Antworten