Thread im TkInter Fenster funktioniert nicht

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
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

Hallo,
ich versuche gerade meinen früheren Punktezähler auch für den Nutzer ein wenig angenehmer zu gestalten. So stoß ich auf GUI und probierte ein wenig mit TkInter. Es klappt alles soweit ziemlich gut, bis ich eine Uhrzeit hinzufügen wollte, die sich alle 60 Sekunden aktualisiert.
Ich weiß, dass sich Schleifen und Tkinter nicht gut vertragen und deswegen habe ich mich an Threads herangesetzt.
Probleme jetzt:
Es funtkioniert trotzdem nicht und ich kann mir nicht erkären wieso!
Ich finde irgendwie nichts dazu, wie ich den Thread entferne/beende/lösche! (Das soll passieren, sobald das Fenster geschlossen ist)

Man könnte jetzt sagen, das sei nicht wichtig und man könnte es weglassen, aber ich möchte anschließend auch noch mit Tastatureingaben arbeiten und da Schleifen sich ja nicht vertragen, muss ich da ja wieder mit threads ran!

Code: Alles auswählen

from tkinter import *
from tkinter import messagebox
from datetime import * 
import threading
import time

#Daten einlesen
file = open("Punktezähler_Daten.txt", "r")
spieler = file.readline().strip()
punkte = file.readline().strip()
datum = file.readline()
file.close

#Daten bearbeiten und Format anpassen
listeNamen = spieler.split(" ")
punktestand = punkte.split(" ")
print(punktestand)
punktestand = list(map(int, punktestand))

#Erzeugen des Fensters
fenster = Tk()
fenster.title("Punktezähler")
fenstergeschlossen = False
#Alle Definitionen:

HeuteDatum = date.today().strftime("%d.%m.%Y")

#Startdefinitionen
def ja():
    Button1.config(text = "Info!", command = information)
    Button2.config(text= "Hinzufügen!", command = hinzufügen )
    eingabe.grid(row = 6, column = 0, padx= 5 , pady= 5, columnspan= 2)
    info1.config(text = "")
    info2.config(text = "")

def nein():
    global listeNamen, punktestand
    listeNamen = []
    punktestand = []
    print(listeNamen)
    namenbox.delete(0, END)
    punktebox.delete(0, END)
    info1.config(text = "")
    info2.config(text = "")
    Button1.config(text = "Info!", command = informationNeueDaten)
    Button2.config(text= "Hinzufügen!", command = SpielerHinzufügen)
    eingabe.grid(row = 6, column = 0, padx= 5 , pady= 5, columnspan= 2)
    Button3.grid(row = 7, column = 0, padx= 5, pady= 5)
    ende.grid(row = 7, column =  1, padx= 5 , pady= 5)

def informationNeueDaten():
    info1.config(text = "Spieler unten eingeben!")
    info2.config(text = "Und auf Hinzufügen klicken!")

def SpielerHinzufügen():
    NeuerSpieler = eingabe.get()
    info1Inhalt = info1.cget("text")

    if info1Inhalt == "Unbedingt Spieler eingeben!" or info1Inhalt == "Es gibt diesen Spieler bereits schon!":
        info1.config(text = "")

    if NeuerSpieler == "":
        info1.config(text = "Unbedingt Spieler eingeben!")
        info2.config(text = "")

    else:
        try:
            listeNamen.index(NeuerSpieler)
        
        except:
            listeNamen.append(NeuerSpieler)
            punktestand.append(0)
            namenbox.insert("end", listeNamen[-1])
            punktebox.insert("end", punktestand[-1])
            print(listeNamen , "\n" , punktestand)
        else:
            info1.config(text = "Es gibt diesen Spieler bereits schon!")
        eingabe.delete(0, "end")

def HinzufügenBeenden():
    Button1.config(command = information)
    Button2.config(command = hinzufügen)
    info1.config(text = "")
    info2.config(text = "")
    Button3.destroy()
    ende.grid(row = 7, column =  0, padx= 5 , pady= 5, columnspan= 2)

#Hauptteildefinitionen
def information():
    ausgewählt = namenbox.curselection()
    if len(ausgewählt) == 0:
        info1.config(text = "Wählen sie zuerste einen Spieler aus! (Klicken)")
    else:
        info1.config(text = "Sie haben " +  str(listeNamen[int(ausgewählt[0])] +  " ausgewählt!"))
        info2.config(text = "Geben Sie die gewünschte zu addierende Punktzahl ein:")
        print(ausgewählt)

