Seite 1 von 1

Zeitverzögerung im mainloop()

Verfasst: Sonntag 1. Juli 2018, 16:12
von Atalanttore
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

Re: Zeitverzögerung im mainloop()

Verfasst: Sonntag 1. Juli 2018, 16:20
von __blackjack__
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.

Re: Zeitverzögerung im mainloop()

Verfasst: Sonntag 1. Juli 2018, 17:00
von wuf
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 ;-)

Re: Zeitverzögerung im mainloop()

Verfasst: Sonntag 1. Juli 2018, 18:28
von Atalanttore
Vielen Dank. Die Erklärung und das Codebeispiel sind super. :thumbsup:

Gruß
Atalanttore