Ergebnisse auswerten und Schleife weiterlaufen lassen

Fragen zu Tkinter.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Hallo,

wie kann man es schaffen, dass man mit tkinter eine Nutzereingabe überprüft?

Zum genauen Problem: Ich bin noch ziemlicher Anfänger in Sachen programmierung und habe ein Programm (in der Kommandozeile) entwickelt, dass dem Nutzer per Zufallszahlen Rechenaufgaben erstellt, die dann gelöst werden sollen. Auf der Kommandozeile ist das kein Problem: mit der input-Anweisung frage ich nach einer Eingabe. Ist die Aufgabe richtig, dann läuft die Schleife weiter und gibt die nächste Aufgabe aus.

Aber bei tkinter komme ich an meine Grenzen: Wie mache ich klar, dass beim Klick auf eine Button die Nutzereingabe aus einer Textbox verarbeitet wird und vor allem die Schleife dann weiterläuft und die nächste Aufgabe ausgibt?

Vielen Dank für eure Ideen.
Benutzeravatar
__blackjack__
User
Beiträge: 14085
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cortez: Das funktioniert in GUIs komplett anders. Da hat die GUI-Hauptschleife die Kontrolle und nicht eine Schleife die Du programmiert hast. GUIs funktionieren ereignisbasiert. Du erstellst die GUI und registrierst Rückruffunktionen/-Methoden die bei bestimmten Ereignissen aufgerufen werden, und dann kurz etwas machen. Da man sich in jedem nicht-trivialen GUI-Programm Zustand über aufrufe hinweg merken muss, braucht man für GUIs objektorientierte Programmierung (OOP), muss also also eigene Klasse(n) schreiben.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok, das ist mir schon klar. Aber was müsste ich da umbauen. Also, ich möchte ja, dass bei einem auf den Button die Ergebniskontrolroutine aufgerufen wird. Soweit würde ich es wohl auch hinbekommen.

Es hängt bei mir nur, dass dann halt die Schleife nicht mehr weiterläuft.

Mit objektorientierter Programmierung habe ich auch das Programm auf der Kommandozeile erstellt.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei einer GUI darf es keine Schleife geben, das mußt Du anders lösen, z.B. indem Du den Zustand bis zum nächsten Ereignis merkst.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok. Stichwort:yield

Käme man damit der Sache näher?

Kann man bei GUI Schleifen wirklich nirgens brauchen? Und ich dachte, die wären wichtig zu beherrschen...
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Nein, mit yield kommst Du auch nicht weiter. Natürlich kann man Schleifen brauchen, nur bestimmte Arten von Schleifen müssen bei GUIs komplett anders umgesetzt werden.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok, was wäre dann eine Möglichkeit. Bräuchte nur ein Stichpunkt, dass ich weitermachen kann.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mit Schleifen hat das erstmal nichts zu tun. Es geht einzig und alleine um die Zeit, die ein Stück Code braucht. Wenn da eine Schleife drin ist, aber er nur Sekundenbruchteile braucht, dann passt das schon. Und auch ganz ohne Schleife kann zb das abfragen eines externen Services Sekunden oder gar minutenlang blockieren, und ist dann ganz ohne Schleife auch ein Problem.

Hier im Forum wird diese Frage auch permanent diskutiert. Stichworte sind Timer, in tkinter mit “after” zu bekommen, Threads und Queues. Einfach mal ein bisschen stöbern.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok, danke erstmal. Ich schaue mich mal um danach. Ich verstehe nur nicht, warum ein Timer. Das Ergebnis soll ja erst (nur) überprüft werden, wenn der entsprechende Button gedrückt wird.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Solange Du keinen Code zeigst, wird man dir nicht mit konkreteren Hinweisen helfen können.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Code: Alles auswählen

import random
import math
import time
import sys

class Spiel:
    def __init__(self, anzahl,typ):
        self.anzahl = anzahl
        self.typ = typ
        self.korrekte_Aufgaben = 0
        self.falsche_Aufgaben = 0
        self.name = input ("Dein Name?")
        
        if self.typ == 1:
            self.leichte_aufgabe(anzahl)
            
        elif self.typ == 2:
            self.schwere_aufgabe(anzahl)
            
        elif self.typ == 3:
            self.speedrechnen(hs)
        else:
            hs.lesen()
            
    def speedrechnen(self,hs):
        startzeit,zielzeit = self.hole_zeit()
        z = 0
        while startzeit < zielzeit:
            #print (startzeit)
            y=self.leichte_aufgabe(1)
            startzeit = int(round(time.time(),0))
            #time.sleep(1)
            if y == True:
                z+=1
            print ("Startzeit: ",startzeit)
            print ("Zielzeit: ",zielzeit)
        print ("Sie haben innerhalb ", zielzeit - startzeit," ",z," Aufgaben gelöst")
        
        hs.dateieintrag(self.name,z)
            
            
    def hole_zeit(self):
        startzeit = int(round(time.time(),0))
        zielzeit = startzeit +10
        return startzeit,zielzeit
            
    def leichte_aufgabe(self,anzahl):
        for j in range(0, anzahl):
            br1 = bruch()
            br1.ausgabe()
            br1.kuerze_bruch()
            
            z = self.eingaberoutine(br1)
            print (z)
            self.statistik(z,anzahl)
            if (z == 1 and anzahl == 1) or j == anzahl:
                return True
           
            
    def schwere_aufgabe(self, anzahl):
        for j in range(0,anzahl):
            vorz = self.vorzeichen()
            br1 = bruch()
            br2 = bruch()
            if vorz == "+":
                print (br1, " + ",br2)
                erg_z,erg_n=br1.addiere(br2)
            elif vorz == "-":
                print (br1, " - ", br2)
                erg_z,erg_n=br1.subtrahiere(br2)
            elif vorz == "*":
                print (br1, " * ", br2)
                erg_z,erg_n=br1.multipliziere(br2)
            else:
                print (br1, " / ", br2)
                erg_z,erg_n=br1.dividiere(br2)
            
            br1 = bruch(erg_z,erg_n)
            br1.kuerze_bruch()
            br1.ausgabe()
            z = self.eingaberoutine(br1)
            self.statistik(z, anzahl)
            
    def eingaberoutine(self,br1):
        erg_z = 0
        erg_n = 0
        
        for i in range(1,4):
            erg_z = input ("Zaehler?")
            erg_n = input ("Nenner?")
            erg_z = int (erg_z)
            erg_n = int(erg_n)
            if erg_z == br1.zehler and erg_n == br1.nenner:
                print ("richtig. Sie brauchten Versuche:  ", i)
                return i
            
            elif (erg_z != br1.zehler or erg_n != br1.nenner) and i == 3:
                print ("Zu viele Versuche, nämlich ",i,)
                return i
            else:
                print ("falsch")
                
       
    def statistik(self, z, anzahl):
        if z == 1:
            
            self.korrekte_Aufgaben += 1
        elif z == 2:
            
            self.falsche_Aufgaben += 1
        else:
            
            self.falsche_Aufgaben += 1
            
        if self.korrekte_Aufgaben + self.falsche_Aufgaben == anzahl:
            quote = round(self.korrekte_Aufgaben/anzahl*100,2)
            print ("Sie haben ", self.korrekte_Aufgaben, " von ", anzahl, " Aufgaben richtig geloest, also ", quote, " %")
            
    def vorzeichen(self):
            random.seed()
            vorz=random.randint(1,4)
        
            if vorz == 1:
                return "+"
            elif vorz == 2:
                return "-"
            elif vorz == 3:
                return "*"
            else:
                return "/"
            