def hinzufügen():
    ausgewählt = namenbox.curselection()
    PlusPunktzahl = eingabe.get()
    print(ausgewählt)
    
    #Vorbeugung möglicher Fehler
    if len(ausgewählt) == 0: 
        info1.config(text = "Wählen sie zuerste einen Spieler aus! (Klicken)")
    elif PlusPunktzahl == "":
        info1.config(text = "Unbedingt eine gültige Punktzahl eingeben!")
    elif int(PlusPunktzahl) <= 0:
        info1.config(text = "Unbedingt eine gültige Punktzahl eingeben!")
        eingabe.delete(0, "end")
    else:
        print(PlusPunktzahl)
        punktestand[int(ausgewählt[0])] +=  int(PlusPunktzahl)
        punktebox.delete(int(ausgewählt[0]))
        punktebox.insert(int(ausgewählt[0]), punktestand[int(ausgewählt[0])] )
        eingabe.delete(0, "end")
        info1.config(text = "")
        print(punktestand)

def Uhrzeitschleife():
    while not fenstergeschlossen:
        UhrzeitLabel.config(text = datetime.now().strftime('%H:%M'))
        time.sleep(60)
        return

#Zerstörung des Labels + Schreiben in die Datei
def Ende():
    if messagebox.askyesno('Sicher?','Wirklich beenden?'):
        fenster.destroy()
        global fenstergeschlossen
        fenstergeschlossen = True
        #Schreiben in die Datei
        file = open("Punktezähler_Daten.txt", "w")
        NamenslisteString =  " ".join(listeNamen)
        print(NamenslisteString)
        PunkteListeString = " ".join(map(str,punktestand))

        file.write(NamenslisteString + "\n")
        file.write(PunkteListeString + "\n")
        file.write(str(HeuteDatum))
        file.close
    else: 
        pass

#Ende der Definitionen

#Bauteile erstellen
DatumsLabel = Label(fenster, text = date.today().strftime("%d.%m.%Y"), justify=RIGHT)
UhrzeitLabel = Label(fenster, text = datetime.now().strftime('%H:%M'))
WillkommensLabel = Label(fenster, text = "Herzlich willkommen zum epischen Punktezähler! ")
namenbox = Listbox(fenster, highlightcolor = "red")
punktebox = Listbox(fenster, highlightcolor = "red")
info1 = Label(fenster, text = "Daten vom: " + datum + " verwenden?")
info2 = Label(fenster, text = "Ja/Nein ")
Button1 = Button(fenster, text = "Ja!", command = ja)
Button2 = Button(fenster, text = "Nein!", command = nein)
Button3 = Button(fenster, text = "Hinzufügen\nbeenden!", command = HinzufügenBeenden)
eingabe = Entry(fenster)
ende = Button(fenster, text = "Beenden", command = Ende)

#Bauteile packen
DatumsLabel.grid(row = 0, column = 1, padx= 5 , pady= 5)
UhrzeitLabel.grid(row = 0, column = 0, padx= 5 , pady= 5)
WillkommensLabel.grid(row = 1, column = 0, columnspan= 2, padx= 5 , pady= 5)
namenbox.grid(row = 2, column = 0, padx= 5 , pady= 5)
punktebox.grid(row = 2, column = 1, padx= 5 , pady= 5) 
Button1.grid(row= 3,  column = 0, padx= 5 , pady= 5)
Button2.grid(row = 3, column = 1, padx= 5 , pady= 5)
info1.grid(row= 4, column = 0, padx= 5 , pady= 5, columnspan= 2)
info2.grid(row = 5, column = 0, padx= 5 , pady= 5, columnspan = 2)
ende.grid(row = 7, column =  0, padx= 5 , pady= 5, columnspan= 2)

#Listboxen befüllen
for name in listeNamen:
    namenbox.insert("end", name)

for punkte in punktestand:
    punktebox.insert("end", punkte)

#Uhrzeit aktualisieren
U = threading.Thread(target = Uhrzeitschleife)
U.start()

#Fenster starten
fenster.mainloop()
Ich sitze und probiere da jetzt schon sehr lange dran und wär auf eine hilfreiche Antwort unglaublich dankbar.
Um noch Verständisfragen bezüglich meines Programmes zu klären: Das Programm speichert die Spieler und dessen Punktezahl fürs nächste Benutzen. Wenn sie das Programm ausprobieren wollen, müssen sie noch schnell ein Textdokument anlegen oder es auskommentieren!
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Mir fallen bei dem ersten Ansehen ein paar Dinge auf, weshal ich nicht tiefer in den Code einsteige:

Du verwendest globale Variablen. Das ist ein No-Go. Funktionen bekommen alles, was sie brauchen, als Parameter und geben das Ergebnis mit return zurück. Wenn man einen Status über einen Methodenaufruf beibehalten möchte, verwendet man Objektorientierte Programierung.
Globale Variablen machen das Programm unwart- und vor allem undebugbar.

Namen schreibt man in Python klein_mit_unterstrich. Ausgenommen Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Keine *-Importe!
Verwende "import tkinter as tk".

Normalerweise startet man ein Python-Programm, indem man eine Funktion "main" definiert und die dann wie folgt aufruft:

Code: Alles auswählen

if __name__ == "main":
    main()
Das tut man, damit das Programm nichts ausführt, wenn man es importiert.
Auf Modulebene, als uneingerückt, gehören nur die Impote, die Definitionen von Klasen und Funktionen und die von Konstanten. Keine Variablen, kein sonstiger Code (außer der oben genannte Einstiegspunkt am Ende des Files).
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

sparrow hat geschrieben: Samstag 16. April 2022, 21:21 Wenn man einen Status über einen Methodenaufruf beibehalten möchte, verwendet man Objektorientierte Programierung.
Globale Variablen machen das Programm unwart- und vor allem undebugbar.
Das sammlen sich schon gleich ein paar Fragen...
Zuerst einmal. Ich bin Anfänger und versuche mir den Stuff selber beizubringen!
Mit globalen Variablen meinst du wahrscheinlich "global fenstergeschlossen". Das war nur ein Versuch dem Thread irgendwie mitzuteilen, wann das Fenster geschlossen ist. Stattdessen verwende ich einfach: return fenstergeschlossen oder wie?
Zudem habe ich leider keinen blassen Schimmer, was mit eine, Methodenabruf gemeint ist. Das "fenstergeschlossen"?

Zu den Importen:
Manchmal passiert es, dass es einzelne Befehle nicht kennt. Da hat es mir geholfen alles zun importieren. Eine Idee, wie ich das Problem in Zukunft anders lösen könnte?

Ich wär ihnen dankbar, wenn sie mir die Fragen beantworten könnten und eventuell doch mal tiefer ins Programm schauen würden!
LG
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Und zusätzlich zu dem was sparrow schreibt: Dateien, die man öffnet sollte man auch wieder schließen, bei close fehlen die Klammern und das immer. Statt sich selbst ein Datenformat auszudenken benutzt man was fertiges, wie z.B. json.
Nackte except benutzt man nicht. Man gibt immer eine Exception an und zwar die, die man erwartet. In Deinem Fall wäre aber ein if und der in-Operator besser.
Ein else: pass macht nichts, kann also weg.

Und nun zum üblichen Problem: Threads und GUIs vertragen sich nicht. Die GUI darf nur aus dem Hauptprogramm aus verändert werden. Du brauchst auch keine Threads. Ein einfacher Callback per after genügt.
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Loster_Paddel: Nein mit globalen Variablen sind nicht nur die beiden Namen gemeint die mit ``global`` in einer Funktion so deklariert wurden sondern alle die nicht lokal in einer Funktion existieren. Du hast da 9 Funktionen die alle *gar keine* Argumente übergeben bekommen, aber alle irgendwas benutzen was nicht nur lokal existiert. Auf Modulebene sollten gar keine Variablen existieren, nur Konstanten, Funktionen, und Klassen sollten dort definiert werden.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
dirk009
User
Beiträge: 27
Registriert: Donnerstag 3. Juni 2021, 21:49

Hallo Loster_Paddel,

die Antwort von Sirius3 war Gold wert. Du kannst den ganzen Thread-Code entfernen und ein Zweizeiler, der sich rekursiv aufruft reicht:

Code: Alles auswählen

def uhrzeit_aktualisieren():
        UhrzeitLabel.config(text=datetime.now().strftime('%H:%M:%S'))
        UhrzeitLabel.after(1000, uhrzeit_aktualisieren)
        
Bei mir kam immer der Beachball beim Beenden, aber nach der Umstellung auf after beendet das Programm sich unverzüglich.


Hier der bereinigte Code (Ich habe die Datei umbenannt.)

Code: Alles auswählen

import tkinter as tk
from tkinter import messagebox
from datetime import date, datetime

