| |
Dieses
Kapitel sollten Sie bearbeiten, falls der bisherige Kurs für Sie zu
schnell gegangen ist. Mit Hilfe der Turtle Grafik sollen Sie Ablaufstrukturen
und OOP trainieren. Aber: Turtle Grafik macht auch Spass! Es gibt sie
für fast alle Programmiersprachen als sehr effizientes Trainings -
Tool.
Die
Idee der Trutle Grafik ist sehr einfach: Eine Turtle (Schildkröte)
bewegt sich programmgesteuert auf dem Bildschirm. Sie kann einfache
Anweisungen ausführen: vorwärts, nach rechts drehen, etc. Und das Schöne
ist: Sie kann eine Spur hinterlassen, so dass ihr Weg zu einer Grafik
wird.
Damit
wir das Ganze nicht selber programmieren müssen, übernehmen wir eine
Klassenbibliothek von Ägidius Plüss, welche sein wunderschönes Buch
"Java - exemplarisch" begleitet und welche auf der Website www.aplu.ch zu
finden ist. Sie sehen so auch gleich, wie man Klassenbibliotheken verwendet,
welche nicht zum Standard SDK gehören:
- Am besten
kopieren Sie die Bibliothek (aplu.jar)
auf Ihr P: in Ihren Java Ordner.
- Erstellen
Sie jetzt ein neues Projekt z.B. mit dem Namen TurtleTest vom
Typ "Empty
Project".
- Ein
solches Projekt enthält noch gar keine Datei. Klicken Sie im "File
View" Fenster mit der rechten Taste auf Ihr Projekt und wählen Sie
"Add...", "New File ...", geben Sie der Datei den Namen TurtleTest.java
und speichern Sie sie hinter "Location" in Ihrem Projektordner.
- Die
Quelldatei ist noch ganz leer, hier brauchen wir die Template Hilfe
von JCreator nicht, unser Programm ist nämlich sehr einfach:
import ch.aplu.turtle.*;
class TurtleTest {
public static void main(String[] args) {
Turtle fritz = new Turtle();
}
}
- Wenn
Sie das übersetzen, gibt's haufenweise Fehlermeldungen, denn das
Package ch.aplu.turtle wird nicht gefunden. Dem helfen Sie ab, indem
Sie JCreator sagen, wo er die Bibliothek findet: Menü "Project",
"Project Properties...", "Required
Libraries", "New...", "Classes",
"Add", "Add Archive". Jetzt suchen Sie Ihr aplu.jar und wählen es
aus. Geben Sie im Fenster "Set Library" der Bibliothek noch einen
Namen, z.B. Turtle und setzen Sie im Fenster "Project Properties"
den Haken vor Turtle. Leider müssen Sie diese Einstellung in der
Schule nach jedem Computerneustart machen - der HDDSheriff lässt
grüssen!.
|
 |
| |
- Übersetzen Sie -
das sollte jetzt klappen - und führen Sie aus: Die Turtle sitzt mitten
in ihrem "Playground" und wartet auf Befehle!
Haben Sie bemerkt,
wie schön objektorientiert alles läuft? Es gibt eine Klasse Turtle,
von der Sie eine Instanz mit Namen fritz gemacht haben. Bei der Instanzierung
von fritz ist für uns unsichtbar im Hintergrund sehr viel passiert:
fritz hat sich
nämlich einen
Playground, also ein grafisches Fenster, gemacht. Selbstverständlich
hat die Klasse Turtle Methoden, welche fritz bekannt sind, z.B. forward(),
right() und left().
- Ergänzen Sie Ihr
Programm:
Turtle fritz = new Turtle();
fritz.forward(20);
fritz.right(90);
fritz.forward(50);
und lassen Sie es laufen. Ich denke, dass Sie begriffen haben wie's geht.
- Schaffen Sie eine
Treppe mit 5 Schritten? Und eine solche mit 100 Schritten, so dass
eine for - Schlaufe nötig ist?
|
 |
