Textbox Text wird nicht angezeigt

Fragen zu Tkinter.
Antworten
Arabio
User
Beiträge: 5
Registriert: Montag 25. Oktober 2021, 08:20

Moin brauche bei meinem Vokabeltrainer Hilfe!
Es wird der erste Text nicht angezeigt in der Textbox, der Letzte allerdings schon

Code: Alles auswählen

    c = 0
    while c<301:
        if c == 10:
            d = 0
            while d<401:
                d = d + 1
                if d == 101:
                    Textbox.delete(1.0,END)
                    i = random.randint(0,len(eintraege)-1)        #es wird eine Zufallszahl von 0 bis zur Länge der Einträge-1 erstellt
                    Textbox.insert(1.0, "Englische Übersetzung von " + eintraege[i].deutsch + " du hast 8 Sekunden!")
        c = c+1
        if c == 301:
            englisch = Textbox.get(1.0, END)
            if eintraege[i].englisch == englisch:
                Textbox.delete(1.0, END)
                Textbox.insert(1.0, "richtig!")
            else:
                Textbox.delete(1.0, END)
                Textbox.insert(1.0, "falsch! Die richtige Antwort ist:" + eintraege[i].englisch)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Die while-Schleife ist etwas komisch, weil exakt zu zwei c-Werten etwas gemacht wird, und zwar das, was in den passenden if-Blöcken steht, die while-Schleife kann also weg, ebenso die Schleife über d, was den Code schon sehr viel übersichtlicher macht:

Code: Alles auswählen

Textbox.delete(1.0,END)
i = random.randint(0,len(eintraege)-1)        #es wird eine Zufallszahl von 0 bis zur Länge der Einträge-1 erstellt
Textbox.insert(1.0, "Englische Übersetzung von " + eintraege[i].deutsch + " du hast 8 Sekunden!")

englisch = Textbox.get(1.0, END)
if eintraege[i].englisch == englisch:
    Textbox.delete(1.0, END)
    Textbox.insert(1.0, "richtig!")
else:
    Textbox.delete(1.0, END)
    Textbox.insert(1.0, "falsch! Die richtige Antwort ist:" + eintraege[i].englisch)
Statt randint würde man direkter randrange, hier aber einfach choice.
Statt Strings mit + zusammenzustückeln benutzt man Formatstrings.
Wenn etwas sowohl im if als auch im else-Block vorkommt, kann man es manchmal auch außerhalb schreiben.

Code: Alles auswählen

Textbox.delete(1.0,END)
vokabel = random.choice(eintraege)
Textbox.insert(1.0, f"Englische Übersetzung von {vokabel.deutsch} du hast 8 Sekunden!")

englisch = Textbox.get(1.0, END)
Textbox.delete(1.0, END)
if vokabel.englisch == englisch:
    Textbox.insert(1.0, "richtig!")
else:
    Textbox.insert(1.0, f"falsch! Die richtige Antwort ist: {vokabel.englisch}")
Du schreibst also in die Textbox etwas, was gleich wieder ausgelesen wird, den Schritt kannst Du Dir also sparen:

Code: Alles auswählen

vokabel = random.choice(eintraege)
englisch = f"Englische Übersetzung von {vokabel.deutsch} du hast 8 Sekunden!"

if vokabel.englisch == englisch:
    ergebnis = "richtig!"
else:
    ergebnis = f"falsch! Die richtige Antwort ist: {vokabel.englisch}"
Textbox.delete(1.0, END)
Textbox.insert(1.0, ergebnis)
Die if-Bedingung ist nur dann erfüllt, wenn sehr seltsamer Text also Englische Vokabel in gespeichert ist. Ich vermute mal, dass das nie der Fall ist.

Bei Deiner Frage fehlt der Kontext, den man sich zusammenreimen muß. Du willst ein Vokabelprogramm schreiben, bei dem der Nutzer 8 Sekunden Zeit haben soll, etwas einzutragen. Dir ist als Lösung eine while-Schleife eingefallen, mit der das aber nicht funktioniert, weil so GUIs nicht arbeiten, sie arbeiten ereignisbasiert.
Du mußt also nach dem Anzeigen der deutschen Variable einen callback per after registrieren, der nach 8 Sekunden eine weitere Funktion aufruft, die dann das Ergebnis prüft.

Sonstige Anmerkungen: Sternchenimporte benutzt man nicht, tkinter wird üblicherweise per `import tkinter as tk` importiert und alle Namen per tk.xyz angesprochen. Variablennamen schreibt man nach Konvention komplett klein. Alles was eine Funktion braucht, muß sie über ihre Argumente bekommen, benutze KEINE globalen Variablen. Für GUI Programme braucht man üblicherweise Klassendefinitionen.
Arabio
User
Beiträge: 5
Registriert: Montag 25. Oktober 2021, 08:20

Guten Abend.
Vielen Dank für die Hilfe!
Es tut mir leid, dass ich nur einen Ausschnitt vom Programm gezeigt habe, dadurch ist es, wie Sie schon erwähnt haben, schwierig den Kontext zu verstehen. Ihr Beitrag hat mir weiter geholfen und auch die Tipps sind hilfreich. Allerdings, brauche ich nochmal Unterstützung, denn wenn ich jetzt den Code ausführe passiert 8 Sekunden nichts und die Lösung wird angezeigt.

Unten ist diesmal das ganze Programm zu sehen. Bitte habt aber im Hinterkopf, dass dies mein erstes Programm mit GUI ist und ich generell noch sehr uneffizient programmiere. Ich bin gerne für Verbesserungsschläge offen, möchte aber erstmal dieses Problem bewältigt bekommen. :D
Schönen Abend und nochmals großen Dank

