URL ändern und Label aktualisieren

Fragen zu Tkinter.
Antworten
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

Hallo,

ich bin leider noch absoluter Einsteiger was Python angeht.
Ich habe jetzt ein Problem wo ich schon seit mehreren Tagen fest sitze.
Ich habe ein Programm was die Informationen von einer Serie aus dem Internet als XML datei bekommt und dann die Datei parsed.
Das funktioniert auch soweit alles ganz gut wenn ich die URL fest in einer Variable habe.
Aber sobald ich die Variable ändere passiert gar nichts.
Alle Label haben noch die alten Werte und änder nichts.

Ich habe es auch schon als Funktion probiert und die URL mit übergeben aber das brachte auch nichts.
Wäre schön wenn ihr mal drüber schauen könntet und mir vieleicht weiter helfen könnt.

Code: Alles auswählen

from Tkinter import *
from gtk._gtk import SIDE_LEFT
from xml.dom.minidom import parse
import xml.dom.minidom
import urllib
import tkMessageBox
import Tkinter
 
proxies = {'http': ''}
contents = urllib.urlopen('http://thetvdb.com/api/F90A595BC96913C9/series/281662/all/de.xml', proxies=proxies)
 
DOMTree = xml.dom.minidom.parse(contents)
Data = DOMTree.documentElement
 
 
def suchen():
    #contents = e1.get()
    contents = urllib.urlopen('http://thetvdb.com/api/F90A595BC96913C9/series/78804/all/de.xml', proxies=proxies)
    DOMTree = xml.dom.minidom.parse(contents)
    Data = DOMTree.documentElement
    html=contents.read()
    print html
    #e2.get()
    #DOMTree = xml.dom.minidom.parse(contents)
   # Data = DOMTree.documentElement
    #if Data.hasAttribute("SeriesName"):
    #    print "Root element : %s" % Data.getAttribute("SeriesName")
 
 
def senden():
    i = 1
    while i < r:
                #print "Episode "+str(i)+" Auswahl:"+str(self.group_alle[i].get())
        print liste[i]
        dateiname = "Group "+str(i)+" selection:"+str(group_alle[i].get())
        #datei = file(liste[i]+".txt",'w')
        #datei.write('<discstub>\n')
        #datei.write("  <title>"+str(liste[i])+"</title>\n")
        #datei.write("  <message>Bitte "+str(ausgabe_serienname)+" Season "+str(ausgabe_season[i])+" DVD"+str(group_alle[i].get())+" einlegen</title>\n")
        #datei.write('</discstub>\n')
                #datei.write("Epsiode ist auf DVD"+str(self.group_alle[i].get()))
        datei.close()
        i = i +1
    tkMessageBox.showinfo('senden','Dateien wurden geschrieben')
 
def hauptseite(contents):
    if Data.hasAttribute("SeriesName"):
        print "Root element : %s" % Data.getAttribute("SeriesName")
 
    group_1 = IntVar()
    group_2 = IntVar()
    group_alle = {}
 
    Label(master, text="Serienname").grid(row=0, column=0,sticky=E)
    Label(master, text="Serien ID").grid(row=1, column=0, sticky=E)
 
    e1 = Entry(master)
    e2 = Entry(master)
    global e1
    global e2
 
    e1.grid(row=0, column=1, columnspan=2, sticky=W)
    e2.grid(row=1, column=1, columnspan=2, sticky=W)
 
    Button(master, text="suchen",command=suchen).grid(row=0, column=3, rowspan=2, columnspan=2)
 
    Button(master, text="erstellen",command=senden).grid(row=0, column=6, rowspan=2, columnspan=2)
 
    serienname = Data.getElementsByTagName("Series")
    SeriesName = Data.getElementsByTagName('SeriesName')[0]
    print "SeriesName: %s" % SeriesName.childNodes[0].data
    ausgabe_serienname = SeriesName.childNodes[0].data
    serien = Data.getElementsByTagName("Episode")
    global r
    r = IntVar()
    r = 1
    liste = {}
    ausgabe_season = {}
    for episode in serien:
 
        EpisodeName = episode.getElementsByTagName('EpisodeName')[0]
        EpisodeNumber= episode.getElementsByTagName('EpisodeNumber')[0]
        Combined_season= episode.getElementsByTagName('Combined_season')[0]
        FirstAired= episode.getElementsByTagName('FirstAired')[0]
 
        ausgabe_season[r]= Combined_season.childNodes[0].data
        episodennummer = EpisodeNumber.childNodes[0].data
        if int(episodennummer) < 10:
            labeltextepisode= "%s - S0%sE0%s - %s" % (SeriesName.childNodes[0].data, Combined_season.childNodes[0].data, EpisodeNumber.childNodes[0].data, EpisodeName.childNodes[0].data)
            liste[r]= "%s - S0%sE0%s - %s" % (SeriesName.childNodes[0].data, Combined_season.childNodes[0].data, EpisodeNumber.childNodes[0].data, EpisodeName.childNodes[0].data)
        else:
            labeltextepisode= "%s - S0%sE%s - %s" % (SeriesName.childNodes[0].data, Combined_season.childNodes[0].data, EpisodeNumber.childNodes[0].data, EpisodeName.childNodes[0].data)
            liste[r]= "%s - S0%sE%s - %s" % (SeriesName.childNodes[0].data, Combined_season.childNodes[0].data, EpisodeNumber.childNodes[0].data, EpisodeName.childNodes[0].data)
        Label(master, text=labeltextepisode).grid(row=r+2,sticky=W,column=0,columnspan=4)
        gruppenname="group_"+str(r)
        master.gruppenname = IntVar()
        group_alle[r] = IntVar()
        Radiobutton(master, text="DVD 1",indicatoron = 0, variable=group_alle[r], value=1).grid(row=r+2,column=5)
        Radiobutton(master, text="DVD 2",indicatoron = 0, variable=group_alle[r], value=2).grid(row=r+2,column=6)
        Radiobutton(master, text="DVD 3",indicatoron = 0, variable=group_alle[r], value=3).grid(row=r+2,column=7)
        Radiobutton(master, text="DVD 4",indicatoron = 0, variable=group_alle[r], value=4).grid(row=r+2,column=8)
        Radiobutton(master, text="DVD 5",indicatoron = 0, variable=group_alle[r], value=5).grid(row=r+2,column=9)
        Radiobutton(master, text="DVD 6",indicatoron = 0, variable=group_alle[r], value=6).grid(row=r+2,column=10)
        Radiobutton(master, text="DVD 7",indicatoron = 0, variable=group_alle[r], value=7).grid(row=r+2,column=11)
        Radiobutton(master, text="DVD 8",indicatoron = 0, variable=group_alle[r], value=8).grid(row=r+2,column=12)
        r = r + 1
if __name__ == '__main__': 
    master = Tk()
    master.title("Media Stub Generator")
    hauptseite(contents)
 
mainloop()

#######################
Eine etwas einfachere Testanwendung die nur den Seriennamen zurückgeben soll

from Tkinter import *
from gtk._gtk import SIDE_LEFT
from xml.dom.minidom import parse
import xml.dom.minidom
import urllib
import tkMessageBox
import Tkinter
proxies = {'http': ''}
global proxies
 
def suchen():
    #contents = e1.get()
    contents = urllib.urlopen('http://thetvdb.com/api/F90A595BC96913C9/series/78804/all/de.xml', proxies=proxies)
    #e2.get()
    #DOMTree = xml.dom.minidom.parse(contents)
   # Data = DOMTree.documentElement
    #if Data.hasAttribute("SeriesName"):
    #    print "Root element : %s" % Data.getAttribute("SeriesName")
    html = contents.read()
    #Label.configure(master, text="SeriesName: %s" % SeriesName.childNodes[0].data)
    print html
    hauptseite(contents = urllib.urlopen('http://thetvdb.com/api/F90A595BC96913C9/series/78804/all/de.xml', proxies=proxies))
 
