Menü mit Klasse?

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.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mittwoch 18. April 2007, 14:14

Hallo zusammen,

zuerst mal nur theoretisch:
Wir schreiben in der Schule folgende Programme:
Modul mit Funktionen (Formeln - Umfang Rechteck usw.),
ein weiteres mit Turtlefunktionen usw.

Dann verpassen wir diesen Modulen ein Benutzerinterface, der Sinn dazu wird klar gemacht.

Das Benutzerinterface ist einfach ein Menü - Bsp. Formeln:
=======Menü=======
1. Umfang Rechteck
2. Fläche Rechtek
usw.
e = Ende
==================


Neulich habe ich mir mal gedacht wie es wäre das Menü in einer Klasse zu definieren und bei Bedarf kann man dann in diesem und jenem Modul ein Menü erzeugen.

Das geht natürlich auch mit einer Funktion. Die Frage ist, ob es nicht doch ein nette Möglichkeit wäre die Schüler in OOP einzuführen.

Was mich selbst dran stört ist, dass ich entweder nicht weiss welche Methoden zur Manipulation definiert werden könnten oder, dass ich mir die Umsetzung etwas schwierig vorstelle.

Z. B. Wenn das Menü mehr als 5 Einträge hat per Tasteneingabe, dieses ein- bzw. auszuklappen. Geht sowas überhaupt?

Seit mal so nett und hirnt über die Idee nach und macht mir mal den einen oder anderen Vorschlag.

Vielen Dank im Voraus

LG

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mittwoch 18. April 2007, 20:41

Zur Verdeutlichung meines Textes:

Code: Alles auswählen

class Menue:    

    menue_kopf = "----------Menü-----------\n"
    menue_option_a = "a für ausklappen\n"
    menue_option_e = "e für einklappen\n"
    menue_option_E = "E für Ende\n"
    menue_fuss = "-------------------------"
    
    
    def __init__(self, *eintraege):
        self.menue_eintraege = ""
        self.hidden = ""
        for i in xrange(len(eintraege)):
            if i > 2:
                self.hidden = self.hidden + str(i + 1) + ". " + \
                              eintraege[i] + "\n"
                
            else:
                self.menue_eintraege = self.menue_eintraege + \
                str(i + 1) + ". " + eintraege[i] + "\n"

    def __str__(self):
        self.menue = self.menue_kopf + \
                     self.menue_eintraege + \
                     self.menue_option_a + \
                     self.menue_option_e +\
                     self.menue_option_E +\
                     self.menue_fuss 
        return self.menue
    
    def ausklappen(self):
        if self.hidden not in self.menue:
            menue_eintraege_neu = self.menue_eintraege + self.hidden
            self.menue = self.menue.replace(self.menue_eintraege,
                                            menue_eintraege_neu)
            print self.menue
    

if __name__ == "__main__":

    menue = Menue("Umfang Rechteck",
                   "Fläche Rechteck",
                   "Umfang Dreieck",
                  "Fläche rechtwinkliges Dreieck",
                  "Umfang Kreis")
    print menue
Sobald man Methoden definiert die das Menü verändern, wird es schon ganz schön umfangreich, dabei habe ich erst eine definiert.

LG

rolgal_reloaded
Zuletzt geändert von rolgal_reloaded am Mittwoch 18. April 2007, 21:46, insgesamt 1-mal geändert.
Costi
User
Beiträge: 544
Registriert: Donnerstag 17. August 2006, 14:21

Mittwoch 18. April 2007, 21:16

nur ein par kurze bemerkung zur implementation:

zeile 37 und 38 kannst du wegglasen
und du kannst zeile 13 loeschen und in zeile 16 das "self.hidden + " auch entfernen (nicht nur einfach machen, ruebe anstrengen ; )

wenn du noch ein paar andere kleine verbesserungen vornimmst ist es sicher einfacher fuer dich mit dem code weiterzuarbeiten


gruesse
costi
cp != mv
BlackJack

Mittwoch 18. April 2007, 21:30

So ganz verstehe ich die Klasse nicht.

Es gibt Wiederholungen beim zusammensetzen der Einträge. Und wenn man `ausklappen()` aufruft bevor ein `Menue`-Objekt nicht mindestens einmal in eine Zeichenkette umgewandelt wurde gibt's eine Fehlermeldung.

Wenn in einem ``else``-Zweig nur ein ``pass`` steht, kann man den Zweig ganz weglassen.

`menue_eintraege_neu` wird nur in `ausklappen()` benutzt, sollte also lokal sein und nicht an das Objekt gebunden werden.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mittwoch 18. April 2007, 21:32

Costi hat geschrieben:nur ein par kurze bemerkung zur implementation:

zeile 37 und 38 kannst du wegglasen
Du meinst doch 38,39, also den else - Zweig?
Costi hat geschrieben: und du kannst zeile 13 loeschen und in zeile 16 das "self.hidden + " auch entfernen (nicht nur einfach machen, ruebe anstrengen ; )
Aber da gibts ein seltsames Verhalten dann:

----------Menü-----------
1. Umfang Rechteck
2. Fläche Rechteck
3. Umfang Dreieck
5. Umfang Kreis
a für ausklappen
e für einklappen
E für Ende
-------------------------

Wie du siehst fehlt da Punkt 4, der sonst nicht fehlt.
Vielleicht hast du es im Detail auch etwas anders gemeint bzw. ich falsch verstanden.


LG

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mittwoch 18. April 2007, 21:45

BlackJack hat geschrieben:So ganz verstehe ich die Klasse nicht.

Es gibt Wiederholungen beim zusammensetzen der Einträge.
Welche Wiederholungen meinst du? Code bitte.
Und wenn man `ausklappen()` aufruft bevor ein `Menue`-Objekt nicht mindestens einmal in eine Zeichenkette umgewandelt wurde gibt's eine Fehlermeldung.
Versteh ich jetzt nicht, dazu kann es doch gar nicht kommen, dass man ausklappen() aufrufen kann bevor en Menueobjekt erzeugt wurde.
Oder reden wir von was anderem?
Wenn in einem ``else``-Zweig nur ein ``pass`` steht, kann man den Zweig ganz weglassen.
Das ist klar.
`menue_eintraege_neu` wird nur in `ausklappen()` benutzt, sollte also lokal sein und nicht an das Objekt gebunden werden.
Hmpf, genau das passiert mir eigentlich selten, egal, danke für den Hinweis!

LG

rolgal_reloaded
BlackJack

Mittwoch 18. April 2007, 22:44

Das mit dem `ausklappen()` war mein Fehler. Ich habe `self.menu` gesehen und dachte das wird dort benutzt und in `__str__()` erzeugt. Also nochmal zwei Fälle von lokalen Variablen die ans Objekt gebunden werden.

Mit Wiederholungen meinte ich die beiden Zweige in `__init__()` wo die Zeichenketten für das Menü zusammengebaut werden. Das könnte man vor die Entscheidung ziehen und dann nur noch entscheiden wo der Eintrag angefügt wird.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mittwoch 18. April 2007, 23:00

BlackJack hat geschrieben:Das mit dem `ausklappen()` war mein Fehler. Ich habe `self.menu` gesehen und dachte das wird dort benutzt und in `__str__()` erzeugt. Also nochmal zwei Fälle von lokalen Variablen die ans Objekt gebunden werden.
Du hast self.menue gesehen.
Richtig es wird in '__str__()' erzeugt, oder nicht????
Warum nochmal zwei Fälle von lokalen Variablen????
Ich muss doch in 'ausklappen()' prüfen ob self.hidden bereits in self.menue vorhanden ist, sonst wird es überflüssigerweise nochmal angehängt.
Da ich nicht glaube, dass du zwei Fehler hintereinander machst, gehe ich davon aus, dass ich nicht checke was du meinst.

Mit Wiederholungen meinte ich die beiden Zweige in `__init__()` wo die Zeichenketten für das Menü zusammengebaut werden. Das könnte man vor die Entscheidung ziehen und dann nur noch entscheiden wo der Eintrag angefügt wird.
Werde ich gleich mal ausprobieren!

LG

rolgal_reloaded
BlackJack

Mittwoch 18. April 2007, 23:12

Ist schon spät, ich bin verunsichert. Aber dann hatte ich ja am Anfang doch recht.

Wenn Du ein `Menue`-Objekt erzeugst und `auklappen()` aufrufst, dann kommt eine Fehler weil auf `self.menu` zugegriffen wird, was es nur gibt wenn das Objekt vorher mindestens einmal in eine Zeichenkette umgewandelt wurde. Das sollte man vermeiden oder gut dokumentieren.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mittwoch 18. April 2007, 23:22

....ahhh, ich glaube ich kann folgen.
Nun. Das Menü wird in jedem Fall beim Start der betreffenden Programmen sofort erzeugt.

Deshalb habe ich folgendes auch so geschrieben:

Code: Alles auswählen


if __name__ == "__main__":

    menue = Menue("Umfang Rechteck",
                   "Fläche Rechteck",
                   "Umfang Dreieck",
                  "Fläche rechtwinkliges Dreieck",
                  "Umfang Kreis")
    print menue