# Daten einlesen
file = open("punktezaehler_daten.txt", "r")
spieler = file.readline().strip()
punkte = file.readline().strip()
datum = file.readline()
file.close()

# Daten bearbeiten und Format anpassen
listeNamen = spieler.split(" ")
punktestand = punkte.split(" ")
print(punktestand)
punktestand = list(map(int, punktestand))

# Erzeugen des Fensters
fenster = tk.Tk()
fenster.title("Punktezähler")
fenstergeschlossen = False
# Alle Definitionen:

HeuteDatum = date.today().strftime("%d.%m.%Y")


# Startdefinitionen
def ja():
    Button1.config(text="Info!", command=information)
    Button2.config(text="Hinzufügen!", command=hinzufügen)
    eingabe.grid(row=6, column=0, padx=5, pady=5, columnspan=2)
    info1.config(text="")
    info2.config(text="")


def nein():
    global listeNamen, punktestand
    listeNamen = []
    punktestand = []
    print(listeNamen)
    namenbox.delete(0, tk.END)
    punktebox.delete(0, tk.END)
    info1.config(text="")
    info2.config(text="")
    Button1.config(text="Info!", command=informationNeueDaten)
    Button2.config(text="Hinzufügen!", command=SpielerHinzufügen)
    eingabe.grid(row=6, column=0, padx=5, pady=5, columnspan=2)
    Button3.grid(row=7, column=0, padx=5, pady=5)
    ende.grid(row=7, column=1, padx=5, pady=5)


def informationNeueDaten():
    info1.config(text="Spieler unten eingeben!")
    info2.config(text="Und auf Hinzufügen klicken!")


def SpielerHinzufügen():
    NeuerSpieler = eingabe.get()
    info1Inhalt = info1.cget("text")

    if info1Inhalt == "Unbedingt Spieler eingeben!" or info1Inhalt == "Es gibt diesen Spieler bereits schon!":
        info1.config(text="")

    if NeuerSpieler == "":
        info1.config(text="Unbedingt Spieler eingeben!")
        info2.config(text="")

    else:
        try:
            listeNamen.index(NeuerSpieler)

        except:
            listeNamen.append(NeuerSpieler)
            punktestand.append(0)
            namenbox.insert("end", listeNamen[-1])
            punktebox.insert("end", punktestand[-1])
            print(listeNamen, "\n", punktestand)
        else:
            info1.config(text="Es gibt diesen Spieler bereits schon!")
        eingabe.delete(0, "end")


def HinzufügenBeenden():
    Button1.config(command=information)
    Button2.config(command=hinzufügen)
    info1.config(text="")
    info2.config(text="")
    Button3.destroy()
    ende.grid(row=7, column=0, padx=5, pady=5, columnspan=2)


# Hauptteildefinitionen
def information():
    ausgewählt = namenbox.curselection()
    if len(ausgewählt) == 0:
        info1.config(text="Wählen sie zuerste einen Spieler aus! (Klicken)")
    else:
        info1.config(text="Sie haben " + str(listeNamen[int(ausgewählt[0])] + " ausgewählt!"))
        info2.config(text="Geben Sie die gewünschte zu addierende Punktzahl ein:")
        print(ausgewählt)


def hinzufügen():
    ausgewählt = namenbox.curselection()
    PlusPunktzahl = eingabe.get()
    print(ausgewählt)

    # Vorbeugung möglicher Fehler
    if len(ausgewählt) == 0:
        info1.config(text="Wählen sie zuerste einen Spieler aus! (Klicken)")
    elif PlusPunktzahl == "":
        info1.config(text="Unbedingt eine gültige Punktzahl eingeben!")
    elif int(PlusPunktzahl) <= 0:
        info1.config(text="Unbedingt eine gültige Punktzahl eingeben!")
        eingabe.delete(0, "end")
    else:
        print(PlusPunktzahl)
        punktestand[int(ausgewählt[0])] += int(PlusPunktzahl)
        punktebox.delete(int(ausgewählt[0]))
        punktebox.insert(int(ausgewählt[0]), punktestand[int(ausgewählt[0])])
        eingabe.delete(0, "end")
        info1.config(text="")
        print(punktestand)


def uhrzeit_aktualisieren():
        UhrzeitLabel.config(text=datetime.now().strftime('%H:%M:%S'))
        UhrzeitLabel.after(1000, uhrzeit_aktualisieren)