def hauptseite(contents = urllib.urlopen('http://thetvdb.com/api/F90A595BC96913C9/series/281662/all/de.xml', proxies=proxies)):
    #master = Tk()
    #master.title("Media Stub Generator")
    Button(master, text="suchen",command=suchen).grid()
 
    #contents = urllib.urlopen('http://thetvdb.com/api/F90A595BC96913C9/series/281662/all/de.xml', proxies=proxies)
    #contents = urllib.urlopen('http://thetvdb.com/api/F90A595BC96913C9/series/78804/all/de.xml', proxies=proxies)
 
    DOMTree = xml.dom.minidom.parse(contents)
    Data = DOMTree.documentElement
    if Data.hasAttribute("SeriesName"):
            print "Root element : %s" % Data.getAttribute("SeriesName")
    serienname = Data.getElementsByTagName("Series")
    SeriesName = Data.getElementsByTagName('SeriesName')[0]
    print "SeriesName: %s" % SeriesName.childNodes[0].data
    Label(master, text="SeriesName: %s" % SeriesName.childNodes[0].data).grid()
    ausgabe_serienname = SeriesName.childNodes[0].data
    serien = Data.getElementsByTagName("Episode")
    mainloop()
if __name__ == '__main__': 
    master = Tk()
    master.title("Media Stub Generator")
    hauptseite()
Zuletzt geändert von Anonymous am Donnerstag 27. August 2015, 20:34, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@spawn2007: Du solltest da dringend etwas sauberer arbeiten und nicht wild alles Mögliche ausprobieren und Code von früheren Versuchen da drin lassen.

Sternchenimporte sollte man vermeiden, da man sich damit zum Beispiel im Fall von Tkinter ca. 190 Namen ins Modul holt. Wenn man am Ende mit Sternchenimporten doch wieder alles in einen Namensraum kippt, machen Module als Namensräume keinen Sinn mehr.

Wenn man eine Tk-GUI hat, dann sollte man nichts aus `gtk` importieren was dann noch nicht einmal benutzt wird.

Der explizite Import von `parse()` aus `xml.dom.minidom` wird auch nicht verwendet. Genauso wie das importierte `Tkinter`-Modul.

Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Dann kann man das Modul ohne Nebeneffekte importieren und einzelne Funktionen zum Beispiel interaktiv in einer Python-Shell testen oder auch automatisiert mit Unittests.

``global`` hat in einem sauberen Programm nichts zu suchen und bei GUI-Programmierung kommt man in Python an objektorientierter Programmierung (OOP) nicht wirklich dran vorbei. Und Werte (ausser Konstanten) betreten Funktionen und Methoden als Argument und verlassen sie als Rückgabewerte.

Die GUI würde ich aber sowieso erst einmal aussen vor lassen und mit einer Funktion anfangen welche die nötigen Informationen aus dem XML extrahiert und in eine passende Datenstruktur überführt. Die kann man dann auch ohne GUI mal testen und die Fehler bereinigen bevor man anfängt sich über die Darstellung der Daten in einer GUI Gedanken zu machen.

Statt `xml.dom.minidom` bevorzugen eigentlich fast alle Python-Programmierer die `xml.etree`-API die wesentlich „pythonischer“ ist. Mit der externen `lxml`-Bibliothek hat man die gleiche API mit einigen Erweiterungen.

XML erzeugt man nicht durch zusammenstückeln von Zeichenketten! Dazu ist das Format zu komplex und man erzeugt leicht mal kaputte Daten die dann von keinem Programm das XML liest, mehr verstanden werden. Lesestoff: HOWTO Avoid Being Called a Bozo When Producing XML.

Indizes fangen bei Listen bei 0 an, wie in der ganzen Informatik üblicherweise bei 0 angefangen wird zu zählen.

Gute Namen sind wichtig. `e1`, `e2`, `r`, `liste` sind alles keine guten Namen weil die dem Leser nichts über die Bedeutung des Wertes im Programm verraten. Bei `liste` ist es besonders übel wenn man an den Namen dann gar keine Liste sondern ein Wörterbuch bindet. Das ist total verwirrend.

Für das herunterladen von dem XML über HTTP würde ich die `requests`-Bibliothek verwenden.
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

Vielen Dank für die vielen Hinweise.

Hab jetzt angefangen alles von vorne neu aufzubauen.
XML.etree ist sogar einfacher als das was ich benutzt habe und funktioniert jetzt auch schon.
Mein Problem wo ich nicht weiter kam hab ich jetzt auch lösen können.
Hab einen Denkanstoß bekommen und dann gemerkt das es schon ein unterschied ist ob
serieneingabe = Entry(master,bg='green').grid() benutze oder
serieneingabe = Entry(master,bg='green')
serieneingabe.grid()

