@Alfons Mittelmeyer: hör endlich auf, Zeug von einem bestimmten Solaris-System zu zitieren, das wahrscheinlich eine Userspace-Threadimplementierung umgesetzt hat, wo natürlich alle Threads kooperativ sein müssen, weil es keine höhere Instanz gibt, die einem Thread die Kontrolle nehmen kann. Linux, MacOS und Windows haben Threads anders implementiert. Da wird vom Betriebssystem in regelmäßigen Abständen ein Thread unterbrochen und die Kontrolle an einen anderen Thread übergeben. Wie das im Detail funktioniert, ist von System zu System unterschiedlich und braucht den normalen Nutzer nicht zu interessieren. Beim OP kommt Rechenzeitverschwendung mit aufwändigen GUI-Updates zusammen, was zu Problemen führt. Das Verwunderliche ist, wenn man die Rechenzeitverschwendung nur ein wenig einschränkt, bekommt die GUI das bißchen mehr an Rechenzeit, damit die gröbsten Probleme verschwinden. Deine ganzen Vorschläge sind aber von einer sauberen Lösung noch weit entfernt.
Zu Deiner letzten "Lösung": Du hast es geschafft, mit trigger_event globale Variablen zu benutzen, so dass Du wieder an Deinem Troll-Ziel angekommen bist. Sollte tkinter nach dem FIFO-Prinzip arbeiten werden erst alle Updates durchgeführt und dann das after mit trigger_event, dynamische FPS-Anpassung, wenn die GUI nicht mit zeichnen nachkommt. Dein Beschreibungstext behauptet das Gegenteil.
Das korrekte exakte Einhalten der Zeit (ganz ohne Event) erreichst Du so:
Code: Alles auswählen
def hauptschleife(self):
start = time()
for frame in count():
sleep(max(0, start + frame / FPS - time.time()))
self.schritt()
self.ausgabe()
@Üpsilon: wenn Du das Programm mit einem Update-Thread haben willst, ist eine Queue für Updates das falsche Mittel, weil, falls die GUI nicht mit dem Zeichnen hinterherkommt, nur der letzte Zustand relevant ist. Du brauchst also ein Spielfeld, das vom Update-Thread jeweils erzeugt und als ganzes an die GUI übergeben wird.