# Zerstörung des Labels + Schreiben in die Datei
def Ende():
    if messagebox.askyesno('Sicher?', 'Wirklich beenden?'):
        fenster.destroy()
        global fenstergeschlossen
        fenstergeschlossen = True
        # Schreiben in die Datei
        file = open("punktezaehler_daten.txt", "w")
        NamenslisteString = " ".join(listeNamen)
        print(NamenslisteString)
        PunkteListeString = " ".join(map(str, punktestand))

        file.write(NamenslisteString + "\n")
        file.write(PunkteListeString + "\n")
        file.write(str(HeuteDatum))
        file.close()



# Ende der Definitionen

# Bauteile erstellen
DatumsLabel = tk.Label(fenster, text=date.today().strftime("%d.%m.%Y"), justify=tk.RIGHT)
UhrzeitLabel = tk.Label(fenster, text=datetime.now().strftime('%H:%M'))
WillkommensLabel = tk.Label(fenster, text="Herzlich willkommen zum epischen Punktezähler! ")
namenbox = tk.Listbox(fenster, highlightcolor="red")
punktebox = tk.Listbox(fenster, highlightcolor="red")
info1 = tk.Label(fenster, text="Daten vom: " + datum + " verwenden?")
info2 = tk.Label(fenster, text="Ja/Nein ")
Button1 = tk.Button(fenster, text="Ja!", command=ja)
Button2 = tk.Button(fenster, text="Nein!", command=nein)
Button3 = tk.Button(fenster, text="Hinzufügen\nbeenden!", command=HinzufügenBeenden)
eingabe = tk.Entry(fenster)
ende = tk.Button(fenster, text="Beenden", command=Ende)

# Bauteile packen
DatumsLabel.grid(row=0, column=1, padx=5, pady=5)
UhrzeitLabel.grid(row=0, column=0, padx=5, pady=5)
WillkommensLabel.grid(row=1, column=0, columnspan=2, padx=5, pady=5)
namenbox.grid(row=2, column=0, padx=5, pady=5)
punktebox.grid(row=2, column=1, padx=5, pady=5)
Button1.grid(row=3, column=0, padx=5, pady=5)
Button2.grid(row=3, column=1, padx=5, pady=5)
info1.grid(row=4, column=0, padx=5, pady=5, columnspan=2)
info2.grid(row=5, column=0, padx=5, pady=5, columnspan=2)
ende.grid(row=7, column=0, padx=5, pady=5, columnspan=2)

# Listboxen befüllen
for name in listeNamen:
    namenbox.insert("end", name)

for punkte in punktestand:
    punktebox.insert("end", punkte)

# Uhrzeit aktualisieren
uhrzeit_aktualisieren()

# Fenster starten
fenster.mainloop()

PS: Hier ein Tutorial zu after: https://www.pythontutorial.net/tkinter/tkinter-after/
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@dirk009: Da wird nichts rekursiv aufgerufen. Rekursive Aufrufe hat man wenn in einem einzelnen Thread eine Funktion aufgerufen wird, während ein vorheriger Aufruf der Funktion noch aktiv ist. Das ist hier nicht der Fall. Es ist immer nur ein Aufruf von `uhrzeit_aktualisieren()` zu jedem gegeben Zeitpunkt aktiv. Bevor die Funktion wieder aufgerufen wird, ist der vorherige Aufruf immer schon zu seinem Aufrufer (aus der Hauptschleife) zurückgekehrt.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

Erstmal bin ich Ihnen unfassbar dankbar für die schnellen Antworten. Da ich aber natürlich noch bessere werden und lernen möchte, habe ich noch ein paar Fragen.

@Sirius3 Mein except ist doch nicht nackt oder verstehe ich das falsch?

@Dirk009 Vertsehe ich das after() richtig, dass es die Funktion und damit sich selbst immer wieder selbst aufruft? Also wie ein thread nur ohne Schleife?

@Dirk009 Bedeutet Beachball, dass es immer weiterläuft oder wie kann ich das verstehen?

Wie ich schon gesagt habe, möchte ich in nächster Zeit noch mit Tastatur bzw. Benutzereingaben arbeiten. Hierfür benutze ich die libary: keyboard. Der computer muss ja deswegen die ganze Zeit schauen ob eine solche Eingabe erfolgt ist. Mache ich das hier dann wieder mit after()? Da er ja auch relativ schnell reagieren soll müsste ich ja dann die Millisekunden im after runterschrauben. Verkraftet der Computer bzw. das Programm das denn, wenn etwas so schnell und oft etwas ausführt oder ist das ein no go?

