GUI ändern vor Schleifenbeginn

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
ChefDeus
User
Beiträge: 2
Registriert: Samstag 31. Oktober 2020, 21:18

Hallo,

ich hab ein kleines Problem, und zwar kann ich keinen Buttontext ändern bevor eine Schleife ausgeführt wird.
testButton.config(text="gedrückt...") - wird immer erst nach beendeter Schleife ausgeführt.
Auch das auslagern der Schleife in eine asynchrone Funktion ändert nichts daran. (Falls ich das überhaupt richtig gemacht hab)

Code: Alles auswählen

from tkinter import *
import asyncio

loop = asyncio.get_event_loop()

def startAsyncFunc():
  testButton.config(text="gedrückt...")
  loop.run_until_complete(asyncFunc())

async def asyncFunc():
  count = 0 
  while True:
    print(count)
    if count == 10000:
      break
    count += 1  

win = Tk()
win.title("test")
testButton = Button(win, text="test button", command=startAsyncFunc)
testButton.pack()
win.mainloop()
Wenn jemand weiß wie ich dieses Problem lösen/umgehen kann, möge er sich bitte melden :)
Gruß
Dennis
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ChefDeus: Eingerückt wird in Python mit vier Leerzeichen pro Ebene.

Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 200 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Und bei GUIs braucht man dann mindestens Closures, zum Beispiel mittels `functools.partial(), für jede nicht-triviale GUI aber objektorientierte Programmierung (OOP). Also eigene Klassen.

``async`` nützt hier nichts, denn das läuft ja nicht parallel. Der `run_until_complete()`-Aufruf blockiert bis alles was von dort ausgehend ausgeführt wird abgearbeitet ist. Da ist also nichts gewonnen.

Man kann den Zwischenschritt über die `after()`-Methode realisieren.

Die ``while``-Schleife ist eine unnötig kompliziert geschriebene ``for``-Schleife.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial


def do_short_work(button):
    for count in range(10_001):
        print(count)

    button["text"] = "fertig"


def start_short_work(button):
    button["text"] = "gedrückt..."
    button.after(10, do_short_work, button)


def main():
    window = tk.Tk()
    window.title("test")
    button = tk.Button(window, text="test button")
    button["command"] = partial(start_short_work, button)
    button.pack()
    window.mainloop()


if __name__ == "__main__":
    main()
Falls `do_short_work()` nicht tatsächlich das macht was der Name suggeriert, also nur kurz etwas tut und damit nicht die GUI blockiert, wird man das anders lösen müssen. Entweder in dem man die Arbeit auf kleine Häppchen aufteilt die auch mit `after()` ausgeführt werden, oder man muss für parallele Ausführung sorgen, beispielsweise mittels `threading` und dann mit `after()` und einer `Queue` zwischen GUI und Thread kommunizieren.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
ChefDeus
User
Beiträge: 2
Registriert: Samstag 31. Oktober 2020, 21:18

Super, Code läuft. darauf kann ich aufbauen, vielen Dank.
Und noch mehr Dank für die Tipps und den Code an sich, da hab ich mehr gelernt als bei 3 Stunden googlen :)

Gruß
Dennis
Antworten