| |
- Oder wie wär's
mit einer patriotischen Turtle? Siehe Bild rechts!
- Fritz sollte doch
nicht ganz allein sein - wie wär's wenn sich ida dazu gesellen würde:
eine zweite Instanz von Turtle!
- Hoppla, ida hat
sich ihren eigenen Playground gemacht. Turtle hat aber noch weitere
Konstruktoren:
Turtle ida = new Turtle(fritz);
Als Parameter für den
Konstrukor von ida geben wir an, in wessen Playground sie spielen soll!
- ida sollte nicht
gleich aussehen wie Fritz, also verwenden wir einen weiteren Konstruktor
von Turtle:
Turtle ida = new Turtle(fritz,java.awt.Color.yellow);
Selbstverständlich können Sie auch java.awt.* importieren. Das lohnt sich, falls
es in Zukunft noch farbiger werden soll.
Falls Sie wissen
möchten, was eine Turtle sonst noch kann, schauen Sie in der Dokumentation zur
Bibliothek nach und suchen Sie die Klasse Turtle.
Zurück zum Schweizerkreuz
und zum Thema OOP! Sie haben wohl die vier Arme des Kreuzes schön einzeln
ausprogrammiert. Das geht bei vier Armen, wird aufwändig bei 100 und
ist überhaupt unschön. Unsere Turtle sollte doch einfach die Eigenschaft
haben, dass sie einen Arm zeichnen kann. Eine Eigenschaft eines Objektes
ist in Java ja eine Methode. Schreiben wir also eine Methode, welche
einen Arm eines Kreuzes zeichnet und rufen wir diese Methode viermal
auf. Wenn Sie das versuchen, dann stolpern Sie über eine der häufigsten
Fehlermeldungen in Java:
"non-static method
arm() cannot be referenced from a static context"
heisst es dann bei
der Übersetzung, falls Ihre Methode arm() heisst. Die Methode main()
ist static, das heisst, sie wird in der Klasse deklariert,
sie ist aber in keiner Instanz der Klasse vorhanden. Die Methode arm()
ist aber nicht-statisch und damit haben wir das Problem. Es gibt verschiedene
Lösungen zu diesem Problem. Wir wählen diejenige, welche auch JCreator
wählt. Erinnern Sie sich: Bei einem Projekt vom Typ "Basic Java Application"
wurden jeweils zwei Quelldateien mit zwei Klassen erstellt: Die Eine
enthielt die Methode main(), in welcher eine Instanz der andern Klasse
erzeugt wurde. Das wollen wir jetzt auch machen, nur noch etwas knapper.
Schauen Sie sich den folgenden Quelltext an und die nachfolgenden Erklärungen:
import ch.aplu.turtle.*;
class Koch {
Koch() {
Turtle fritz = new Turtle();
for (int i=1; i<=4; i++) arm(fritz);
}
void arm(Turtle t) {
t.forward(50);
t.right(90);
t.forward(30);
t.right(90);
t.forward(50);
t.left(90);
}
public static void main(String[] args) {
new Koch();
}
}
- Meine Klasse heisst
Koch, weil wir später mit ihr eine sogenannte Koch - Kurve zeichnen
wollen.
- Im Konstruktor
der Klasse wird die Instanz fritz der Klasse Turtle erstellt und
es wird in der for - Schlaufe viermal die Methode arm() aufgerufen.
- Die Methode arm()
erwartet als Parameter eine Turtle Instanz, mit welcher sie arbeitet.
Beachten Sie die letzte Anweisung: Die Turtle richtet sich so aus,
dass der nächste Arm gezeichnet werden kann.
- Die Methode main()
ist hier in der selben Klasse (bei JCreator eine separate Klasse
in einer separaten Datei) und erzeugt eine Instanz der Klasse. Dieser
Instanz wird nicht einmal ein Name gegeben, weil dieser ja auch nicht
weiter verwendet wird.
Merken Sie sich diesen
Trick, wie man das Problem mit dem "static context" umgehen kann! Und jetzt
zur Anwendung:
- Erstellen Sie
ein neues "Empty Project" namens Koch, fügen Sie dem Projekt eine
Quelldatei Koch.java zu, fügen Sie den obigen Quelltext in die Datei
ein (kopieren, warum auch nicht?), übersetzen und testen Sie - Sie
sollten wieder ein Schweizerkreuz haben!
- Da jetzt unser
Kreuz auf OOP Art programmiert ist, stehen uns viele Möglichkeiten
offen, die wir etwas ausloten wollen: Drehen Sie am Schluss die Turtle
um 170 anstatt 90 Grad!
- Wenn die Arme
so fast nebeneinander liegen, dann sollte das "Kreuz" eben 36 Arme
haben! Bevor Sie die for - Schlaufe verändern, sollten Sie die Arme
kleiner machen, sonst hat's nicht Platz im Fenster.
|

|
| |
- Meine Methode heisst
linie, sie zeichnet eine Verbindung von A (linker Rand) nach B (rechter
Rand). Diese Verbindung ist aber nicht eine einfache Strecke, die Strecke
wird in
drei Teile
der Länge laenge unterteilt. Der mittlere Teil besteht aus zwie
Strecken der Länge laenge, die zwei Seiten eines gleichseitigen Dreiecks
bilden.
- Da ich nur eine
Turtle brauche, wird sie nicht der Methode übergeben. Damit sie sowohl
im Konstruktor als auch in der Methode bekannt ist, wird sie in der
Klasse deklariert.
- Mit setX() startet
die Turtle am linken Rand und mit hideTurtle() wird schneller gezeichnet.
- Ändern Sie Ihre
Quelldatei entsprechend und testen Sie!
Die Verbindung
von A nach B besteht also selber wieder aus vier Verbindungen und
diese müssten
nicht unbedingt eine Strecke sein, sondern wir könnten aus jede wieder
die Vorschriften der Methode linie anwenden. Irgendmal braucht's
aber ein Ende
für dieses "sich selber wieder aufrufen": Wenn die Länge klein
genug geworden ist, zeichnen wir die Strecke. Das sieht dann etwa
so aus: void linie(int laenge) {
laenge = laenge / 3;
if (laenge > limit) linie(laenge);
else t.forward(laenge);
t.left(60);
if (laenge > limit) linie(laenge);
else t.forward(laenge);
t.right(120);
if (laenge > limit) linie(laenge);
else t.forward(laenge);
t.left(60);
if (laenge > limit) linie(laenge);
else t.forward(laenge);
}
Die Variable limit
bestimmt bei welcher Streckenlänge die Rekursion abbricht.
- Ändern Sie wieder
und testen Sie für verschiedene Werte von limit.
- Die Kurve sieht
aus wie ein Teil einer Schneeflocke. Mit drei Grunsstrecken, die ein
gleichseitiges Dreieck bilden, erhalten Sie die vollständige Schneeflocke.
Falls Sie weiter an
der Theorie zu dieser Kurve interessiert sind, finden Sie z.B. hier oder
hier weitere
Angaben.Eine Kurve, welche sich selbst wieder enthält, heisst auch Fraktal.Fraktale
sind von grosser Bedeutung in der Chaostheorie.
Viel Vergnügen bei weiteren Experimenten! |
 |