Gerade wurde die Multiplikation zweier Brüche durchgeführt.
Die Schüler haben dann die entsprechenden Klassen des Fachkonzepts festgelegt. Sie haben die Aufgabe, die einzelnen Klassen zu programmieren und mit Hilfe von Testumgebungen zu testen.
Die grafische Oberfläche (letzter Abschnitt im Quelltext) wird vom Lehrer erstellt. Die Schüler haben die Aufgabe, die Oberfläche zu erweitern und zu verbessern.
Es wurde auf eine weitgehende Trennung zwische GUI und Fachkonzept Wert gelegt.
Das Ergebnis der Programmierung wird zeigen, dass der Entwurf - bzw. bereits die Anforderungsdefinition - nicht gründlich genug erarbeitet wurde. So wäre es sinnvoll, die Operationen sofort beim Drücken der entsprechenden Tasten auszuführen (ähnl. umgekehrter polnischer Notation). Das Ergebnis des Kürzens sollte den zu kürzenden Bruch überschreiben usw... (Aus Fehlern lernen hoffentlich auch die Schüler).
Die Bedienung des Rechners erfolgt in folgender Weise:
Gesamtquelltext für Bruchrechner Version 2 =========================================== ---------------------------------------------------------------------------- Datei gzahl.py ---------------------------------------------------------------------------- #! /usr/bin/python class GZahl: """ /* Klasse stellt eine ganze Zahl bereit """ def __init__(self): """ /* Der Initial-Wert ist 0 """ self.Wert=0 def setWert(self,wert): """ /* Der Wert wird auf wert gesetzt. Ist wert ein REAL, so /* werden die Nachkommastellen weggeschnitten, bei anderen /* Objekten erfolgt eine Fehlermeldung über StdIO. /* ---------------------------------------------------------- /* wert : integer : Wert der ganzen Zahl """ try: self.Wert=int(wert) except: print "Objekte der Klasse GZahl können nur ganzzahlige Werte annehmen!" def getWert(self): """ /* liefert den Wert zurück /* ------------------------------------- /* Rückgabewert : integer """ return self.Wert if __name__ == "__main__": mGZ=GZahl() mGZ.setWert("ttt") print mGZ.getWert() ---------------------------------------------------------------------- Bruch HAT zwei GanzZahlen (Zähler und Nenner) Datei: bruch.py ---------------------------------------------------------------------- #! /usr/bin/python from xterm import * # nur für Testumgebung from gzahl import * import string class Bruch: """ /* Klasse Bruch stellt Zähler und Nenner und erforderliche Methoden bereit. """ def __init__(self): """ /* Zaehler und Nenner werden aus der Klasse GZahl gebildet """ self.zaehler=GZahl() self.nenner=GZahl() def setZaehler(self,wert): """ /* setzt den Zähler. Ist wert ein REAL, so werden die Stellen nach dem /* Komma abgeschnitten, ist wert ein anderes Objekt, so wird eine /* Fehlermeldung über StdIO ausgegeben (s. Klasse GZahl) /* -------------------------------------------------------------------- /* wert : integer : Wert für Zähler """ self.zaehler.setWert(wert) def setNenner(self,wert): """ /* setzt den Nenner. Ist wert ein REAL, so werden die Stellen nach dem /* Komma abgeschnitten, ist wert ein anderes Objekt, so wird eine /* Fehlermeldung über StdIO ausgegeben (s. Klasse GZahl) /* -------------------------------------------------------------------- /* wert : integer : Wert für Nenner """ self.nenner.setWert(wert) def getZaehler(self): """ /* liefert den Wert des Zählers /* -------------------------------------- /* Rückgabewert : integer """ return self.zaehler.getWert() def getNenner(self): """ /* liefert den Wert des Nenners /* -------------------------------------- /* Rückgabewert : integer """ return self.nenner.getWert() def invertieren(self): """ /* vertauscht Zähler und Nenner (Kehrbruch) """ zwi=self.zaehler self.zaehler=self.nenner self.nenner=zwi def erweitern_mit(self,n): """ /* Der Bruch wird mit n erweitert /* --------------------------------------------------- /* n : integer : Wert, mit dem erweitert werden soll """ self.zaehler.setWert(self.zaehler.getWert()*n) self.nenner.setWert(self.nenner.getWert()*n) def kuerzen_durch(self,n): """ /* Der Bruch wird durch n gekürzt /* --------------------------------------------------- /* n : integer : Wert, durch den gekürzt werden soll """ if (self.zaehler.getWert()%n==0) and (self.nenner.getWert()%n==0): self.zaehler.setWert(self.zaehler.getWert()/n) self.nenner.setWert(self.nenner.getWert()/n) return 1 # true else: return 0 # false def kuerzen(self): """ /* primitiver Algorithmus, der soweit wie möglich kürzt """ x=1 while x: N=self.nenner.getWert() x=0 for i in range(2,N+1): x = x or self.kuerzen_durch(i) # Testumgebung: if __name__ == "__main__": terminal=XTerm() mein_Bruch=Bruch() terminal.clear() terminal.output("Zähler eingeben: ") mein_Bruch.setZaehler(string.atoi(terminal.input())) terminal.output("\nNenner eingeben: ") mein_Bruch.setNenner(string.atoi(terminal.input())) terminal.goto(0,10) mein_Bruch.kuerzen() terminal.output("\nZähler: "+str(mein_Bruch.getZaehler())) terminal.output("\nNenner : "+str(mein_Bruch.getNenner())+"\n") mein_Bruch.invertieren() terminal.output("\nZähler: "+str(mein_Bruch.getZaehler())) terminal.output("\nNenner : "+str(mein_Bruch.getNenner())+"\n") -------------------------------------------------------------------- Bruchrechner HAT 3 Brüche Datei bruchrechner.py -------------------------------------------------------------------- #! /usr/bin/python from xterm import * # für Testumgebung from bruch import * import string class Bruchrechner: """ /* stellet das Fachkonzept für einen Bruchrechner dar """ def __init__(self): """ /* Attribute sind: Bruch1, Bruch2, Ergebnis, Operator (default: +) """ self.bruch1=Bruch() self.bruch2=Bruch() self.ergebnis=Bruch() self.operator='+' def setOperator(self,wert): """ /* Der Operator wird auf eine der Operationen + - * : gesetzt /* Es erfolgt noch keine Berechnung /* ---------------------------------------------------------- /* wert : character : gewünschte Operation (ohne Fehlerabfragen) """ self.operator=wert def getOperator(self): """ /* liefert die ausgewählte Operation zurück """ return self.operator def setBruch(self,zaehler,nenner,Nr): """ /* Bruch1 oder Bruch2 können definiert werden. /* -------------------------------------------- /* zaehler : integer /* nenner : integer /* Nr : integer : 1 oder 2 für Bruch1 oder Bruch2 """ if Nr == 1 : self.bruch1.setZaehler(zaehler) self.bruch1.setNenner(nenner) else: self.bruch2.setZaehler(zaehler) self.bruch2.setNenner(nenner) def getBruch(self,Nr): """ /* liefert den Bruch als Zahlenpaar zurück /* ----------------------------------------------- /* Nr: integer : 1,2 oder 3 für Ergebnisbruch /* ----------------------------------------------- /* Rückgabe : Paar : (integer,integer) """ if Nr == 1 : return self.bruch1.getZaehler(), self.bruch1.getNenner() if Nr == 2: return self.bruch2.getZaehler(), self.bruch2.getNenner() if Nr == 3: return self.ergebnis.getZaehler(), self.ergebnis.getNenner() def erweitern_mit(self,n): """ /* Bruch1 wird mit n erweitert (monadische Operation) /* ----------------------------------------------- /* n : integer """ self.bruch1.erweitern_mit(n) def kuerzen(self,Nr): """ /* Bruch1, Bruch2 oder ergebnis werden soweit wie möglich gekürzt /* -------------------------------------------------------------- /* Nr : 1,2 oder 3 für Ergebnisbruch """ if Nr==1: self.bruch1.kuerzen() if Nr==2: self.bruch2.kuerzen() if Nr==3: self.ergebnis.kuerzen() def berechne(self): """ /* Entsprechend der Operations-Vorwahl wird die Berechnung aus den /* beiden Brüchen durchgeführt und als Ergebnisbruch gespeichert. /* (diadische Operationen: + - * : ). /* Fehlermeldung, wenn Nenner 0 über StdIO """ if (self.bruch2.getNenner()==0) or (self.bruch1.getNenner()==0): print "Fehler! DIVISION durch 0!" else: if self.operator=='+': n=self.bruch1.getNenner() self.bruch1.erweitern_mit(self.bruch2.getNenner()) self.bruch2.erweitern_mit(n) self.ergebnis.setZaehler \ (self.bruch1.getZaehler()+self.bruch2.getZaehler()) self.ergebnis.setNenner(self.bruch1.getNenner()) if self.operator=='-': n=self.bruch1.getNenner() self.bruch1.erweitern_mit(self.bruch2.getNenner()) self.bruch2.erweitern_mit(n) self.ergebnis.setZaehler \ (self.bruch1.getZaehler()-self.bruch2.getZaehler()) self.ergebnis.setNenner(self.bruch1.getNenner()) if self.operator=='*': self.ergebnis.setZaehler \ (self.bruch1.getZaehler()*self.bruch2.getZaehler()) self.ergebnis.setNenner \ (self.bruch1.getNenner()*self.bruch2.getNenner()) if self.operator==':': if self.bruch2.getZaehler()==0: print "Fehler! DIVISION durch 0!" else: self.bruch2.invertieren() self.setOperator('*') self.berechne() self.kuerzen(3) # Testumgebung: if __name__ == "__main__": terminal=XTerm() terminal.clear() terminal.output("Zähler1 eingeben: ") z1=string.atoi(terminal.input()) terminal.output("\nNenner1 eingeben: ") n1=string.atoi(terminal.input()) terminal.output("Zähler2 eingeben: ") z2=string.atoi(terminal.input()) terminal.output("\nNenner2 eingeben: ") n2=string.atoi(terminal.input()) terminal.output("Operation + - * : ") o=terminal.input() terminal.goto(0,10) mB=Bruchrechner() mB.setOperator(o[0]) mB.setBruch(z1,n1,1) mB.setBruch(z2,n2,2) mB.berechne() terminal.output("\nErgebnis: "+str(mB.getBruch(3))+"\n") ----------------------------------------------------------------- Graphische Benutzeroberfläche: mFenster KENNT mRechner Datei: rechner_GUI.py ----------------------------------------------------------------- #! /usr/bin/python import Tkinter from Tkconstants import * from bruchrechner import * class xBruch: """ /* GUI-Darstellung eines Bruches """ def __init__(self,win): """ /* Zwei Eingabefelder werden übereinander angeordnet (Zähler,Nenner). /* ------------------------------------------------------------------ /* win kennzeichnet das Parent-Objekt, in das der Bruch gelegt wird. """ zWert=Tkinter.StringVar() self.zaehler=Tkinter.Entry(win,textvariable=zWert, width=5) self.zaehler.pack() nWert=Tkinter.StringVar() self.nenner=Tkinter.Entry(win,textvariable=nWert, width=5) self.nenner.pack() def getZaehler(self): """ /* liefert den eingegebenen Wert aus dem Zähler-Eingabefeld """ self.zaehler.selection_range(0,"end") return (self.zaehler.selection_get()) def getNenner(self): """ /* liefert den eingegebenen Wert aus dem Nenner-Eingabefeld """ self.nenner.selection_range(0,"end") return (self.nenner.selection_get()) def setZaehler(self,wert): """ /* Vorbesetzung des Zähler-Eingabefeldes mit einem Wert """ self.zaehler.delete(0,"end") self.zaehler.insert(0,wert) def setNenner(self,wert): """ /* Vorbesetzung des Nenner-Eingabefeldes mit einem Wert """ self.nenner.delete(0,"end") self.nenner.insert(0,wert) class xTaste: """ /* GUI-Darstellung einer Taste """ def __init__(self, win, Text, Bef, Seite=TOP): """ /* win kennzeichnet das Parent-Objekt, in das die Taste gelegt wird. /* Text : string : Beschriftung der Taste /* Bef : Methodenreferenz : Methode, die beim Drücken der Taste /* ausgeführt werden soll. /* Seite: opt. Parameter, um Tasten auch nebeneinander anordnen zu können """ Knopf=Tkinter.Button(win, text=Text, command=Bef) Knopf.pack(side=Seite, padx=5, pady=12) class xRechner: """ /* GUI-Darstellung des Rechners """ def __init__(self,Rechner): """ /* Bei der Objekterzeugung wird ein Fenster mit dem Rechner /* geöffnet /* --------------------------------------------------------- /* Rechner: Referenz auf ein Objekt der Klasse Bruchrechner """ self.Rechner=Rechner win=Tkinter.Tk() Fensterbreite=str(450) Fensterhoehe=str(350) geometrie=Fensterbreite+"x"+Fensterhoehe+"+0+0" win.geometry(geometrie) win.title("Bruchrechner") Rahmen0=Tkinter.Frame(win, relief=SUNKEN, bd=2) Rahmen0.pack(padx=5, pady=9) RahmenX=Tkinter.Frame(win, bd=2) RahmenX.pack(padx=5, pady=9) Rahmen1=Tkinter.Frame(Rahmen0, relief=SUNKEN, bd=2) Rahmen1.pack(side=LEFT, padx=5, pady=9) Rahmen2=Tkinter.Frame(Rahmen0, relief=SUNKEN, bd=2) Rahmen2.pack(side=LEFT, padx=5, pady=9) Rahmen3=Tkinter.Frame(Rahmen0, relief=SUNKEN, bd=2) Rahmen3.pack(side=LEFT, padx=5, pady=9) Rahmen4=Tkinter.Frame(Rahmen0, relief=SUNKEN, bd=2) Rahmen4.pack(side=LEFT, padx=5, pady=9) Rahmen5=Tkinter.Frame(Rahmen0, relief=SUNKEN, bd=2) Rahmen5.pack(side=LEFT, padx=5, pady=9) self.B1=xBruch(Rahmen1) self.B2=xBruch(Rahmen3) self.B3=xBruch(Rahmen5) K0=xTaste(Rahmen4,' = ', self.ist) K1=xTaste(Rahmen2,' + ', self.plus) K2=xTaste(Rahmen2,' - ', self.minus) K3=xTaste(Rahmen2,' * ', self.mal) K4=xTaste(Rahmen2,' : ', self.geteilt) KY=xTaste(RahmenX,' kürzen ',self.kuerzen, "left") KX=xTaste(RahmenX,' E N D E ', "exit", "left") def ist(self): """ /* Methode, die beim Drücken der = Taste aufgerufen wird """ self.Rechner.setBruch(self.B1.getZaehler(),self.B1.getNenner(),1) self.Rechner.setBruch(self.B2.getZaehler(),self.B2.getNenner(),2) self.Rechner.berechne() self.B3.setZaehler(self.Rechner.getBruch(3)[0]) self.B3.setNenner(self.Rechner.getBruch(3)[1]) def plus(self): """ /* Methode, die beim Drücken der + Taste aufgerufen wird """ self.Rechner.setOperator('+') def minus(self): """ /* Methode, die beim Drücken der - Taste aufgerufen wird """ self.Rechner.setOperator('-') def mal(self): """ /* Methode, die beim Drücken der * Taste aufgerufen wird """ self.Rechner.setOperator('*') def geteilt(self): """ /* Methode, die beim Drücken der : Taste aufgerufen wird """ self.Rechner.setOperator(':') def kuerzen(self): """ /* Methode, die beim Drücken der Kürzen-Taste aufgerufen wird """ self.Rechner.setBruch(self.B1.getZaehler(),self.B1.getNenner(),1) self.Rechner.kuerzen(1) self.B3.setZaehler(self.Rechner.getBruch(1)[0]) self.B3.setNenner(self.Rechner.getBruch(1)[1]) if __name__ == "__main__": mRechner=Bruchrechner() mWindow=xRechner(mRechner) Tkinter.mainloop()
Dr. Bernd Kokavecz