Threads
Wir möchten nun erreichen, dass der Text nicht nur angezeigt, sondern auch animiert wird. Dazu müssen wir ihn in regelmäßigen Zeitabständen an einer leicht versetzten Position ausgeben. Zumindest der zweite Teil der Aufgabe ist relativ leicht zu lösen, indem wir die x-Position in einer Variable speichern, die wir bei jedem Neuzeichnen verändern:
public void paint(Graphics g) {
pos--;
if (pos<-200) pos=200;
g.drawString("Es gibt noch Bier auf Hawai..",pos,30);
}
Naheliegend wäre es, den Code einfach in einer Schleifelaufen zu lassen, damit pos regelmässig verändert wird. Leider funktioniert das nicht. Die Schleife würde zwar korrekt gezählt, aber das Programm hätte niemals Zeit, die Ausgabe zu zeichnen. Selbst wenn wir die Ausführung pausieren lassen, kann das Programm seine Oberfläche nicht neu zeichnen, weil es ja eben pausiert.
Wir brauchen daher einen zweiten Thread, der die Paint-Methode des ersten regelmässig aufruft. Ein Thread ist so etwas wie ein zweites kleines Programm, das parallel zu dem ersten abläuft. Dann hätte unser ursprünglicher Thread Zeit, die Bildschirmausgabe zu zeichnen. Ein Thread ist so klein, dass er nur aus einer einzigen Methode besteht: run(). Diese Methode ist definiert in java.lang.Runnable, und jede Klasse, die Runnable implementiert, kann einen zweiten Thread aufmachen.
Wir implementieren daher in unserem Applet java.lang.Runnable und schreiben wie es das Interface verlangt die Run-Methode:
public void run() {
// Endlosschleife für Animation
while (true) {
// dies wird regelmässig ausgeführt
repaint();
try {
// Pause des Threads einplanen
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Run läuft endlos in einer while-Schleife und ruft repaint() auf. Repaint ist eine Methode aus java.awt.Component, die den Ausgabebereich löscht (mit der Hintergrundfarbe malt) und anschliessend paint(Graphics) aufruft; das ist die Methode, die wir überschrieben haben. Wir rufen also quasi paint(Graphics) über einen Umweg auf. Anschliessend pausiert der Thread mit Thread.sleep(Millisekunden).
Der neue Thread muss aber auch gestartet werden. Dazu genügt es nicht, run() einfach aufzurufen. Vielmehr muss die Java – VM aus der Runnable – Klasse einen neuen Thread erzeugen. Daher wird ein Thread stets mit (Thread#start()) gestartet:
Thread thread=new Thread(runnableImplementingObject)
thread.start();
Die Java – VM erkennt so, dass sie einen neuen Thread starten soll, und ruft die run()-Methode des Runnable-Objekts in einem neuen Thread auf. Schauen wir uns das Beispiel an:
public void start() {
new Thread(this).start();
}
„Start()" wird ja beim Starten des Applets durch den Browser aufgerufen. This ist das Applet selbst, das Runnable implementiert und somit für einen zweiten Thread gut ist.
Stoppen können Sie einen solchen Thread nur schwer. Wie Sie in der Dokumentation zu java.lang.Thread sehen, ist die Methode Thread#stop() deprecated, soll also nicht mehr verwendet werden. Wenn man den Thread kontrolliert beenden will, ist es am besten, statt while(true) eine Variable zu verwenden (while(isRunning)) und diese umzuschalten, damit der Thread ausläuft. Beachten Sie, das ein Programm nicht auf natürlichem Wege zu Ende geht, wenn noch ein Thread läuft.
Aufgabe: LaufschriftAppletStartStop
Schreiben Sie ein Laufschrift - Applet, dessen Animation sich auf Mausklick starten und stoppen läßt.
Musterlösung: java1.aufg.referenz.LaufschriftAppletStartStop