Code: Alles auswählen

from tkinter import *  
import random
import time                     #ein paar nützliche Module werden importiert
class Eintrag:                  #Klasse Eintrag wird definiert
    def __init__(self, deutsch, englisch): #Innitialisierung
        self.deutsch = deutsch
        self.englisch = englisch
    def __str__(self):                     #Funktion die wir später noch benötigen zum Anzeigen der Vokabeln
        return self.deutsch + " - " + self.englisch
global englisch
eintraege = []                             #Liste wird erstellt um Vokabeln vorübergehend zu speichern
fenster = Tk()
fenster.resizable(False,False)
fenster.title("Vokabeltrainer")
fenster.geometry("550x550")                #Fenster wird erstellt
Textbox = Text(fenster, height=13, width=30,font=("Helvetica", 15))
Textbox.pack()
Textbox.place(x=40, y=60)                  #Textbox wird erstellt
Überschrift = Label(text="Vokabeltrainer")
Überschrift.config(font=("Times", 20))
Überschrift.pack()                         #Überschrift "Vokabeltrainer" wird erstellt
def eingabe():
    Textbox.delete(1.0, END)                            #Textbox wird geleert und sagt was als nächstes
    Textbox.insert(1.0, "Schreibe das deutsche Wort")   #getan werden muss °^°
def deutscheingabe():
    global deutsch
    deutsch = Textbox.get(1.0, END)                     #das deutsche Wort wird in einer Variable gespeichert
    Textbox.delete(1.0, END)                            
    Textbox.insert(1.0, "Schreibe das englische Wort")  #der Text der Textbox ändert sich
def englischeingabe():
    englisch = Textbox.get(1.0, END)                    #das englische Wort wird in einer Variable gespeichert
    eintraege.append(Eintrag(deutsch,englisch))         #neuer Eintrag wird erstellt und in Liste gespeichert
    Textbox.delete(1.0, END)
def abfrage():
    vokabel = random.choice(eintraege)
    englisch = f"Englische Übersetzung von {vokabel.deutsch} du hast 8 Sekunden!"
    Textbox.delete(1.0, END)
    Textbox.insert(1.0, englisch)
    def Überprüfung():
        if vokabel.englisch == englisch:
            ergebnis = "richtig!"
        else:
            ergebnis = f"falsch! Die richtige Antwort ist: {vokabel.englisch}"
        Textbox.delete(1.0, END)
        Textbox.insert(1.0, ergebnis)
    Textbox.after(8000, Überprüfung())
    
def printall():
    Textbox.delete(1.0, END)
    for eintrag in eintraege:
        Textbox.insert(1.0,eintrag.__str__())
buttonweiter = Button(master=fenster, text="weiter", command=deutscheingabe)
buttonweiter.place(x=400, y=200, width=100, height=25)
buttonfertig = Button(master=fenster, text="fertig", command=englischeingabe)
buttonfertig.place(x=400, y=270, width=100, height=25)
buttonEingabe = Button(master=fenster, text="neue Vokabel eingeben!", command=eingabe)
buttonEingabe.place(x=150, y=400, width=200, height=25)
buttonAbfragen = Button(master=fenster, text="Vokabeln abfragen", command=abfrage)
buttonAbfragen.place(x=150, y=450, width=200, height=25)
buttonAusgabe = Button(master=fenster, text="alle Vokabeln anzeigen", command=printall)
buttonAusgabe.place(x=150, y=500, width=200, height=25)                    #mehrere Knöpfe werden erstellt
imageBild = PhotoImage(file='Bild1.png')
labelBild1 = Label(image=imageBild)
labelBild1.place(x=480, y=480, width=60, height=60)           #Bild wird reingeladen
def Beenden():                                                #Funktion welche das Programm beenden kann
    Textbox.delete(1.0, END)
    Textbox.insert(1.0, "Bye Bye! :D")                        #inklusive Verabschiedung
    def Beendenbeenden():
        fenster.destroy
        exit()
    Textbox.after(700, Beendenbeenden)
buttonschließen = Button(master=fenster, text="Schliessen", command=Beenden)
buttonschließen.place(x=20, y=500, width=100, height=25)                        #Knopf um Programm zu beenden
mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Arabio: Du rufst die Methode *sofort* auf und übergibst den Rückgabewert an `after()` statt die Methode. Lass die Klammern für den Aufruf weg.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Arabio
User
Beiträge: 5
Registriert: Montag 25. Oktober 2021, 08:20

@__blackjack__ : Tut mir leid, aber irgendwie verstehe ich das nicht und weiß auch nichts mit Ihrem Code anzufangen. Trotzdem danke für die Antwort
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Arabio: Runde Klammern bedeuten nach einem Ausdruck: aufrufen, *jetzt*. Das willst Du aber gar nicht. Du willst `Überprüfung` nicht selbst aufrufen und das Ergebnis an `after()` übergeben, sondern Du willst die Funktion `Überprüfung` an `after()` übergeben, damit die GUI-Hauptschleife das nach 8 Sekunden aufruft.

Letztlich sieht der gesamte Code aber auch danach aus, als wenn GUI-Programmierung viel zu weit ist. Da steht eigentlich die Verwendung von Funktionen, und der Code hat keine einzige die den Namen verdient hätte, und dann Klassen, davor. Das sollte man können bevor man mit GUI-Programmierung anfängt, denn das sind Voraussetzungen dafür.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten