Fortgeschrittene objektorientierte Programmierung
LVA 185.211, VL 2.0, 2008 S
1. Übungsaufgabe
Entwickeln Sie in Java, C# oder C++ eine grafische Oberfläche für ein einfaches (simuliertes) schwarz/weiß-ASCII-Terminal und eine kleine Anwendung, die diese Oberfläche verwendet.
Grafische Oberfläche:
Am Terminal sollen Fenster darstellbar sein, deren Ränder durch die Zeichen
|
(vertikal),
-
(horizontal) und
+
(an den Ecken) gezeichnet sind.
Es sollen gleichzeitig mehrere Fenster mit unterschiedlichem Inhalt (auch überlappend) darstellbar sein.
Aktiv ist immer das vorderste Fenster unter der aktuellen Cursor-Position (muss nicht das vorderste Fenster überhaupt sein, wenn der Cursor gerade nicht über diesem steht) bzw. kein Fenster, wenn der Cursor nicht über einem Fenster steht.
Tastatureingaben in das Terminal können folgende Objekte betreffen:
- Das ganze Terminal (global):
- Die globale Bedeutung der Eingabe ist unabhängig davon,
welches Fenster aktiv ist.
- Das aktive Fenster selbst (lokal):
- Wenn der Cursor über dem sichtbaren Rand eines Fensters steht,
bezieht sich eine Eingabe auf dieses Fenster selbst.
- Die Anwendung hinter dem aktiven Fenster (lokal):
- Wenn der Cursor innerhalb eines sichtbaren Fensters (nicht über
dessen Rand) steht, bezieht sich eine Eingabe auf die Anwendung hinter
dem Fenster.
Wenn es ein aktives Fenster gibt, wird für jede Eingabe sowohl eine globale (das ganze Terminal betreffende) als auch eine lokale (ein Fenster oder die Anwendung dahinter betreffende) Aktion ausgeführt, sonst nur eine globale.
Folgende globale Aktionen sollen unterstützt werden:
l
, r
, u
und d
:
- Diese Eingaben Verschieben den Cursor um eine Position nach links, rechts, oben, bzw. unten, außer wenn der Cursor dadurch ganz aus dem Terminal verschwinden würde.
In letzterem Fall springt der Cursor an den genau gegenüberliegenden Rand des Terminals.
Dabei kann ein anderes Fenster aktiv werden; dieses wird aber nicht automatisch nach vorne verschoben.
L
, R
, U
und D
:
- Verschieben den Cursur ebenso nach links, rechts, oben, bzw. unten.
Statt aus dem Terminal zu verschwinden (oder an den anderen Rand zu springen) bleibt der Curser jedoch an seiner Position stehen.
Wenn es zu einer Änderung der Cursor-Position kommt, kann ein anderes Fenster aktiv werden.
Das aktive Fenster, über dem der Cursor (nach einer möglichen Positionsänderung) steht, wird ganz nach vorne verschoben.
- Alle anderen Eingaben
- bewirken, dass das aktive Fenster (falls ein Fenster aktiv ist) ganz nach vorne verschoben wird.
Danach gibt es kein Fenster, welches das aktive Fenster teilweise verdeckt.
Wenn kein Fenster aktiv ist, haben diese Eingaben keinen Effekt.
Eingaben, die ein Fenster selbst betreffen, sollen folgende lokale Effekte haben:
L
, R
, U
und D
:
- Bewirken, dass sich das gesamte aktive Fenster mit dem Cursor (entsprechend dem globalen Effekt) mitverschiebt.
Die Position des Cursors relativ zum Fenster bleibt dadurch unverändert.
Es ist möglich, dass das Fenster durch die Verschiebung teilweise aus dem Terminal verschwindet.
+
und -
:
- Bewirkt eine Vergrößerung bzw. Verkleinerung des aktiven Fensters.
Dabei wird der Rand des Fensters, über dem der Cursor steht, verschoben.
Steht der Cursor über einer Ecke des Fensters, werden beide angrenzenden Ränder verschoben.
Auch die aktuelle Cursor-Position muss entsprechend verschoben werden.
Größe und Cursor-Position werden nicht verändert, wenn das Fenster durch die entsprechende Änderung unter eine Mindestgröße reduziert, über eine Maximalgröße ausgedehnt oder der Cursor aus dem Terminal verschwinden würde.
Wählen Sie Mindest- und Maximalgröße so, dass Fenster deutlich kleiner und größer sein können als das Terminal.
b
:
- Das oberste (bisher aktive) Fenster wird ganz nach hinten verschoben.
Dadurch kann das bisher aktive Fenster ganz oder teilweise durch andere Fenster verdeckt werden.
Das nach dieser Änderung aktive Fenster soll ohne weitere Eingabe nicht gleich ganz nach vorne verschoben werden (globaler vor lokalem Effekt).
q
:
- Schließt das aktive Fenster und beendet die Anwendung dahinter.
Wenn dadurch das letzte Fenster am Terminal geschlossen wird, wird auch die Ausführung der grafischen Oberfläche beendet.
- alle anderen Eingaben
- haben keinen Effekt.
Wenn Sie wollen, können Sie andere als die hier genannten Tasten (z.B. Pfeiltasten) verwenden.
Je nach Programmiersprache und verwendetem Ansatz könnte die Verwendung von speziellen Tasten jedoch den Programmieraufwand erhöhen.
Jedem Fenster ist genau eine Anwendung zugeordnet, und jede Anwendung hat genau ein Fenster.
Beim Start der grafischen Oberfläche soll automatisch ein Editor (als Beispielanwendung) gestartet werden.
Editor (Beispielanwendung)
Ein einfacher Editor für kleine ASCII-Dateien soll als Beispielanwendung dienen.
Gestartet werden kann der Editor nur in einer Kommandozeile mit dem Namen der editierten Datei als Argument.
Beim Start der grafischen Oberfläche soll der Editor automatisch mit einem fixen Dateinamen aufgerufen werden.
Zur Vereinfachung können Sie folgende Annahmen treffen:
- Nur der linke Teil des Textes wird im Fenster angezeigt falls der Text breiter ist als das Fenster.
Bei Änderungen der Fenstergröße und beim Speichern soll jedoch nichts verloren gehen.
- Eingegebene Zeichen überschreiben Zeichen, die davor an derselben Position gestanden sind.
Es gibt keinen Modus zum Einfügen oder Löschen.
- Die Befehle
p
und n
(oder, wenn Sie wollen, andere Tasten oder Tastenkombinationen) dienen zum Blättern im Text, wobei p
um die Mindesthöhe des Fensterinhalts nach oben und n
um dieselbe Anzahl an Zeilen nach unten blättert.
Die Cursorposition ändert sich beim Blättern nicht.
- Die Eingabe von
e
(oder eine andere Taste bzw. Tastenkombination) bewirkt, dass der gesamte Text in der Zeile, in der der Cursor steht, als Kommando interpretiert und im Hintergrund (von einer Shell bzw. vom Betriebssystem) ausgeführt wird.
Die Standard- und Fehler-Ausgabe wird an das Ende der gerade editierten Datei geschrieben.
- Die Buchstaben
l
, r
, u
, d
, L
, R
, U
, D
, p
, n
und e
können nicht geschrieben werden (außer Sie verwenden andere Tasten für vorgegebene Befehle).
- Es ist keine weitere Eingabe möglich, sobald der Cursor am rechten Rand des Fensterinhalts oder des Terminals steht.
Alle Änderungen sollen sofort in der Datei gespreichert werden.
Daher wird kein Befehl für das Speichern benötigt.
Es ist erlaubt, dass dieselbe Datei durch mehrere Editoren gleichzeitig editiert wird.
Änderungen, die ein Editor macht, sollen unmittelbar danach (innerhalb einer Sekunde) im anderen Editor sichtbar sein.
Kommandos können jederzeit abgesetzt werden, auch dann, wenn die Ausführung eines zuvor abgesetztes Kommando noch nicht beendet ist.
Dadurch ist es möglich, dass sich die Ausgaben mehrerer Befehle (und im Editor getippter Text falls der Cursor ganz am Ende steht) beliebig überlappen.
Dieses Verhalten ist beabsichtigt und soll nicht unterbunden werden.
Wenn durch die Ausgabe die Datei erweitert wird, soll der sichtbare Text entsprechend mitgeführt werden.
Die Verzögerung zwischen Ausgabe und Sichtbarwerden im Editor soll (unter normalen Bedingungen) höchstens eine Sekunde betragen.
Ausgaben sind von normal editiertem Text nicht zu unterscheiden; auch Ausgabezeilen können im Editor (ganz oder teilweise) überschrieben und als Befehle ausgeführt werden.
Neben der Standard- und Fehler-Ausgabe (die in der editierten Datei sichtbar wird) kann die Ausführung eines Kommandos natürlich auch weitere Effekte bzw. Ausgaben haben.
Es soll jedenfalls möglich sein, im Editor einen weiteren Editor zu starten, der keine Standard-Ausgabe produziert, sondern ein neues Fenster öffnet.
Eine Fehler-Ausgabe ist trotzdem nicht ausgeschlossen.
Wie die Aufgabe zu lösen ist:
Gestalten Sie Ihre Lösung möglichst einfach und gut wartbar.
Verwenden Sie ganz bewusst Softwareentwurfsmuster, die Ihnen für diese Aufgabe geeignet erscheinen, und vermeiden Sie ebenso bewusst Entwurfsmuster, deren Einsatz Ihnen hier nicht für gerechtfertigt erscheint.
Die eigentliche Bildschirmausgabe können Sie einfach gestalten.
Beispielsweise können Sie einmal pro Sekunde (oder in kürzeren Intervallen) den gesamten Bildschirminhalt neu ausgeben.