Ich berufe mich hier auch auf ein Gespräch zu einem Code von mir, das ich mal mit Leonidas hatte. Er meinte im damaligen Fall, man muss das Programm nicht unbedingt so verfassen, dass dem Benutzer jegliches denken abgenommen wird. - Frei zitiert ohne nochmal nachgelesen zu haben, also mit Vorbehalt:-))

Aber freilich ist dein Einwand sinnvoll und ich sollte mir nochmal überlegen, ob man es nicht besser lösen könnte bzw. entsprechend kommentieren sollte.

Also bis bald,

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mittwoch 18. April 2007, 23:36

BlackJack hat geschrieben:
Wenn Du ein `Menue`-Objekt erzeugst und `auklappen()` aufrufst, dann kommt eine Fehler weil auf `self.menu` zugegriffen wird, was es nur gibt wenn das Objekt vorher mindestens einmal in eine Zeichenkette umgewandelt wurde. Das sollte man vermeiden oder gut dokumentieren.
Was hältst du davon den AttributeError abzufangen und da auf die falsche Verwendung hinzuweisen?

Code: Alles auswählen

    def ausklappen(self):
        try:
            if self.hidden not in self.menue:
                menue_eintraege_neu = self.menue_eintraege + self.hidden
                self.menue = self.menue.replace(self.menue_eintraege,
                                                menue_eintraege_neu)
                print self.menue
        except AttributeError:
            print "Achtung, Sie müssen zuerst das Menü ausgeben!"

LG

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Donnerstag 19. April 2007, 00:06

Hi,

so funzt es mit ausklappen und einklappen, einklappen erschien mir zuerst schwierig, aber wenn man nicht self.menue überschreibt, sondern ein neues Objekt erzeugt - menue_a (zunächst mal lokal, später vielleicht für die realisierung ineuer deen doch besser nicht lokal?), dann ist einklappen natürlich easy, weil ich einfach wieder self.menue ausgebe.

Code: Alles auswählen

class Menue:    

    menue_kopf = "----------Menü-----------\n"
    menue_option_a = "a für ausklappen\n"
    menue_option_e = "e für einklappen\n"
    menue_option_E = "E für Ende\n"
    menue_fuss = "-------------------------"
    
    
    def __init__(self, *eintraege):
        self.menue_eintraege = ""
        self.hidden = ""
        for i in xrange(len(eintraege)):
            if i > 2:
                self.hidden = self.hidden + str(i + 1) + ". " + \
                              eintraege[i] + "\n"
                
            else:
                self.menue_eintraege = self.menue_eintraege + \
                str(i + 1) + ". " + eintraege[i] + "\n"

    def __str__(self):
        self.menue = self.menue_kopf + \
                     self.menue_eintraege + \
                     self.menue_option_a + \
                     self.menue_option_e +\
                     self.menue_option_E +\
                     self.menue_fuss 
        return self.menue
    
    def ausklappen(self):
        try:
            if self.hidden not in self.menue:
                menue_eintraege_neu = self.menue_eintraege + self.hidden
                menue_a = self.menue.replace(self.menue_eintraege,
                                                menue_eintraege_neu)
                print menue_a
        except AttributeError:
            print "Achtung, Sie müssen zuerst das Menü ausgeben!"

    def einklappen(self):
        try:
            print self.menue
        except AttributeError:
            print "Achtung, Sie müssen zuerst das Menü ausgeben!"

     

    

if __name__ == "__main__":

    formelrechnermenue = Menue("Umfang Rechteck",
                   "Fläche Rechteck",
                   "Umfang Dreieck",
                  "Fläche rechtwinkliges Dreieck",
                  "Umfang Kreis")
    #print menue
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Donnerstag 19. April 2007, 08:20

Wenn deine Klasse schon Menue heißt, musst du nicht alle Namen der (Klassen-)Attribute mit "menue_" anfangen lassen, da bereits klar ist, in welchem Kontext sich die Attribute befinden.
BlackJack

Donnerstag 19. April 2007, 09:31

Von dem Abfangen des Fehlers halte ich nicht so viel. Warum muss man ein Menü erst in eine Zeichenkette umwandeln bevor man die Methoden benutzen kann. Das ist eine recht willkürliche und künstliche Einschränkung.

Und das alles auf einer Zeichenkette gemacht wird, ist auch nicht so schön und nicht besonders übersichtlich. Ein Menü besteht abstrakt gesehen ja nicht aus einer Zeichenkette, sondern aus Einzelteilen wie Menüpunkten, Kopfzeile usw.

Andere Methoden die man auf einem Menü erwartet sind zum Beispiel hinzufügen und entfernen von Menüpunkten. Spätestens dann wird es mit der Zeichenkette richtig kompliziert.