Ansonsten schon einmal vielen Dank
LG
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da hinter dem except keine konkrete Ausnahme steht, ist das nackt. Das bedeutet, es werden auch alle moeglichen Fehler abgefangen, die gar nichts mit den eigentlich zu erwartenden Fehlerfaellen zu tun haben. ZB Namensfehler, durch falsche Programmierung.

Code: Alles auswählen

try:
    foo = 100
    print(foob ** 2)
except:
    print("Programmierfehler verschleiert")
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

@Loster_Paddel: das Modul `keyboard` ist nicht für Benutzereingaben gedacht. Dafür gibt es in TkInter `bind`. Davor solltest Du aber dringend das Problem mit globalen Variablen beheben.
dirk009
User
Beiträge: 27
Registriert: Donnerstag 3. Juni 2021, 21:49

Loster_Paddel hat geschrieben: Dienstag 19. April 2022, 10:02 @Dirk009 Vertsehe ich das after() richtig, dass es die Funktion und damit sich selbst immer wieder selbst aufruft? Also wie ein thread nur ohne Schleife?
Ja, allerdings indirekt durch Neuregistrierung. Die Funktion wird dann vom GUI-Thread aufgerufen.


https://web.archive.org/web/20201112021 ... ter-method
after(delay_ms, callback=None, *args) [#]
Registers an alarm callback that is called after a given time.

This method registers a callback function that will be called after a given number of milliseconds. Tkinter only guarantees that the callback will not be called earlier than that; if the system is busy, the actual delay may be much longer.

The callback is only called once for each call to this method. To keep calling the callback, you need to reregister the callback inside itself:

class App:
def __init__(self, master):
self.master = master
self.poll() # start polling

def poll(self):
... do something ...
self.master.after(100, self.poll)

Loster_Paddel hat geschrieben: Dienstag 19. April 2022, 10:02
@Dirk009 Bedeutet Beachball, dass es immer weiterläuft oder wie kann ich das verstehen?
Der spinning beach ball of death (https://en.wikipedia.org/wiki/Spinning_pinwheel) wird nach dem Schliessen des Fensters angezeigt, solange dein Uhrzeit-Thread sich noch nicht selbst beendet hat. Im Extremfall noch59 Sekunden lang.
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

Sirius3 hat geschrieben: Dienstag 19. April 2022, 10:23 @Loster_Paddel: das Modul `keyboard` ist nicht für Benutzereingaben gedacht. Dafür gibt es in TkInter `bind`. Davor solltest Du aber dringend das Problem mit globalen Variablen beheben.
Stimmt das mit den Events ist schon echt besser. Wie man erkennt wechseln sie commands der einzelnen Buttons (Deswegen auch der bescheuerte Name). Wie kann ich denn ein schon gebindetes Event bearbeiten? Ich habe da nichts gefunden...

Wieso sind für die Events die globalen Variablen so ein großes Problem?
LG
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

Sirius3 hat geschrieben: Dienstag 19. April 2022, 10:23 Davor solltest Du aber dringend das Problem mit globalen Variablen beheben.
Wie kriege ich denn zum Beispiel das weg?

Code: Alles auswählen

# Daten einlesen
file = open("punktezaehler_daten.txt", "r")
spieler = file.readline().strip()
punkte = file.readline().strip()
datum = file.readline()
file.close()

# Daten bearbeiten und Format anpassen
listeNamen = spieler.split(" ")
punktestand = punkte.split(" ")
print(punktestand)
punktestand = list(map(int, punktestand))

# Erzeugen des Fensters
fenster = tk.Tk()
fenster.title("Punktezähler")
fenstergeschlossen = False
Mit einer Funktion dateiEinlesen() und dann einmal aufrufen oder wie macht man das?

LG
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

dirk009 hat geschrieben: Sonntag 17. April 2022, 23:06

Code: Alles auswählen

def uhrzeit_aktualisieren():
        UhrzeitLabel.config(text=datetime.now().strftime('%H:%M:%S'))
        UhrzeitLabel.after(1000, uhrzeit_aktualisieren)
Wenn ich das Label jetzt mit:

Code: Alles auswählen

UhrzeitLabel.destroy()
zerstöre... Läuft die Funktion immernoch weiter?

LG
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Das kannst Du doch selbst herausfinden.
Und um die Antwort gleich zu geben, nein, so was sollte man nicht machen, weil das Fehlermeldungen provoziert.
Es ist auch selten eine gute Idee, den Inhalt eines Fensters zu zerstören. Fenster sollten etwas fixes sein, alles andere verwirrt den Nutzer.
Antworten