dann klappt es auch mit dem serieneingabe.get()

Ich werde bald den Quellcode nochmal posten dann kannst du nochmal drüber schauen.

Vielen dank erstmal
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

Hab jetzt ein Problem im 2. Fenster in der Listbox einen neuen Eintrag einzufügen.
Was ist hier falsch?

listbox.insert(END,"text")
NameError: global name 'END' is not defined

Code: Alles auswählen

import xml.etree.ElementTree as ET
from Tkinter import mainloop, Button, Entry, Text, StringVar, Toplevel, Label,\
    Listbox
from Tkinter import Tk
import urllib

serieneingabe_text = StringVar
proxies = {'http': ''}
    
def seriensuche():
    sucheserienname = serieneingabe.get()
    print sucheserienname
    contents = urllib.urlopen("http://thetvdb.com/api/GetSeries.php?seriesname="+sucheserienname, proxies=proxies)
    html = contents.read()
    root = ET.fromstring(html)
    # Neues Fenster oeffnen
    auswahlfenster = Toplevel(master)
    auswahlfenster.title('Fehler')
    auswahlfenster.geometry('160x60')
    Label(auswahlfenster, text="Gefundene Serien").grid()
    listbox = Listbox(auswahlfenster)
    listbox.grid()
    listbox.insert(END,"text")
    for child in root.findall('Series'):
        serienname = child.find('SeriesName').text
        serienid = child.find('seriesid').text
        #listbox.insert(END,auswahlfenster,text=serienname+" ("+serienid+")")
        Label(auswahlfenster,text=serienname+" ("+serienid+")").grid()
  
    
    
    
master = Tk()
serieneingabe = Entry(master,bg='green')
serieneingabe.grid()
suchbutton = Button(master, text="Suchen",command=seriensuche)
suchbutton.grid()


mainloop()
Zuletzt geändert von Anonymous am Freitag 28. August 2015, 13:23, insgesamt 1-mal geändert.
Grund: Quelltext in Code-Tags gesetzt.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

1. Schreib deinen Code doch bitte in

Code: Alles auswählen

-Tags. Einfach den [Code]-Button über dem Eingabefeld drücken und zwischen den Tags dann deinen Code einfügen.

2. Orientierst du dich an Beispielen? Kann es sein, dass in den Beispielen alle aus dem Tkinter-Namensraum imporiert wurde (*-Import), was man nicht machen sollte? Wenn ja, dann liegt END im Tkinter-Namensraum und du kannst es entweder imporieren, so wie du das mit den anderen Elementen auch machst, oder du sprichst des über Tkinter.END an.
Der Fehler lautet ja: "Ich kenne END nicht, das hast du nicht definiert", und da hat Python recht, ich sehe nirgends eine Definition ;)
BlackJack

@spawn2007: Da ist immer noch GUI und Geschäftslogik vermischt und die ”Funktion” greift einfach so auf modulglobale Variablen zu.

Ich würde nochmal `requests` für die HTTP-Abfragen empfehlen, das macht einiges einfacher und schöner wenn man es richtig machen will. In den „query“-Teil einer URL einfach so eine Benutzereingabe unverändert zu übernehmen ist nämlich keine gute Idee, denn gültige URLs müssen sich an Regeln halten die man so sehr leicht verletzen kann. Eine URL darf nur aus ASCII-Zeichen bestehen und dabei dann auch nicht aus allen. Zeichen- beziehungsweise Bytewerte die dem nicht entsprechen müssen geeignet kodiert werden. Die Unicode-Zeichenkette kodieren und Sonderzeichen die in URLs nicht erlaubt sind escapen macht `requests` alles für einen. Deine Variante könnte zum Beispiel nicht nach der Serie „F/X“ suchen oder nach „Starsky & Hutch“ oder irgendwas mit Leerzeichen, oder Umlauten.
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

Hallo sparrow,

ja werd drauf achten code zu benutzen.

Ja das ist aus einem Beispiel wie diesem:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Tkinter as tk