Ich würde die Menüpunkte im Objekt speichern und ein Flag ob das Menü gerade ausgeklappt ist oder nicht. Und in der `__str__()`-Methode dann jedesmal entsprechend eine Zeichenkette zusammenbauen. Da kann man dann auch gleich dafür sorgen das nur einer der beiden Punkte für's ein- oder ausklappen angezeigt wird, weil es verwirrend ist den Punkt ausklappen bei einem schon ausgeklappten Menü zu haben und umgekehrt.

Aus dem `*eintraege`-Argument in der `__init__()` würde ich `eintraege` machen. Dann kann man die Einträge in einer Datenstruktur halten und als *ein* Argument übergeben. Ausserdem verbaut man sich nicht die Möglichkeit der Klasse oder Unterklassen weitere Argumente hinzuzufügen.

Und man könnte noch eine Möglichkeit schaffen den Einträgen Objekte zuzuordnen, zum Beispiel indem Einträge Tupel aus (Menütext, Objekt) sind.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Freitag 20. April 2007, 13:39

BlackJack hat geschrieben:Von dem Abfangen des Fehlers halte ich nicht so viel. Warum muss man ein Menü erst in eine Zeichenkette umwandeln bevor man die Methoden benutzen kann. Das ist eine recht willkürliche und künstliche Einschränkung.

Und das alles auf einer Zeichenkette gemacht wird, ist auch nicht so schön und nicht besonders übersichtlich. Ein Menü besteht abstrakt gesehen ja nicht aus einer Zeichenkette, sondern aus Einzelteilen wie Menüpunkten, Kopfzeile usw.

Andere Methoden die man auf einem Menü erwartet sind zum Beispiel hinzufügen und entfernen von Menüpunkten. Spätestens dann wird es mit der Zeichenkette richtig kompliziert.

Ich würde die Menüpunkte im Objekt speichern und ein Flag ob das Menü gerade ausgeklappt ist oder nicht. Und in der `__str__()`-Methode dann jedesmal entsprechend eine Zeichenkette zusammenbauen. Da kann man dann auch gleich dafür sorgen das nur einer der beiden Punkte für's ein- oder ausklappen angezeigt wird, weil es verwirrend ist den Punkt ausklappen bei einem schon ausgeklappten Menü zu haben und umgekehrt.

Aus dem `*eintraege`-Argument in der `__init__()` würde ich `eintraege` machen. Dann kann man die Einträge in einer Datenstruktur halten und als *ein* Argument übergeben. Ausserdem verbaut man sich nicht die Möglichkeit der Klasse oder Unterklassen weitere Argumente hinzuzufügen.

Und man könnte noch eine Möglichkeit schaffen den Einträgen Objekte zuzuordnen, zum Beispiel indem Einträge Tupel aus (Menütext, Objekt) sind.
Hab mal versucht in die Richtung zu gehen. Mir kommt es jetzt schon besser vor, obwohl noch viele Details wie auch die Nummern zu den Menüpunkten fehlen.
Aber ich denke du hast dir in dieser Art der Anlage vorgestellt?

Code: Alles auswählen

class Menue:    

    menue_kopf = "----------Menü-----------\n"
    menue_option_a = "a für ausklappen\n"
    menue_option_e = "e für einklappen\n"
    menue_option_E = "E für Ende\n"
    menue_fuss = "-------------------------"    
    
    def __init__(self, eintraege):
        self.menue = ""
        self.eintraege = eintraege
        self.klappbar = False
        if len(self.eintraege) > 2:

            self.menue_eintraege = "".join(self.eintraege[:3])
            self.klappbar = True
            
        else:
            self.menue_eintraege = "".join(self.eintraege)
 
        self.__str__()
        print self.menue
        
        
    def __str__(self):        
        if self.klappbar:
            self.menue = self.menue_kopf + \
                         self.menue_eintraege + \
                         self.menue_option_a + \
                         self.menue_option_e +  \
                         self.menue_option_E +\
                         self.menue_fuss
        else:
            self.menue = self.menue_kopf + \
                     self.menue_eintraege + \
                     self.menue_option_E + \
                     self.menue_fuss
        return self.menue
    
    def ausklappen(self):
        self.menue_eintraege = "".join(self.eintraege)
        
    def einklappen(self):
        self.menue_eintraege = "".join(self.eintraege[:3])
   

if __name__ == "__main__":

    menue = Menue(["Umfang Rechteck\n",
                   "Fläche Rechteck\n",
                   "Umfang Dreieck\n",
                  "Fläche rechtwinkliges Dreieck\n",
                  "Umfang Kreis\n"])
Antworten