class bruch:
    def __init__(self,zehler=0,nenner=0):
        self.zehler=zehler
        self.nenner=nenner
        if zehler==0 or nenner ==0:
            wert_zehler = self.generiere_bruchzahl()
            wert_nenner = self.generiere_bruchzahl()
            self.zehler += wert_zehler
            self.nenner += wert_nenner
        
       
        
    def __str__(self):
        return str(self.zehler) + "/" + str(self.nenner)
    
    def generiere_bruchzahl(self):
        prob = 2,2,2,2,3,3,3,5,5,7
        wert = 1
        
        random.seed()
        anz = random.randint(2,5)
    
        for i in range(1,anz):
            wert *=random.choice(prob)
        
        
        return wert
    
    def kuerze_bruch(self):
        ggt = math.gcd(self.zehler,self.nenner)
        self.zehler = self.zehler / ggt
        self.nenner = self.nenner / ggt
        self.zehler = int(self.zehler)
        self.nenner = int(self.nenner)
        
    def mache_nennergleich(self,other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        print (self)
        print (other)
        
        
        counter=1
        counter_b=1
    
        while self.nenner != other.nenner:
        
            if self.nenner < other.nenner:
                self.nenner += (self.nenner / counter)
                #print ("Nenner_a ", self.nenner)
                counter +=1
            
            if other.nenner < self.nenner:
                other.nenner += (other.nenner / counter_b)
                #print ("Nenner_b ", other.nenner)
                counter_b +=1
        
            if self.nenner == other.nenner:
                break
            
        self.zehler *= counter
        other.zehler *= counter_b
        self.nenner = int(self.nenner)
        other.nenner = int(other.nenner)
        return self, other
        
    def addiere(self,other):
        if self.nenner != other.nenner:
            self,other=self.mache_nennergleich(other)
        
        ergebnis = self.zehler + other.zehler
        nenner = self.nenner
        return ergebnis,nenner
        
    def subtrahiere(self, other):
        if self.nenner != other.nenner:
            self, other = self.mache_nennergleich(other)
    
        ergebnis = self.zehler -other.zehler
        nenner = self.nenner
        return ergebnis,nenner
    
    def multipliziere(self, other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        erg_z = self.zehler*other.zehler
        erg_n = self.nenner*other.nenner
        return erg_z, erg_n
    
    def dividiere(self,other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        erg_z = self.zehler*other.nenner
        erg_n = self.nenner*other.zehler
        return erg_z, erg_n
            
    def ausgabe(self):
        print (self.zehler, " / ", self.nenner)
        
        
class Highscore():
    #def __init__(self):
        
    def dateieintrag(self, name, z):
        lt = time.localtime()
        try:
            datei = open("rekorde.txt","a")
        except:
            print ("Konnte Datei nicht oeffnen")
            
        datei.write(name+" hat am " +time.strftime("%d.%m.%Y",lt) + " "+str(z)+" Aufgaben richtig" + "\n")
        datei.close()
        
        
        try:
            datei2 = open("daten.csv","a")
        except:
            print ("Konnte Datei nicht oeffnen")
            
        datei2.write(name + ";" + str(z) + "\n")
        datei2.close()
        
    def lesen(self):
        try:
            datei = open("rekorde.txt")
        except:
            print ("Dateizugriff nicht erfolgreich")
        allezeilen = datei.readlines()
        datei.close()
        such = " "


        print (f"{'Name':>11}{'Aufgaben':>30}")
        for zeile in allezeilen:
            anzahl = zeile.count(such)
            pos = zeile.find(such)
            anfpos = pos
            #print (anzahl, " ", pos)
            for i in range(1,5):
                #print (zeile)
                pos = zeile.find(such, pos+1)
                #print (pos)
            #print (zeile[0:anfpos], " ",zeile[pos-1], " Aufgaben")
            name = zeile[0:anfpos]
            zahl = zeile[pos-1]
            print (f"{zeile[0:anfpos]:>10}{int(zeile[pos-1]):20.0f}")
            
        try:
            datei2 = open("daten.csv")
        except:
            print ("Dateizugriff nicht erfolgreich")
            
        gesamt = datei2.read()
        datei2.close()
        
        zeilen=gesamt.split(chr(10))
        li = []
        for zeile in zeilen:
            zwliste = zeile.split(";")
            print (zwliste)
            li.append(zwliste)
            print (li)
        li2 = []
        for s in range(0,len(li)):
            sort = sorted(li[s])
            li2.append(sort)
            print (li2)
            
        li = sorted(li2)
        print (li)
        for p in range(len(li)-1,0,-1):
            print(f"{li[p][1]:<20}{int(li[p][0]):>2}")
            

print ("Hauptprogramm")



hs = Highscore()  
anzahl = input ("Wieviel Aufgaben?")
typ = input ("Aufgabentyp?")
anzahl = int(anzahl)
typ = int(typ)
s = Spiel(anzahl,typ)
Ok, dann mache ich das hiermit mal. Das ist das Programm für die Kommandozeile.

Zur Erklärung: Es ist ein Programm zum Bruchrechnen. Man kann verschiedene Modi wählen:

1: ausgegebener Bruch muss vollständig gekürzt werden.

2: Bruchrechenaufgabe: Addition/Subtraktion/Multiplikation/Division

3: Speedrechnen: Der Spieler hat 10 Sekunden um möglichst viele Brüche vollständig zu kürzen. Sein ergebnis wird in einer highscore-Datei gespeichert.

Die Highscore-Datei kann man sich auch ausgeben lassen.

Eines vorweg: Ich weiß, dass eine Fehler/Ausnahmebehandlung noch nicht stattgefunden hat.

Das Programm ist objektorientiert geschrieben, also es gibt das Objekt "spiel" und das Objekt "Bruch"

Und als nächsten Schritt wollte ich das Ganze, Stück für Stück, auf einem GUI zum Laufen bringen.


Schonmal danke dafür, dass ihr geantwortet habt. Ich hoffe nur, mein Code ist nicht zu stümperhaft (ist mein erster Versuch nach Ewigkeiten :oops: )
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Da haben wir ja schon das Problem: die Klasse ›Spiel‹ ist gar keine richtige Klasse. __init__ ist dazu da eine Klasse zu initialisieren, nicht dass darin alles läuft. leichte_aufgabe oder schwere_aufgabe muß außerhalb aufgerufen werden.
Zudem ist `hs` eine globale Variable, solche Fehler würden gar nicht auftreten, wenn Du eine main-Funktion hättest.

Code: Alles auswählen

class Spiel:
    def __init__(self):
        self.korrekte_aufgaben = 0
        self.falsche_aufgaben = 0
        self.name = input ("Dein Name?")

    ...        

def main():
    print("Hauptprogramm")
    anzahl = int(input("Wieviel Aufgaben?"))
    typ = int(input("Aufgabentyp?"))
    spiel = Spiel()
    if typ == 1:
        spiel.leichte_aufgabe(anzahl)
    elif self.typ == 2:
        spiel.schwere_aufgabe(anzahl)
    elif self.typ == 3:
        hs = Highscore()
        spiel.speedrechnen(hs)

if __name__ == '__main__':
    main()
Und jetzt sollte es einfach sein, die Schleife in ›leichte_aufgabe‹ so aufzuteilen, dass die Einzelteile durch Knopfdrücke ausgeführt werden.

Sonstige Anmerkungen:
Variablennamen und Attribute werden komplett klein geschrieben. Benutze keine Abkürzungen. Warum br1 in leichte_aufgaben wenn es nur einen Bruch gibt?

`hole_zeit`, `eingaberoutine` und `vorzeichen` gehören gar nicht in die Klasse, weil sie `self` gar nicht brauchen.
In `vorzeichen` ist random.seed falsch, weil es die Zufälligkeit stört. Statt randint und den ifs wäre ein random.choice einfacher.

Code: Alles auswählen

def vorzeichen():
    return random.choice("+-*/")
`bruch` ist falsch geschrieben, weil Klassen groß geschrieben werden: Bruch. Zähler schreibt man nicht mit e.
`bruch.__str__`: statt Strings mit + zusammenzustückeln benutzt man Formatstrings.
`generiere_bruchzahl` generiert gar keine Bruchzahl und benutzt self nicht.
In `kuerze_bruch` benutzt Ganzzahldivision //.
`mache_nennergleich` ändert self und other und gibt zwei Brüche zurück. Eine Funktion sollte nicht unkommentiert Argumente verändern.
`addiere`, `subtrahiere`, `multipliziere` und `dividiere` sollten einen Bruch zurückliefern und die übergebenen Brüche nicht verändern.
`ausgabe` ist überflüssig da es ja bruch.__str__ gibt.

In `Highscore` sollte man keine nackten excepts benutzen, vor allem weil die Fehlerbehandlung kaputt ist, da sie das Programm nicht in einen funktionierenden Zustand versetzt.
Dateien öffnet man mit dem with-Statement.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok, vielen Dank für deine ausführliche Antwort.

Ok, das mit der __init -funktion macht Sinn. Wenn das im Hauptprogramm wäre, dann wären wir der Sache schon näher.

Zugegebenermaßen sind nicht alle Variablen und funktionennamen von mir gut gewählt.

Ok, hole_zeit usw. kommt auch ins Hauptprogramm.

mache_nennergleich habe ich auch so gedacht, dass er zwei Brüche zurückgibt. Beide Brüche verändern sich ja in der Regel dadurch...

Ausgabe ist überflüssig - hast Recht.

hs habe ich global gemacht, dass man von überall drauf zugreifen kann.

Wie gesagt, die Fehlerbehandlung ist noch nicht vorhanden.

Datei öffnen haben ich nach meinem Lehrbuch nachprogrammiert. Von einem with-statement war da leider nie die Rede.

Schon mal Danke bis hierher für deine Mühe.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

So, habe den Code mal ein wenig verbessert.

Code: Alles auswählen

import random
import math
import time
import sys


def vorzeichenwahl():    
    return random.choice("+-*/")

def eingaberoutine(bruch):
    ergebnis_zaehler = 0
    ergebnis_nenner = 0
        
    for i in range(1,4):
        ergebnis_zaehler = input ("Zaehler?")
        ergebnis_nenner = input ("Nenner?")
        ergebnis_zaehler = int (ergebnis_zaehler)
        ergebnis_nenner = int(ergebnis_nenner)
        if ergebnis_zaehler == bruch.zähler and ergebnis_nenner == bruch.nenner:
            print ("richtig. Sie brauchten der Versuche ", i)
            return i
            
        elif (ergebnis_zaehler != bruch.zähler or ergebnis_nenner != bruch.nenner) and i == 3:
            print ("Zu viele Versuche, nämlich ",i,)
            return i
        else:
            print ("falsch")
            
def hole_zeit():
    startzeit = int(round(time.time(),0))
    zielzeit = startzeit +10
    return startzeit,zielzeit

class Spiel:
    def __init__(self):
        #self.anzahl = anzahl
        #self.typ = typ
        self.korrekte_Aufgaben = 0
        self.falsche_Aufgaben = 0
        self.name = input ("Dein Name?")
        
            
    def speedrechnen(self,hs):
        startzeit,zielzeit = hole_zeit()
        z = 0
        while startzeit < zielzeit:
            #print (startzeit)
            y=self.leichte_aufgabe(1)
            startzeit = int(round(time.time(),0))
            #time.sleep(1)
            if y == True:
                z+=1
            print ("Startzeit: ",startzeit)
            print ("Zielzeit: ",zielzeit)
        print ("Sie haben innerhalb ", zielzeit - startzeit," ",z," Aufgaben gelöst")
        
        hs.dateieintrag(self.name,z)
            
            
    def leichte_aufgabe(self,anzahl):
        for j in range(0, anzahl):
            bruch = Bruch()
            bruch.ausgabe()
            bruch.kuerze_bruch()
            bruch.ausgabe()
            z = eingaberoutine(bruch)
            print (z)
            self.statistik(z,anzahl)
            if (z == 1 and anzahl == 1) or j == anzahl:
                return True
            
            
    def schwere_aufgabe(self, anzahl):
        for j in range(0,anzahl):
            vorzeichen = vorzeichenwahl()
            bruch1 = Bruch()
            bruch2 = Bruch()
            if vorzeichen == "+":
                print (bruch1, " + ",bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.addiere(bruch2)
            elif vorzeichen == "-":
                print (bruch1, " - ", bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.subtrahiere(bruch2)
            elif vorzeichen == "*":
                print (bruch1, " * ", bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.multipliziere(bruch2)
            else:
                print (bruch1, " / ", bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.dividiere(bruch2)
            
            bruch = Bruch(ergebnis_zaehler,ergebnis_nenner)
            bruch.kuerze_bruch()
            bruch.ausgabe()
            z = eingaberoutine(bruch)
            self.statistik(z, anzahl)
            
                
       
    def statistik(self, z, anzahl):
        if z == 1:
            
            self.korrekte_Aufgaben += 1
        elif z == 2:
            
            self.falsche_Aufgaben += 1
        else:
            
            self.falsche_Aufgaben += 1
            
        if self.korrekte_Aufgaben + self.falsche_Aufgaben == anzahl:
            quote = round(self.korrekte_Aufgaben/anzahl*100,2)
            print ("Sie haben ", self.korrekte_Aufgaben, " von ", anzahl, " Aufgaben richtig geloest, also ", quote, " %")
            


class Bruch:
    def __init__(self,zähler=0,nenner=0):
        self.zähler=zähler
        self.nenner=nenner
        if zähler==0 or nenner ==0:
            wert_zähler = self.generiere_bruchzahl()
            wert_nenner = self.generiere_bruchzahl()
            self.zähler += wert_zähler
            self.nenner += wert_nenner
        
        prob = 2,2,2,2,3,3,3,5,5,7
        
    def __str__(self):
        return str(self.zähler) + "/" + str(self.nenner)
    
    def generiere_bruchzahl(self):
        prob = 2,2,2,2,3,3,3,5,5,7
        wert = 1
        #random.choice(prob)
        random.seed()
        anz = random.randint(2,5)
    
        for i in range(1,anz):
            wert *=random.choice(prob)
        #print (wert)
        
        return wert
    
    def kuerze_bruch(self):
        ggt = math.gcd(self.zähler,self.nenner)
        self.zähler = self.zähler // ggt
        self.nenner = self.nenner // ggt
        self.zähler = int(self.zähler)
        self.nenner = int(self.nenner)
        
    def mache_nennergleich(self,other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        print (self)
        print (other)
        
        
        counter=1
        counter_b=1
    
        while self.nenner != other.nenner:
        
            if self.nenner < other.nenner:
                self.nenner += (self.nenner / counter)
                #print ("Nenner_a ", self.nenner)
                counter +=1
            
            if other.nenner < self.nenner:
                other.nenner += (other.nenner / counter_b)
                #print ("Nenner_b ", other.nenner)
                counter_b +=1
        
            if self.nenner == other.nenner:
                break
            
        self.zähler *= counter
        other.zähler *= counter_b
        self.nenner = int(self.nenner)
        other.nenner = int(other.nenner)
        return self, other
        
    def addiere(self,other):
        if self.nenner != other.nenner:
            self,other=self.mache_nennergleich(other)
        
        ergebnis = self.zähler + other.zähler
        nenner = self.nenner
        return ergebnis,nenner
        
    def subtrahiere(self, other):
        if self.nenner != other.nenner:
            self, other = self.mache_nennergleich(other)
    
        ergebnis = self.zähler -other.zähler
        nenner = self.nenner
        return ergebnis,nenner
    
    def multipliziere(self, other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        erg_z = self.zähler*other.zähler
        erg_n = self.nenner*other.nenner
        return erg_z, erg_n
    
    def dividiere(self,other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        erg_z = self.zähler*other.nenner
        erg_n = self.nenner*other.zähler
        return erg_z, erg_n
            
    def ausgabe(self):
        print (self.zähler, " / ", self.nenner)
        
        
class Highscore():
    #def __init__(self):
        
    def dateieintrag(self, name, z):
        lt = time.localtime()
        try:
            datei = open("rekorde.txt","a")
        except:
            print ("Konnte Datei nicht oeffnen")
            
        datei.write(name+" hat am " +time.strftime("%d.%m.%Y",lt) + " "+str(z)+" Aufgaben richtig" + "\n")
        datei.close()
        
        
        try:
            datei2 = open("daten.csv","a")
        except:
            print ("Konnte Datei nicht oeffnen")
            
        datei2.write(name + ";" + str(z) + "\n")
        datei2.close()
        
    def lesen(self):
        try:
            datei = open("rekorde.txt")
        except:
            print ("Dateizugriff nicht erfolgreich")
        allezeilen = datei.readlines()
        datei.close()
        such = " "


        print (f"{'Name':>11}{'Aufgaben':>30}")
        for zeile in allezeilen:
            anzahl = zeile.count(such)
            pos = zeile.find(such)
            anfpos = pos
            #print (anzahl, " ", pos)
            for i in range(1,5):
                #print (zeile)
                pos = zeile.find(such, pos+1)
                #print (pos)
            #print (zeile[0:anfpos], " ",zeile[pos-1], " Aufgaben")
            name = zeile[0:anfpos]
            zahl = zeile[pos-1]
            print (f"{zeile[0:anfpos]:>10}{int(zeile[pos-1]):20.0f}")
            
        try:
            datei2 = open("daten.csv")
        except:
            print ("Dateizugriff nicht erfolgreich")
            
        gesamt = datei2.read()
        datei2.close()
        
        zeilen=gesamt.split(chr(10))
        li = []
        for zeile in zeilen:
            zwliste = zeile.split(";")
            print (zwliste)
            li.append(zwliste)
            print (li)
        li2 = []
        for s in range(0,len(li)):
            sort = sorted(li[s])
            li2.append(sort)
            print (li2)
            
        li = sorted(li2)
        print (li)
        for p in range(len(li)-1,0,-1):
            print(f"{li[p][1]:<20}{int(li[p][0]):>2}")
            

def main():

    print ("Hauptprogramm")


    hs = Highscore()  
    anzahl = int(input ("Wieviel Aufgaben?"))
    typ = int(input ("Aufgabentyp?"))
    spiel = Spiel()
    
    if typ == 1:
        spiel.leichte_aufgabe(anzahl)
    elif typ == 2:
        spiel.schwere_aufgabe(anzahl)
    elif typ == 3:
        hs = Highscore()
        spiel.speedrechnen(hs)
        hs.lesen()
if __name__ == '__main__':
    main()
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Das oben genannte Problem habe ich aber immernoch.

Und vor allem kapiere ich nicht, wie ich die tkinter-Objekte in die Methoden meiner Klassen implementieren soll. Die werden nicht erkannt, wenn ich das Fenster mit in die main - Funktion packe. Wenn ich das Fenster allerdings ganz nach "oben" in den Code packe, kann ich über die tkinter-Objekte die Objekte meiner Klasse nicht nutzen.

Muss ich da irgendwas global machen? Oder geht das irgendwie anders?

Ich habe keinen Plan mehr, was ich noch versuchen könnte.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Das offensichtliche ist ja, alle Ein- und Ausgaben durch GUI-Elemente zu ersetzen.
Also aus

Code: Alles auswählen

            bruch = Bruch()
            bruch.ausgabe()
            bruch.kuerze_bruch()
            bruch.ausgabe()
            z = eingaberoutine(bruch)
            print (z)
            self.statistik(z,anzahl)
müssen drei Teile werden:
1. einen neuen Bruch erzeugen und diesen in der GUI anzeigen (also Labelinhalte entsprechend setzen).
2. Du brauchst Eingabefelder und einen Ok-Button und beim Druch auf Ok muß die Eingabe geprüft werden (also die Schleife in eingaberoutine kann so auch nicht bestehen bleiben).
3. Statistik: das ist ja auch nur eine Ausgabe, also das setzen von entsprechenden Labelinhalten.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok, vielen Dank für den Input.

Die statistikfunktion lassen wir vielleicht erstmal beiseite und gehen Schritt für Schritt vor.

Das Hauptfenster soll 5 Buttons haben (einfache Aufgabe, schwere Aufgaben, Speedrechnen, Highscore einsehen, Ende).

Darüber hinaus den "OK" Button, von dem du sprachst.

Zur Anzeige / Eingabe der einfachen Aufgabe stehen entsprechend Labels und Entries zur Verfügung.

Namen und Anzahl der Aufgaben würde ich zu Testzwecken mal fix vorgeben. Das könnte man dann in einem weiteren Schritt per Eingabefeld regeln.

Ich codiere mal so weit und würde den Code dann später posten, wenn ich soweit bin. Dann lässt sich sicher am Besten erkennen, wo der Hund begraben liegt.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

So, hier mal mein Code bis jetzt. Ich habe als Start jetzt mal so programmiert, dass beim Klick auf den entsprechenden Button einfach ein Bruch erzeugt und anschließend mit der entsprechenden Methode gekürzt wird.
Aber schon hier gibts Probleme:

Gebe ich ein bruch.kuerze_bruch() ein, erhalte ich die Fehlermedung: kuerze_bruch() missing 1 required positional argument: 'self'

Was bitte soll da übergeben werden?

Kommentiere ich diese Funktion aus, erhalte ich folgende Fehlermeldung:AttributeError: type object 'Bruch' has no attribute 'zähler'

HÄ? Selbstverständlich existiert dieses attribut, wie sich aus der Klasse unschwer ersehen lässt.

EDIT: Habe dafür den Fehler gefunden. Beim Objekterzeugen hat eine Klammer gefehlt.

Hier dennoch mal der Code:

Code: Alles auswählen

import tkinter
import random
import math
import time
import sys




def vorzeichenwahl():    
    return random.choice("+-*/")

def eingaberoutine(bruch):
    ergebnis_zaehler = 0
    ergebnis_nenner = 0
        
    for i in range(1,4):
        ergebnis_zaehler = int(zähler_eingabe.get())
        ergebnis_nenner = int(nenner_eingabe.get())
    
        if ergebnis_zaehler == bruch.zähler and ergebnis_nenner == bruch.nenner:
            print ("richtig. Sie brauchten der Versuche ", i)
            return i
            
        elif (ergebnis_zaehler != bruch.zähler or ergebnis_nenner != bruch.nenner) and i == 3:
            print ("Zu viele Versuche, nämlich ",i,)
            return i
        else:
            print ("falsch")
            
def hole_zeit():
    startzeit = int(round(time.time(),0))
    zielzeit = startzeit +10
    return startzeit,zielzeit

class Spiel:
    def __init__(self):
        #self.anzahl = anzahl
        #self.typ = typ
        self.korrekte_Aufgaben = 0
        self.falsche_Aufgaben = 0
        #self.name = input ("Dein Name?")
        self.name = "Max Mustermann"
        
            
    def speedrechnen(self,hs):
        startzeit,zielzeit = hole_zeit()
        z = 0
        while startzeit < zielzeit:
            #print (startzeit)
            y=self.leichte_aufgabe(1)
            startzeit = int(round(time.time(),0))
            #time.sleep(1)
            if y == True:
                z+=1
            print ("Startzeit: ",startzeit)
            print ("Zielzeit: ",zielzeit)
        print ("Sie haben innerhalb ", zielzeit - startzeit," ",z," Aufgaben gelöst")
        
        hs.dateieintrag(self.name,z)
            
            
    def leichte_aufgabe(self,anzahl):
        for j in range(0, anzahl):
            bruch = Bruch()
            bruch.ausgabe()
            bruch.kuerze_bruch()
            bruch.ausgabe()
            z = eingaberoutine(bruch)
            print (z)
            self.statistik(z,anzahl)
            if (z == 1 and anzahl == 1) or j == anzahl:
                return True
            
            
    def schwere_aufgabe(self, anzahl):
        for j in range(0,anzahl):
            vorzeichen = vorzeichenwahl()
            bruch1 = Bruch()
            bruch2 = Bruch()
            if vorzeichen == "+":
                print (bruch1, " + ",bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.addiere(bruch2)
            elif vorzeichen == "-":
                print (bruch1, " - ", bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.subtrahiere(bruch2)
            elif vorzeichen == "*":
                print (bruch1, " * ", bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.multipliziere(bruch2)
            else:
                print (bruch1, " / ", bruch2)
                ergebnis_zaehler,ergebnis_nenner=bruch1.dividiere(bruch2)
            
            bruch = Bruch(ergebnis_zaehler,ergebnis_nenner)
            bruch.kuerze_bruch()
            bruch.ausgabe()
            z = eingaberoutine(bruch)
            self.statistik(z, anzahl)
            
                
       
    def statistik(self, z, anzahl):
        if z == 1:
            
            self.korrekte_Aufgaben += 1
        elif z == 2:
            
            self.falsche_Aufgaben += 1
        else:
            
            self.falsche_Aufgaben += 1
            
        if self.korrekte_Aufgaben + self.falsche_Aufgaben == anzahl:
            quote = round(self.korrekte_Aufgaben/anzahl*100,2)
            print ("Sie haben ", self.korrekte_Aufgaben, " von ", anzahl, " Aufgaben richtig geloest, also ", quote, " %")
            


class Bruch:
    def __init__(self,zähler=0,nenner=0):
        self.zähler=zähler
        self.nenner=nenner
        if zähler==0 or nenner ==0:
            wert_zähler = self.generiere_bruchzahl()
            wert_nenner = self.generiere_bruchzahl()
            self.zähler += wert_zähler
            self.nenner += wert_nenner
        
        prob = 2,2,2,2,3,3,3,5,5,7
        
    def __str__(self):
        return str(self.zähler) + "/" + str(self.nenner)
    
    def generiere_bruchzahl(self):
        prob = 2,2,2,2,3,3,3,5,5,7
        wert = 1
        #random.choice(prob)
        random.seed()
        anz = random.randint(2,5)
    
        for i in range(1,anz):
            wert *=random.choice(prob)
        #print (wert)
        
        return wert
    
    def kuerze_bruch(self):
        ggt = math.gcd(self.zähler,self.nenner)
        self.zähler = self.zähler // ggt
        self.nenner = self.nenner // ggt
        self.zähler = int(self.zähler)
        self.nenner = int(self.nenner)
        
    def mache_nennergleich(self,other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        print (self)
        print (other)
        
        
        counter=1
        counter_b=1
    
        while self.nenner != other.nenner:
        
            if self.nenner < other.nenner:
                self.nenner += (self.nenner / counter)
                #print ("Nenner_a ", self.nenner)
                counter +=1
            
            if other.nenner < self.nenner:
                other.nenner += (other.nenner / counter_b)
                #print ("Nenner_b ", other.nenner)
                counter_b +=1
        
            if self.nenner == other.nenner:
                break
            
        self.zähler *= counter
        other.zähler *= counter_b
        self.nenner = int(self.nenner)
        other.nenner = int(other.nenner)
        return self, other
        
    def addiere(self,other):
        if self.nenner != other.nenner:
            self,other=self.mache_nennergleich(other)
        
        ergebnis = self.zähler + other.zähler
        nenner = self.nenner
        return ergebnis,nenner
        
    def subtrahiere(self, other):
        if self.nenner != other.nenner:
            self, other = self.mache_nennergleich(other)
    
        ergebnis = self.zähler -other.zähler
        nenner = self.nenner
        return ergebnis,nenner
    
    def multipliziere(self, other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        erg_z = self.zähler*other.zähler
        erg_n = self.nenner*other.nenner
        return erg_z, erg_n
    
    def dividiere(self,other):
        self.kuerze_bruch()
        other.kuerze_bruch()
        
        erg_z = self.zähler*other.nenner
        erg_n = self.nenner*other.zähler
        return erg_z, erg_n
            
    def ausgabe(self):
        print (self.zähler, " / ", self.nenner)
        
        
class Highscore():
    #def __init__(self):
        
    def dateieintrag(self, name, z):
        lt = time.localtime()
        try:
            datei = open("rekorde.txt","a")
        except:
            print ("Konnte Datei nicht oeffnen")
            
        datei.write(name+" hat am " +time.strftime("%d.%m.%Y",lt) + " "+str(z)+" Aufgaben richtig" + "\n")
        datei.close()
        
        
        try:
            datei2 = open("daten.csv","a")
        except:
            print ("Konnte Datei nicht oeffnen")
            
        datei2.write(name + ";" + str(z) + "\n")
        datei2.close()
        
    def lesen(self):
        try:
            datei = open("rekorde.txt")
        except:
            print ("Dateizugriff nicht erfolgreich")
        allezeilen = datei.readlines()
        datei.close()
        such = " "


        print (f"{'Name':>11}{'Aufgaben':>30}")
        for zeile in allezeilen:
            anzahl = zeile.count(such)
            pos = zeile.find(such)
            anfpos = pos
            #print (anzahl, " ", pos)
            for i in range(1,5):
                #print (zeile)
                pos = zeile.find(such, pos+1)
                #print (pos)
            #print (zeile[0:anfpos], " ",zeile[pos-1], " Aufgaben")
            name = zeile[0:anfpos]
            zahl = zeile[pos-1]
            print (f"{zeile[0:anfpos]:>10}{int(zeile[pos-1]):20.0f}")
            
        try:
            datei2 = open("daten.csv")
        except:
            print ("Dateizugriff nicht erfolgreich")
            
        gesamt = datei2.read()
        datei2.close()
        
        zeilen=gesamt.split(chr(10))
        li = []
        for zeile in zeilen:
            zwliste = zeile.split(";")
            print (zwliste)
            li.append(zwliste)
            print (li)
        li2 = []
        for s in range(0,len(li)):
            sort = sorted(li[s])
            li2.append(sort)
            print (li2)
            
        li = sorted(li2)
        print (li)
        for p in range(len(li)-1,0,-1):
            print(f"{li[p][1]:<20}{int(li[p][0]):>2}")
            

def main():
    def typ1():
    #spiel = Spiel()
        #spiel.leichte_aufgabe(3)
        bruch = Bruch()
        bruch.kuerze_bruch()
        zähler_anzeige["text"] = str(bruch.zähler)
        nenner_anzeige["text"] = str(bruch.nenner)
        
    def typ2():
        pass
    
    def speedrechnen():
        pass
    
    def siehe_highscore():
        pass
        
    def ende():
        haupt.destroy()
    
    haupt = tkinter.Tk()


    framelinks = tkinter.Frame(haupt, width=50)
    #framelinks["bg"] = "#FF0000"
    framelinks.pack(side="left", pady=0)


    zähler_anzeige = tkinter.Label(framelinks, text = "3")
    zähler_anzeige["width"] = 2
    zähler_anzeige["height"] = 0
    zähler_anzeige["font"] = "Arial 70 bold"
    zähler_anzeige["bg"] = "cyan"
    zähler_anzeige["anchor"] = "s"
    zähler_anzeige.pack(pady = 30)

    bruchstrich = tkinter.Label(framelinks, text = "_____")
    bruchstrich["width"] = 0
    bruchstrich["height"] = 0
    bruchstrich["font"] = "Arial  40 bold"
    #bruchstrich["anchor"] = "n"
    bruchstrich.pack(pady = 0)

    nenner_anzeige = tkinter.Label(framelinks, text = "4")
    nenner_anzeige["width"] = 2
    nenner_anzeige["bg"] = "cyan"
    nenner_anzeige["height"] = 0
    nenner_anzeige["font"] = "Arial 70 bold"
    nenner_anzeige.pack(pady = 50)


    framemitte = tkinter.Frame(haupt, width=50)
    #framemitte["bg"] = "red"
    framemitte.pack(side="left",pady=0)

    istgleich = tkinter.Label(framemitte, text = "=")
    istgleich["font"] = "Arial 70 bold"
    istgleich["height"] = 0
    istgleich["bg"] = "white"
    istgleich["anchor"] = "n"
    istgleich.pack(padx = 20)

    framebuttons = tkinter.Frame(haupt, width=50)
    framebuttons.pack(side="right",pady=0)

    buttonende = tkinter.Button(framebuttons, text = "Ende", command = ende)
    buttonende.pack(pady=0)

    buttonaufgabe1 = tkinter.Button(framebuttons, text =" Kuerzen", command = typ1)
    buttonaufgabe1.pack(pady=0,side="left")
    
    buttonaufgabe2 = tkinter.Button(framebuttons, text = "Bruchrechnen", command = typ2)
    buttonaufgabe2.pack()
    
    buttonspeed = tkinter.Button(framebuttons, text = "Speedrechnen", command = speedrechnen)
    buttonspeed.pack()
    
    buttonhighscore = tkinter.Button(framebuttons, text = "Highscore ansehen", command = siehe_highscore)
    buttonhighscore.pack()

    framerechts = tkinter.Frame(haupt,width=500)
    framerechts.pack(side="left",pady=2)

    zähler_eingabe = tkinter.Entry(framerechts)
    zähler_eingabe["bg"] = "white"
    zähler_eingabe["font"] = "Arial 70 bold"
    zähler_eingabe["width"] = 2
    #zehler_eingabe["anchor"] = "center"
    zähler_eingabe.pack(padx = 20,pady = 0)

    bruchstrich2 = tkinter.Label(framerechts, text = "_____")
    bruchstrich2["width"] = 0
    bruchstrich2["height"] = 0
    bruchstrich2["font"] = "Arial  40 bold"
    #bruchstrich["anchor"] = "n"
    bruchstrich2.pack(pady = 30)

    nenner_eingabe = tkinter.Entry(framerechts)
    nenner_eingabe["bg"] = "white"
    nenner_eingabe["font"] = "Arial 70 bold"
    nenner_eingabe["width"] = 2
    #nenner_eingabe["anchor"] = "center"
    nenner_eingabe.pack(padx = 20,pady = 20)

    ausgabelabel = tkinter.Label(haupt, text = "ausgabe")
    ausgabelabel.pack()



    print ("Hauptprogramm")


    hs = Highscore()  
    #anzahl = int(input ("Wieviel Aufgaben?"))
    #typ = int(input ("Aufgabentyp?"))
    spiel = Spiel()
    haupt.mainloop()
    #if typ == 1:
        #spiel.leichte_aufgabe(anzahl)
    #elif typ == 2:
        #spiel.schwere_aufgabe(anzahl)
    #elif typ == 3:
        #hs = Highscore()
        #spiel.speedrechnen(hs)
        #hs.lesen()
        
    

if __name__ == '__main__':
    main()



#s = Spiel(5,1)
Soweit, sogut.

Nun habe ich eine OK-Button erstellt und möchte, dass beim Klick darauf die Ergebniskontrollroutine kommt. Aber das funktioniert nicht, weil das Objekt "bruch" nicht erkannt wird. Müsste ich daher die Variable "bruch" global setzen?

Hier mal der hinzugefügte Code:
buttonok = tkinter.Button(framebuttons, text = "OK", command = eingaberoutine(bruch))
Benutzeravatar
__blackjack__
User
Beiträge: 14085
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cortez: ``global`` ist da gar nichts zu setzen. Grundsätzlich nicht!

`command` erwartet etwas Aufrufbares das kein Argument bekommt. Du rufst da `eingaberoutine()` auf und übergibst den *Rückgabewert* davon als `command`. Das geht nicht. Also das ginge nicht einmal wenn `bruch` definiert wäre.

Lokale Funktionen so wie in der `main()` macht man nicht. Du brauchst für die GUI eine Klasse. Und für die Programmlogik Code der keinen GUI-Code enthält. Deine `eingaberoutine()` fragt in einer Schleife immer wieder die gleichen Eingabeelemente ab — das funktioniert so nicht weil der Benutzer nie die Möglichkeit hat da andere Werte einzugeben, da werden also direkt hintereinander weg jedes mal die gleichen Werte abgefragt und verarbeitet bis die Versuche aufgebraucht sind.

GUI-Programmierung funktioniert wirklich komplett anders als der lineare Programmablauf bei einer Konsolananwendung. Ich denke nicht, dass es Sinn macht, dass Du versuchst den alten Code, der ja auch schon deutliche Probleme mit OOP hatte, jetzt irgendwie in eine GUI-Anwendung umzubauen. Die solltest Du besser von Grund auf neu schreiben. Oder zumindest mit dem Zwischenschritt die Konsolenanwendung zuerst einmal so umzuschreiben das es immer noch eine Konsolenanwendung ist, aber Programmlogik und Benutzerinteraktion komplett getrennt sind, und man ein Objekt mit der Programmlogik hat, das so gestaltet ist, dass man es sowohl von einer Konsolenanwendung als auch von einer GUI-Anwendung benutzen kann.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok, das sehe ich ein. Mein Programm scheint für den GUI-Gebrauch nicht geeignet zu sein. Also für diesen Zweck neumachen.

Das Problem, das ich dabei habe ist nur Folgendes: Wie kann man eigene Klassen (wie bei mir z.B. Bruch) in die GUI-Programmierung miteinbringen? Alles, was man so an Tutorials findet, erklärt lediglich, wie man Buttons mit Funktionen außerhalb von Klassen verknüpft-

Aber ich müsste ja mit einem Buttondruck Methoden der Klasse aufrufen. Und Übergabewerte (die Nutzereingaben) brauche ich ja auch...
Antworten