class ListboxDemo(object):
    def __init__(self, master):
        self.selection = []
        self.items = ["eins", "zwei", "drei", "und als letztes vier"]
        activated = (0,2) # Vor-Aktivierte Punkte

        # Kleiner Info Text
        tk.Label(master, text="Wähle was aus und drücke OK").pack()

        # Die Listbox erstellen
        self.listbox = tk.Listbox(
            master,
            selectmode=tk.MULTIPLE, # multiple choice
            #selectmode=tk.SINGLE # single select mode
            height=5, width=80
        )
        self.listbox.pack()

        # Einträge einfügen
        for txt in self.items:
            self.listbox.insert(tk.END, txt)

        # Vor-Aktivierte Punkte selektieren
        for index in activated:
            self.listbox.selection_set(index)

        # Noch zwei Buttons erstellen
        b = tk.Button(master, text = "OK", command=self.display_selection)
        b.pack(side=tk.RIGHT)
        b = tk.Button(master, text = "Abort", command=master.destroy)
        b.pack(side=tk.RIGHT)

    def display_selection(self):
        selection = []
        for i in self.listbox.curselection():
            index = int(i) # i ist ein String
            selection.append(self.items[index])

        print "Aktuelle Selektion ist:", selection

if __name__ == '__main__':
    root = tk.Tk()
    root.title("Listbox demo")

    ListboxDemo(root)

    root.mainloop()
Da sehe ich auch nicht wo END gesetzt wird.
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

Hallo BlackJack,

ich werde das mal mit request versuchen mal sehenwie gut das geht.
Du hast natürlich Recht mit den Umlauten und Sonderzeichen.
Muss erstmal die anderen sachen halbwegs zum laufen bekommen.

Ich versuche mich erst seit 4 Tagen mit Python und bin doch schon etwas frustriert.
BlackJack

@spawn2007: Bei dem Beispiel steht nicht ``END`` sondern ``tk.END`` und damit ist klar dass das im `Tkinter`-Modul definiert wurde, denn sonst würde das Programm an der Stelle ja auch abbrechen, mit einem `AttributeError`.
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

@ BlackJack

Ja da hast du vollkommen recht, jetzt funktioniert es.

Danke für den Hinweis
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

Was mache ich den beim listbox.curselection falsch?
Oder besser noch wie gebe ich die Auswahl am besten als Rückgabewert beim schließen zurück??

Code: Alles auswählen

import xml.etree.ElementTree as ET
from Tkinter import mainloop, Button, Entry, Text, StringVar, Toplevel, Label,\
Listbox
from Tkinter import Tk
import Tkinter as tk
import urllib
     
serieneingabe_text = StringVar
proxies = {'http': ''}

def seriensuche():
    sucheserienname = serieneingabe.get()
    print sucheserienname
    contents = urllib.urlopen("http://thetvdb.com/api/GetSeries.php?seriesname="+sucheserienname)
    html = contents.read()
    root = ET.fromstring(html)
    # Neues Fenster oeffnen
    auswahlfenster = Toplevel(master)
    auswahlfenster.title('Fehler')
    auswahlfenster.geometry('200x150')
    Label(auswahlfenster, text="Gefundene Serien").grid()
    listbox = Listbox(auswahlfenster)
    listbox.grid()

    #listbox.insert(tk.END,"text")
    for child in root.findall('Series'):
        serienname = child.find('SeriesName').text
        serienid = child.find('seriesid').text
        listbox.insert(tk.END,serienname+" ("+serienid+")")
        Label(auswahlfenster,text=serienname+" ("+serienid+")").grid()
    listeAusgewaehlt = listbox.curselection()
    print listeAusgewaehlt
    return listeAusgewaehlt
     
       
       
master = Tk()
serieneingabe = Entry(master,bg='green')
serieneingabe.grid()
sucheserienname = serieneingabe.get()
suchbutton = Button(master, text="Suchen",command=seriensuche)
suchbutton.grid()

   
mainloop()
BlackJack

@spawn2007: Der Benutzer hat niemals eine Chance etwas auszuwählen bevor Du die Auswahl ausliest. GUI-Programmierung funktioniert nicht so linear im Ablauf. Der Benutzer muss etwas auswählen und dann zum Beispiel eine Schaltfläche zum bestätigen der Auswahl drücken. Und in der Rückruffunktion/-methode kannst Du dann auslesen was der Benutzer ausgewählt hat. Die GUI benutzen kann der Benutzer nur während die `mainloop()`-Funktion aktiv ist.

Du solltest aber echt erst einmal die Geschäftslogik von der GUI trennen und Dich mit objektorientierter Programmierung anfreunden.
spawn2007
User
Beiträge: 8
Registriert: Donnerstag 27. August 2015, 15:26

Was Mache ich bei den Rückgabewerten falsch?
Beim klicken wird der richtige Text ausgegeben aber nicht zurückgegeben.
Und ja ich sollte curselection nutzen aber da bekomme ich ja nur den Index der Zeile raus richtig?

Code: Alles auswählen

import xml.etree.ElementTree as ET
from Tkinter import mainloop, Button, Entry, Text, StringVar, Toplevel, Label,\
    Listbox
from Tkinter import Tk
import Tkinter as tk
import urllib

serieneingabe_text = StringVar
listeAusgewaehlt = StringVar

def on_select(event):
    #print event.widget.curselection()
    print event.widget.selection_get()
    listeAusgewaehlt = event.widget.selection_get()
    return listeAusgewaehlt

    
def seriensuche():
    sucheserienname = serieneingabe.get()
    print sucheserienname
    contents = urllib.urlopen("http://thetvdb.com/api/GetSeries.php?seriesname="+sucheserienname)
    html = contents.read()
    root = ET.fromstring(html)
    # Neues Fenster oeffnen
    auswahlfenster = Toplevel(master)
    auswahlfenster.title('Serie Auswaehlen')
    auswahlfenster.geometry('400x350')
    Label(auswahlfenster, text="Gefundene Serien").grid()
    listbox = Listbox(auswahlfenster)
    listbox.grid()
    for child in root.findall('Series'):
        serienname = child.find('SeriesName').text
        serienid = child.find('seriesid').text
        listbox.insert(tk.END,serienname+" ("+serienid+")")
        Label(auswahlfenster,text=serienname+" ("+serienid+")").grid()
    listbox.bind('<<ListboxSelect>>', on_select)
    
    return listeAusgewaehlt
     
       
       
master = Tk()
serieneingabe = Entry(master,bg='green')
serieneingabe.grid()
sucheserienname = serieneingabe.get()
suchbutton = Button(master, text="Suchen",command=seriensuche)
suchbutton.grid() 
   
mainloop()

BlackJack

@spawn2007: Bei einem Handler macht ein Rückgabewert keinen Sinn. Der Aufrufer ist die Hauptschleife des GUI-Rahmenwerks, die hat keine Ahnung was sie mit so einem Wert anstellen sollte.

Und das ``return listeAusgewaehlt`` in `seriensuche()` gibt die `StringVar`-Klasse zurück die auf Modulebene an den Namen `listeAusgewählt` gebunden ist. Das ist ziemlich sinnlos und dieser Name/Wert hat auf Modulebene sowieso nichts zu suchen. Die Rückgabe erfolgt auch hier wieder an die Hauptschleife des GUI-Rahmenwerks, denn die hat die Funktion aufgerufen als der Benutzer die „Suchen“-Schaltfläche gedrückt hat.

GUI-Programmierung funktioniert ereignisbasiert. Du schreibst da keinen Code der rein linear abgearbeitet wird wo Du die kontrolle über die Reihenfolge hast, sondern Du schreibst Code der eine GUI erstellt und registrierst Rückruffunktionen die aufgerufen werden wenn bestimmte Ereignisse auftreten, und dann rufst Du die Hauptschleife auf die ab da alles weitere Koordiniert. Und wenn ein Ereignis auftritt wird die entsprechende Rückruffunktion ausgeführt. Die darf aber selber nur relativ kurz laufen und nicht versuchen die Programmflusskontrolle wieder zu übernehmen, denn solange eine Rückruffunktion läuft, kann die Hauptschleife die GUI nicht mehr aktuell halten und auf Benutzereingaben oder andere Ereignisse reagieren.

Wenn man sich Zustand über solche Rückrufe hinweg merken will/muss, dann braucht man objektorientierte Programmierung. Und man sollte Geschäftslogik von GUI trennen. Und die Geschäftslogik erst einmal ohne GUI implementieren und testen. Und Werte betreten und verlassen Funktionen als Argumente und Rückgabewerte. Und irgendwie habe ich einiges davon schon mal geschrieben und Du hast nichts davon umgesetzt…
Antworten