(Verantwortlich für die Seiten: W. Seyboldt / Stand: 15. März 2001)
Das fertige Applet und dessen Code: KeinThread01.htm
Das Applet bewegt einen Ball auf einem Tisch . Das Objekt vom Typ KeinThread01, eine Unterklasse von Applet, behandelt dabei lediglich die Benutzereingabe. Nach Drücken des Buttons wird ein Objekt vom Typ Ball erstellt und gestartet, das die Position des Balles ändert und ihn dann erneut anzeigt. Da dieses Programm kein Thread ist, gibt es den Prozessor während der Wartezeit nicht frei, sondern läuft solange, bis es von sich aus beendet ist, hier etwa 20 Sekunden lang. Während dieser Zeit kann der Button nicht erneut gedrückt werden. Soll das Programm davor beendet werden, oder tritt ein Programmierfehler auf, kann der Browser evtl. nur mit dem Task-Manager gestoppt werden oder dadurch, dass der Rechner durch einen Warmstart neu initialisiert wird.
Bemerkung: Natürlich können andere Programme auf dem Rechner weiterhin parallel ablaufen, wenn das Betreibssystem ein Time-Sharing von parallelen Prozessen ermöglicht. Manche Browser erlauben auch ein Beenden, da in ihnen jedes Applet als Thread läuft.
Zum Applet selbst:
Wenn der Button im Appletfenster gedrückt wird, wird ein Objekt der Klasse Ball erzeugt und von diesem Objekt die Methode anzeigen aufgerufen. In dieser Methode wird eine for-Schleife ausgeführt, die den Ball bewegt. Damit das Objekt den Ball auf den Schirm zeichnen kann, wird ihm im Konstruktor das Graphics-Objekt des Applets übergeben.
public void actionPerformed(ActionEvent event) { if (event.getSource() == start) { Graphics g = getGraphics(); Ball ball = new Ball(g); ball.anzeigen();} public void anzeigen() { int ddx, ddy; g.setColor(Color.white); // den Tisch zeichnen g.fillRect(tischX0, tischY0, tischX1-tischX0, tischY1-tischY0); g.setColor(Color.black); g.drawRect(tischX0, tischY0, tischX1-tischX0, tischY1-tischY0); for (int n=1; n<100; n++) { //siehe Schleife unten }}
Der Tisch wird durch die Koordinaten der linken oberen und
der rechten unteren Ecke beschrieben (hier 50/30 und 150/130) und durch ein
einfaches Rechteck dargestellt (Methode drawRect). Der Ball ist ein Kreis, der
durch seinen Durchmesser d und den Punkt der linken oberen Ecke des umgebenden
Quadrats, durch (x/y) beschreiben wird (wegen der Funktion g.fillOval). Der Ball
wird in einer Schleife 100 mal gezeichnet.
Genauer: Zuerst wird der Ball mit der Hintergrundfarbe gezeichnet und ist damit
nicht mehr sichtbar, dann werden die Punktkoordinaten geändert und der Ball
wird mit der Ballfarbe gezeichnet. Danach wird durch Aufruf der Methode
Thread.sleep(200) 200 Millisekunden lang gewartet, bevor die nächste Schleife
durchlaufen wird.
for (int n=1; n<100; n++) { g.setColor(Color.white); //Hintergrundfarbe g.fillOval(x,y,d,d); // Ball löschen ddx=dx; ddy=dy; // Ändern der Ballposition if (x+dx<=tischX0) {ddx=-(x-tischX0-1); dx=-dx;} if (x+dx+d>=tischX1) {ddx=tischX1-x-d-1; dx=-dx;} if (y+dy<=tischY0) {ddy=-(y-tischY0-1); dy=-dy;} if (y+dy+d>=tischY1) {ddy=tischY1-y-d-1; dy=-dy;} x=x+ddx; y=y+ddy; g.setColor(Color.red); // Ballfarbe g.fillOval(x,y,d,d); // Ball an neuer Position zeichnen try { Thread.sleep(200);} // 200 ms warten catch (InterruptedException e) { System.err.println("Ausnahme bei sleep");}}
Die Variablen dx und dy beschreiben die Solländerung in die jeweiligen Richtungen. ddx und ddy die wirkliche Änderung. Wenn durch dx (bzw dy) der Ball den Tischrand überschreiten würde, wird ddx (bzw. ddy) verringert und dx bzw. dy ändern das Vorzeichen, so dass der Ball reflektiert wird.
Das fertige Applet und dessen Code: Thread01.htm
Dieses Applet unterscheidet sich vom vorigen Applet nur dadurch, dass das Objekt, das beim Drücken des Buttons gestartet wird, eine Unterklasse vom Typ Thread ist. Damit wird der Prozessor in den Wartezeiten zwischen dem Zeichnen der Kugel freigegeben. Dies bedeutet unter anderem, dass der Button Start wiederholt gedrückt werden kann. Jedesmal erscheint dann auf dem Tisch ein weiterer sich bewegende Ball. Jeder Ball wird durch einen eigenständigen Thread dargestellt.
In der Methode actionPerformed, die beim Drücken des Buttons aufgerufen wird, wird nun nach dem Erzeugen des Objekts ball vom Typ Ball nicht mehr die selbstdefinierte Methode ball.anzeigen aufgerufen, sondern die Methode ball.start. Dies ist eine Methode der Superklasse Thread, die automatisch die Methode run startet. Diese Methode run wird nun selbst programmiert und enthält die oben beschriebene for-Schleife (Hier wird die for-Schleife erst nach 5000 Zyklen beendet, d.h. nach 500 Sekunden (die Wartezeit ist auf 100 ms eingestellt.)
public void actionPerformed(ActionEvent event) { if (event.getSource() == start) { Graphics g = getGraphics(); Ball ball = new Ball(g); ball.start();}} public void run() { int ddx, ddy; for (int n=1; n<5000; n++) { // siehe Schleife oben beim Applet KeinThread01
Der Button kann nun jederzeit gedrückt werden. Bei jedem Drücken wird ein Objekt vom Typ Ball erzeugt, das eigenständig läuft. Wird der Button also dreimal gedrückt, sieht man drei Bälle am Bildschirm, die sich in derselben Bahn bewegen.
Das fertige Applet und dessen Code: Kugeln01.htm
Verbesserung von Thread01: Die Kugeln haben nun unterschiedliche Farbe und kommen mit unterschiedlicher Geschwindigkeit und Richtung aus der Mitte des Tisches.
Beim Aufruf des Kontruktors werden nun die entsprechenden Parameter gesetzt. Die Funktion Math.random() liefert eine Zufallszahl zwischen 0 und 1 (einschließlich der 0, ohne die 1). Wird diese Zahl z.B. mit 3 multipliziert und dann nach int konvertiert, so ergibt sich entweder 0 oder 1 oder 2.
Bestimmen der Farbe:
int fn = (int) (Math.random()*4); switch (fn) { case 0 : farbe=Color.red;break; case 1 : farbe=Color.blue; break; case 2 : farbe=Color.green; break; case 3 : farbe=Color.yellow; break;}
Bestimmen der Startparameter Kugelmitte (x,y), Dicke d und Geschwindigkeit (dx,dy):
private int x = tischX0+(tischX1-tischX0)/2; private int y = tischY0+(tischY1-tischY0)/2; private int d = (int) (Math.random()*3)+6; private int dx = (int) (Math.random()*11)-5; private int dy = (int) (Math.random()*11)-5;
Diese Berechnungen können sogar bei der Deklaration der Variablen vorgenommen werden, da Java die hierfür nötigen Berechnungen vor dem Code des Konstruktors ausführt.
Die for-Schleige wurde hier durch ein While-Schleife ersetzt, bei der die Begingung (1==1) stets erfüllt ist, so dass sie quasi unendlich lange läuft.
Das fertige Applet und dessen Code: Wurm01.htm
Im Spektrum 3/88 S.8 ff war vor einigen Jahren ein Artikel über Würmer, die auf einem Tisch laufen. Die Würmer bestehen aus Kreisen, die sich leicht überlappen. Die Bewegung der Würmer wir dadurch simuliert, dass das letzte Glied gelöscht wird und vorne ein neuer Kreis gezeichnet wird. Da sich Würmer nicht immer gerade bewegen, muss man die Bewegungsrichtung bei jedem Schritt leicht variieren.
Dieses Applet lässt bei jedem Druck auf einen Button einen neuen Wurm aus der Mitte eines Tisches krabbeln. Die Würmer sind durch folgende Parameter bestimmt:
Der eigentlich Code, der den Wurm wandern lässt, ist recht kurz:
public void run() { while (1==1) { // Löschen des letzten Gliedes g.setColor(Color.white); g.fillOval(gliedx[länge-1],gliedy[länge-1],dicke,dicke); // Erneutes Zeichnen der übrigen Glieder, damit ein Wurm auch dann // sichtbar ist, wenn das Fenster verändert wurde. g.setColor(farbe); for (int i=länge-1;i>0;i--) { gliedx[i]=gliedx[i-1]; gliedy[i]=gliedy[i-1]; g.fillOval(gliedx[i],gliedy[i],dicke,dicke); } // neue Richtung bestimmen richtung+=maxDreh*(Math.random()-0.5); if (richtung>2*Math.PI) richtung-=2*Math.PI; if (richtung<0) richtung+=2*Math.PI; // neuen Kopfkreis zeichnen gliedx[0]=gliedx[0]+(int)(abstand*Math.cos(richtung)); gliedy[0]=gliedy[0]+(int)(abstand*Math.sin(richtung)); g.fillOval(gliedx[0],gliedy[0],dicke,dicke); try { Thread.sleep(200);} catch (InterruptedException e) { System.err.println("Ausnahme bei sleep");}}
Der Rest des Codes ist, abgesehen von den leicht geänderten Initialisierungen, gleich wie beim obigen Applet.
Das fertige Applet und dessen Code: Wurm02.htm
Die Würmer sollen nun den Tisch nicht verlassen.