Ihr sollt in dieser Woche ein Taschenrechner-Applet schreiben. Der Clou dabei ist, dass es sich nicht um einen ganz gewöhnlichen Taschenrechner handeln soll, sondern um einen, der (ausschließlich) Umgekehrt Polnische Notation (UPN) beherrscht.
Es ist wichtig, dass ihr diesen Text hier bis zum Ende durchlest (und versteht natürlich). Bei Unklarheiten fragt einfach einen von uns.
3 4 +
Dadurch entfällt die Notwendigkeit von Klammern, denn infix
(3 + 4) * 5ist jetzt in UPN
3 4 + 5 *Auch ist die Auswertung solcher Ausdrücke durch einen Computer sehr viel einfacher zu programmieren als für Infixnotation (deshalb ist es ja eine Übungsaufgabe). Man benötigt lediglich einen genügend großen Stack, auf den man die Zahlen
pusht, die der Benutzer eingibt. Wenn der Benutzer
dann eine Operator-Taste klickt (wie '+'), werden entsprechend viele
Zahlen vom Stack gepopt, miteinander verrechnet und
das Ergebnis wieder auf den Stack gepusht, usw.
Wenn nicht mehr genügend Zahlen für eine Operation vorhanden sind, gibt
der Rechner eine Fehlermeldung aus.
Den Stack bekommt ihr übrigens von uns unten geschenkt.
Historisch ist UPN durch Taschenrechner von Hewlett Packard sehr populär geworden. Auch heute noch schätzen manche Leute (wie Olaf) die einfache und problemlose Eingabe von UPN-Ausdrücken in den Taschenrechner. Andere Anwendungen von UPN sind die Programmiersprachen Forth und Postscript.
Allerdings gibt es ein paar Dinge, die (mindestens) sein müssen:
Buttons für alle zehn Ziffern und den Dezimalpunkt
'.'. Wenn der Benutzer auf diese Tasten klickt, werden
die entsprechenden Ziffern in einem TextField angehängt.
Den Programmcode für ein Panel mit diesen Buttons
könnt ihr gleich von hier kopieren:
/* A panel with a button for each number 1 .. 9, 0, the decimal point,
and a '-' for negative numbers. The panel is filled
from top to button, left to right. */
Panel p;
Button b;
String[] buttonLabels = { "7", "8", "9", "4", "5", "6", "1", "2", "3", "0",
".", "-" };
p = new Panel();
p.setLayout(new GridLayout(4, 3)); // Four rows and three columns.
for(int i = 0; i < buttonLabels.length; i++)
{
b = new Button(buttonLabels[i]);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
/* e.getActionCommand() is the label string of the button that
generated this event. */
inputString += e.getActionCommand(); // Append digit.
inputField.setText(inputString); // Update display.
}
});
p.add(b);
}
Damit das richtig funktioniert müsst ihr natürlich das
TextField inputField nennen und den
sich ansammelnden String inputString. Hier sehr
ihr übrigens ein neues Layout (GridLayout), das
euch vielleicht auch noch woanders nützlich sein kann.
Button "Enter", der bewirkt, dass die Zahl aus
dem inputField/inputString gelesen
(und ggf. über ungültiges Format gemeckert) und auf den
Stack gepackt wird. Das TextField sollte anschließend
gelöscht werden. Wird "Enter" bei leeren inputField geklickt
passiert gar nichts.
TextArea wird der komplette Stackinhalt
angezeigt werden. Die Stack-Klasse, die wir euch
weiter unten stellen, hat bereits eine
Methode, die den entsprechenden String erzeugt.
Button "CE" ermöglicht es dem Benutzer, den aktuellen
Inputstring zu löschen, ein Button "C", den kompletten
Stack und das inputField zugleich.
Buttons vorhanden.
Bevor die eigentliche Operation ausgeführt wird, muss zunächst
genauso verfahren werden wie nach einem Klick auf "Enter" (siehe oben),
um eine eventuell noch anstehende Zahl auf den Stack zu legen.
Am besten ihr ruft hier gleich eure "Enter"-Methode einmal auf.
| Operation | Auswirkung |
|---|---|
+ | Poppe die beiden obersten Zahlen vom Stack und pushe ihre Summe zurück. |
- | Poppe die beiden obersten Zahlen vom Stack und ziehe die ehemals oberste von der ehemals zweitobersten ab. Pushe das Ergebnis auf den Stack |
* und / | Analog zu + und - |
1/x | Ersetze die obere Zahl des Stacks mit ihrem Kehrwert. |
x <-> y | Vertausche die beiden obersten Zahlen des Stacks |
Wenn bei einer Operation der Stack zu wenig Elemente
enthält, müsst ihr dem Benutzer eine entsprechende (eigene)
Fehlermeldung ausgeben. Das gleiche gilt für unmögliche
Operationen (ArithmeticException
auffangen). Beachtet: Es darf im abnahmefertigen Applet
niemals eine Fehlermeldung der Java-Umgebung (im
xterm) auftauchen.
TextField im unteren Teil eures Applets oder ihr
benutzt die showStatus(String)-Methode des
Applets. Vergesst dann nicht, mit der nächsten (gelungenen) Eingabe
die Fehlermeldung wieder zu löschen.
Tipp: Benutzt für eine schöne Benutzeroberfläche am besten ein
(hierarchisches) Arrangement von Panels, die ja alle
ihren eigenen LayoutManager haben können.
Also Panels stecken in Panels stecken in Panels stecken ...
Beispiel:
Panel p1 = new Panel();
p1.setLayout(new BorderLayout());
Panel p2 = new Panel();
p1.setLayout(new GridLayout(3, 1); // three rows, one column
// ... fill p2 ...
Panel p3 = new Panel();
// No layout set explicitely.
// ... fill p3 ...
p1.add("West", p2);
p1.add("East", p3);
p1.add("Center", someOtherPanel);
// etc.
doubles) benutzen
könnt müsst ihr sie zunächst für euch sichtbar machen. Das geht
mit einem einmaligen
cp -r ~co1-001/stack ~/programs/program4Das erzeugt euch in
~/programs/program4/ ein zusätzliches Verzeichnis stack,
in das ihr aber nichteinmal reinschauen braucht, um diese
Aufgabe zu programmieren.
Zum Benutzen der der neuen Klasse müsst ihr am Anfang eures Applet zusätzlich ein
import stack.*;machen. Dann ist alles ganz einfach, zum Beispiel:
Stack stack = new Stack(30); // New stack with room for 30 entries.
stack.push(1.5);
stack.push(0.0);
stack.push(23.21);
// Get whole stack as one multi-line string and display it in our textArea.
textArea.setText(stack.toString());
// Pop and print everything:
while(!stack.isEmpty())
{
outputArea.append("in stack: " + stack.top() + "\n"); // Look at topmost item.
stack.pop(); // Remove from stack.
}
Eine genaue Dokumentation der Stack-Klasse ist
vorhanden, ebenso wie alle Quellcodes.