diff options
| author | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
|---|---|---|
| committer | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
| commit | 33613a85afc4b1481367fbe92a17ee59c240250b (patch) | |
| tree | 670b842326116b376b505ec2263878912fca97e2 /Master/Reference Architectures and Patterns/hjp5/html/k100226.html | |
| download | Studium-33613a85afc4b1481367fbe92a17ee59c240250b.tar.gz Studium-33613a85afc4b1481367fbe92a17ee59c240250b.tar.bz2 | |
Diffstat (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100226.html')
| -rw-r--r-- | Master/Reference Architectures and Patterns/hjp5/html/k100226.html | 1504 |
1 files changed, 1504 insertions, 0 deletions
diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100226.html b/Master/Reference Architectures and Patterns/hjp5/html/k100226.html new file mode 100644 index 0000000..546f4de --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100226.html @@ -0,0 +1,1504 @@ +<html>
+<head>
+<title>
+Handbuch der Java-Programmierung, 5. Auflage
+</title>
+</head>
+<body>
+<a name="startofbody"></a>
+<script language="JavaScript" src="hjp4lib.js">
+</script>
+<script language="JavaScript">
+installKbdHandler("97,#startofbody;101,#endofbody;116,cover.html;122,k100003.html;115,search.html;105,index.html;100,JDKDOCS;112,APIDOCS;104,k100224.html;106,k100225.html;107,k100227.html;108,k100228.html");
+</script>
+<table border=0 cellpadding=0 cellspacing=1 width="100%">
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html"> Titel </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html"> Inhalt </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html"> Suchen </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html"> Index </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()"> DOC </a>
+<td align="right">Handbuch der Java-Programmierung, 5. Auflage
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100224.html"> << </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100225.html"> < </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100227.html"> > </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100228.html"> >> </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()"> API </a>
+<td align="right">Kapitel 34 - Bitmaps und Animationen
+</table>
+<hr>
+
+
+<!-- Section -->
+<a name="sectlevel2id034002"></a>
+<h2>34.2 <a name="ixa102341">Animation</a></h2>
+<hr>
+<ul>
+<li><a href="k100226.html#sectlevel2id034002">34.2 Animation</a>
+<ul>
+<li><a href="k100226.html#sectlevel3id034002001">34.2.1 Prinzipielle Vorgehensweise</a>
+<ul>
+<li><a href="k100226.html#sectlevel4id034002001001">Die repaint-Schleife</a>
+<li><a href="k100226.html#sectlevel4id034002001002">Verwendung von Threads</a>
+</ul>
+<li><a href="k100226.html#sectlevel3id034002002">34.2.2 Abspielen einer Folge von Bitmaps</a>
+<li><a href="k100226.html#sectlevel3id034002003">34.2.3 Animation mit Grafikprimitiven</a>
+<li><a href="k100226.html#flackernreduzieren">34.2.4 Reduktion des Bildschirmflackerns</a>
+<ul>
+<li><a href="k100226.html#sectlevel4id034002004001">Bildschirm nicht löschen</a>
+<li><a href="k100226.html#sectlevel4id034002004002">Nur den wirklich benötigten Teil des Bildschirms löschen</a>
+<li><a href="k100226.html#sectlevel4id034002004003">Doppelpufferung</a>
+</ul>
+</ul>
+</ul>
+<hr>
+
+
+<!-- Section -->
+<a name="sectlevel3id034002001"></a>
+<h3>34.2.1 Prinzipielle Vorgehensweise </h3>
+
+<p>
+Das Darstellen einer Animation auf dem Bildschirm ist im Prinzip nichts
+anderes als die schnell aufeinanderfolgende Anzeige einer Sequenz
+von Einzelbildern. Die Bildfolge erscheint dem menschlichen Auge aufgrund
+seiner Trägheit als zusammenhängende Bewegung.
+
+<p>
+Obwohl die prinzipielle Vorgehensweise damit klar umrissen ist, steckt
+die Tücke bei der Darstellung von animierten Bildsequenzen im
+Detail. Zu den Problemen, die in diesem Zusammenhang zu lösen
+sind, gehören:
+<ul>
+<li>Für die Anzeige der Einzelbilder muss das richtige <i>Timing</i>
+gewählt werden. Werden zu wenig Bilder je Zeiteinheit angezeigt,
+erscheint das Ergebnis ruckelig. Werden zu viele gezeigt, kann es
+sein, dass <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>-Events
+verlorengehen und Teile des Bildes nicht korrekt angezeigt werden.
+<li>Wird zur Anzeige der Einzelbilder der normale <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>-/<a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Mechanismus
+von Java verwendet, wird die Darstellung durch ein starkes <i>Flackern</i>
+gestört. Wir werden eine Reihe von Techniken kennenlernen, mit
+denen dieses Flackern verhindert werden kann.
+<li>Die Darstellung der Einzelbilder darf nicht die <i>Interaktivität</i>
+des Programms beeinträchtigen. Vor allem darf die Nachrichtenschleife
+nicht blockiert werden. Wir werden lernen, wie man diese Probleme
+mit Hilfe separater Threads umgehen kann.
+</ul>
+
+<p>
+All dies sind Standardprobleme, die vom Programmierer bei der Entwicklung
+von Animationen zu lösen sind. Wir werden feststellen, dass Java
+dafür durchweg brauchbare Lösungen zu bieten hat und die
+Programmierung kleiner Animationen recht einfach zu realisieren ist.
+
+
+<!-- Section -->
+<a name="sectlevel4id034002001001"></a>
+<h4>Die <a name="ixa102342">repaint-Schleife</a> </h4>
+
+<p>
+Das Grundprinzip einer Animation besteht darin, in einer Schleife
+die Methode <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>
+wiederholt aufzurufen. Ein Aufruf von <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>
+führt dazu, dass die <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>-Methode
+aufgerufen wird, und innerhalb von <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+generiert die Anwendung dann die für das aktuelle Einzelbild
+benötigte Bildschirmausgabe.
+
+<p>
+<a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+muss sich also merken (oder mitgeteilt bekommen), welches Bild bei
+welchem Aufruf erzeugt werden soll. Typischerweise wird dazu ein Schleifenzähler
+verwendet, der das gerade anzuzeigende Bild bezeichnet. Nach dem Ausführen
+der Ausgabeanweisungen terminiert <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>,
+und der Aufrufer wartet eine bestimmte Zeitspanne. Dann zählt
+er den Bildzähler hoch und führt den nächsten Aufruf
+von <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>
+durch. Dies setzt sich so lange fort, bis die Animation beendet ist
+oder das Programm abgebrochen wird.
+
+<p>
+Das folgende Listing stellt eines der einfachsten Beispiele für
+eine Grafikanimation dar:
+<a name="listingid034006"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* Listing3406.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.awt.*;
+<font color="#555555">004 </font><font color="#0000AA">import</font> java.awt.event.*;
+<font color="#555555">005 </font>
+<font color="#555555">006 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing3406
+<font color="#555555">007 </font><font color="#0000AA">extends</font> Frame
+<font color="#555555">008 </font>{
+<font color="#555555">009 </font> <font color="#006699">int</font> cnt = 0;
+<font color="#555555">010 </font>
+<font color="#555555">011 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">012 </font> {
+<font color="#555555">013 </font> Listing3406 wnd = <font color="#0000AA">new</font> Listing3406();
+<font color="#555555">014 </font> wnd.setSize(250,150);
+<font color="#555555">015 </font> wnd.setVisible(<font color="#006699">true</font>);
+<font color="#555555">016 </font> wnd.startAnimation();
+<font color="#555555">017 </font> }
+<font color="#555555">018 </font>
+<font color="#555555">019 </font> <font color="#0000AA">public</font> Listing3406()
+<font color="#555555">020 </font> {
+<font color="#555555">021 </font> <font color="#006699">super</font>(<font color="#0000FF">"Animierter Zähler"</font>);
+<font color="#555555">022 </font> setBackground(Color.lightGray);
+<font color="#555555">023 </font> addWindowListener(<font color="#0000AA">new</font> WindowClosingAdapter(<font color="#006699">true</font>));
+<font color="#555555">024 </font> }
+<font color="#555555">025 </font>
+<font color="#555555">026 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> startAnimation()
+<font color="#555555">027 </font> {
+<font color="#555555">028 </font> <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
+<font color="#555555">029 </font> repaint();
+<font color="#555555">030 </font> }
+<font color="#555555">031 </font> }
+<font color="#555555">032 </font>
+<font color="#555555">033 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> paint(Graphics g)
+<font color="#555555">034 </font> {
+<font color="#555555">035 </font> ++cnt;
+<font color="#555555">036 </font> g.drawString(<font color="#0000FF">"Counter = "</font>+cnt,10,50);
+<font color="#555555">037 </font> <font color="#0000AA">try</font> {
+<font color="#555555">038 </font> Thread.sleep(1000);
+<font color="#555555">039 </font> } <font color="#0000AA">catch</font> (InterruptedException e) {
+<font color="#555555">040 </font> }
+<font color="#555555">041 </font> }
+<font color="#555555">042 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/Listing3406.java"><font color="#000055" size=-1>Listing3406.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.6: Ein animierter Zähler</i></p>
+
+<p>
+Das Programm öffnet ein Fenster und zählt in Sekundenabständen
+einen Zähler um eins hoch:
+<p>
+<a name="imageid034003"></a>
+<img src="images/ZaehlerAnim.gif">
+<p>
+
+<p><i>
+Abbildung 34.3: Ein animierter Zähler</i></p>
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=1></td>
+<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Leider hat das Programm einen entscheidenden Nachteil. Die Animation
+selbst funktioniert zwar wunderbar, aber das Programm reagiert nur
+noch sehr schleppend auf Windows-Nachrichten. Wir wollen zunächst
+dieses Problem abstellen und uns ansehen, wie man die <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Schleife
+in einem eigenen <a href="index_t.html#ixb100591"><font color=#000080><tt>Thread</tt></font></a>
+laufen läßt.</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#CC0000">
+<tr>
+<td><font color="#FFFFFF"> Warnung </font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+
+
+<!-- Section -->
+<a name="sectlevel4id034002001002"></a>
+<h4>Verwendung von <a name="ixa102343">Threads</a> </h4>
+
+<p>
+Um die vorherige Version des Programms zu verbessern, sollte die <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Schleife
+in einem eigenen <a href="index_t.html#ixb100591"><font color=#000080><tt>Thread</tt></font></a>
+laufen. Zusätzlich ist es erforderlich, die Zeitverzögerung
+aus <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+herauszunehmen und statt dessen in die <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Schleife
+zu verlagern. So bekommt der Haupt-Thread des Animationsprogramms
+genügend Zeit, die Bildschirmausgabe durchzuführen und kann
+andere <font color="#000077"><tt>Events</tt></font> bearbeiten. Daß
+in einem anderen <a href="index_t.html#ixb100591"><font color=#000080><tt>Thread</tt></font></a>
+eine Endlosschleife läuft, merkt er nur noch daran, dass in regelmäßigen
+Abständen <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Ereignisse
+eintreffen.
+
+<p>
+Um das Programm auf die Verwendung mehrerer Threads umzustellen, sollte
+die Fensterklasse das Interface <a href="index_r.html#ixb101107"><font color=#000080><tt>Runnable</tt></font></a>
+implementieren und eine Instanzvariable vom Typ <a href="index_t.html#ixb100591"><font color=#000080><tt>Thread</tt></font></a>
+anlegen. Dann wird die Methode <font color="#000077"><tt>startAnimation</tt></font>
+so modifiziert, dass sie den neuen <a href="index_t.html#ixb100591"><font color=#000080><tt>Thread</tt></font></a>
+instanziert und startet. Die eigentliche <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Schleife
+wird in die Methode <a href="index_r.html#ixb101108"><font color=#000080><tt>run</tt></font></a>
+verlagert. Schließlich sollte beim Beenden des Programms auch
+der laufende <a href="index_t.html#ixb100591"><font color=#000080><tt>Thread</tt></font></a>
+beendet werden. Hier ist die modifizierte Fassung:
+<a name="listingid034007"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* Listing3407.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.awt.*;
+<font color="#555555">004 </font><font color="#0000AA">import</font> java.awt.event.*;
+<font color="#555555">005 </font>
+<font color="#555555">006 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing3407
+<font color="#555555">007 </font><font color="#0000AA">extends</font> Frame
+<font color="#555555">008 </font><font color="#0000AA">implements</font> Runnable
+<font color="#555555">009 </font>{
+<font color="#555555">010 </font> <font color="#006699">int</font> cnt = 0;
+<font color="#555555">011 </font>
+<font color="#555555">012 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">013 </font> {
+<font color="#555555">014 </font> Listing3407 wnd = <font color="#0000AA">new</font> Listing3407();
+<font color="#555555">015 </font> wnd.setSize(250,150);
+<font color="#555555">016 </font> wnd.setVisible(<font color="#006699">true</font>);
+<font color="#555555">017 </font> wnd.startAnimation();
+<font color="#555555">018 </font> }
+<font color="#555555">019 </font>
+<font color="#555555">020 </font> <font color="#0000AA">public</font> Listing3407()
+<font color="#555555">021 </font> {
+<font color="#555555">022 </font> <font color="#006699">super</font>(<font color="#0000FF">"Animations-Threads"</font>);
+<font color="#555555">023 </font> setBackground(Color.lightGray);
+<font color="#555555">024 </font> addWindowListener(<font color="#0000AA">new</font> WindowClosingAdapter(<font color="#006699">true</font>));
+<font color="#555555">025 </font> }
+<font color="#555555">026 </font>
+<font color="#555555">027 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> startAnimation()
+<font color="#555555">028 </font> {
+<font color="#555555">029 </font> Thread th = <font color="#0000AA">new</font> Thread(<font color="#006699">this</font>);
+<font color="#555555">030 </font> th.start();
+<font color="#555555">031 </font> }
+<font color="#555555">032 </font>
+<font color="#555555">033 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> run()
+<font color="#555555">034 </font> {
+<font color="#555555">035 </font> <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
+<font color="#555555">036 </font> repaint();
+<font color="#555555">037 </font> <font color="#0000AA">try</font> {
+<font color="#555555">038 </font> Thread.sleep(1000);
+<font color="#555555">039 </font> } <font color="#0000AA">catch</font> (InterruptedException e) {
+<font color="#555555">040 </font> <font color="#00AA00">//nichts</font>
+<font color="#555555">041 </font> }
+<font color="#555555">042 </font> }
+<font color="#555555">043 </font> }
+<font color="#555555">044 </font>
+<font color="#555555">045 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> paint(Graphics g)
+<font color="#555555">046 </font> {
+<font color="#555555">047 </font> ++cnt;
+<font color="#555555">048 </font> g.drawString(<font color="#0000FF">"Counter = "</font>+cnt,10,50);
+<font color="#555555">049 </font> }
+<font color="#555555">050 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/Listing3407.java"><font color="#000055" size=-1>Listing3407.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.7: Verwendung von Threads zur Animation</i></p>
+
+<p>
+Das so modifizierte Programm erzeugt dieselbe Ausgabe wie das vorige,
+ist aber in der Lage, in der gewohnten Weise auf Ereignisse zu reagieren.
+Selbst wenn die Verzögerungsschleife ganz entfernt und der Hauptprozess
+so pausenlos mit <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Anforderungen
+bombardiert würde, könnte das Programm noch normal beendet
+werden.
+
+<!-- Section -->
+
+<a name="sectlevel3id034002002"></a>
+<h3>34.2.2 Abspielen einer Folge von Bitmaps </h3>
+
+<p>
+Eine der einfachsten und am häufigsten verwendeten Möglichkeiten,
+eine Animation zu erzeugen, besteht darin, die zur Darstellung erforderliche
+Folge von Bitmaps aus einer Reihe von Bilddateien zu laden. Jedem
+Einzelbild wird dabei ein <a href="index_i.html#ixb100643"><font color=#000080><tt>Image</tt></font></a>-Objekt
+zugeordnet, das vor dem Start der Animation geladen wird. Alle Images
+liegen in einem Array oder einem anderen Container und werden in der
+<a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>-Schleife
+nacheinander angezeigt.
+
+<p>
+Das folgende Programm speichert die 30 anzuzeigenden Einzelbilder
+in einem Array <font color="#000077"><tt>arImg</tt></font>, das nach
+dem Start des Programms komplett geladen wird. Da dieser Vorgang einige
+Sekunden dauern kann, zeigt das Programm den Ladefortschritt auf dem
+Bildschirm an:
+<p>
+<a name="imageid034004"></a>
+<img src="images/LadeVorgang.gif">
+<p>
+
+<p><i>
+Abbildung 34.4: Die Ausgabe während des Ladevorgangs</i></p>
+
+<p>
+Erst nach dem vollständigen Abschluss des Ladevorgangs, der mit
+einem <a href="index_m.html#ixb101739"><font color=#000080><tt>MediaTracker</tt></font></a>
+überwacht wird, beginnt die eigentliche Animation. Die ganzzahlige
+Instanzvariable <font color="#000077"><tt>actimage</tt></font> dient
+als Zähler für die Bildfolge und wird nacheinander von 0
+bis 29 hochgezählt, um dann wieder bei 0 zu beginnen. Nach jedem
+Einzelbild wartet das Programm 50 Millisekunden und führt dann
+den nächsten Aufruf von <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>
+durch:
+<a name="listingid034008"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* Listing3408.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.awt.*;
+<font color="#555555">004 </font><font color="#0000AA">import</font> java.awt.event.*;
+<font color="#555555">005 </font>
+<font color="#555555">006 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing3408
+<font color="#555555">007 </font><font color="#0000AA">extends</font> Frame
+<font color="#555555">008 </font><font color="#0000AA">implements</font> Runnable
+<font color="#555555">009 </font>{
+<font color="#555555">010 </font> Thread th;
+<font color="#555555">011 </font> Image[] arImg;
+<font color="#555555">012 </font> <font color="#006699">int</font> actimage;
+<font color="#555555">013 </font>
+<font color="#555555">014 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">015 </font> {
+<font color="#555555">016 </font> Listing3408 wnd = <font color="#0000AA">new</font> Listing3408();
+<font color="#555555">017 </font> wnd.setSize(200,150);
+<font color="#555555">018 </font> wnd.setVisible(<font color="#006699">true</font>);
+<font color="#555555">019 </font> wnd.startAnimation();
+<font color="#555555">020 </font> }
+<font color="#555555">021 </font>
+<font color="#555555">022 </font> <font color="#0000AA">public</font> Listing3408()
+<font color="#555555">023 </font> {
+<font color="#555555">024 </font> <font color="#006699">super</font>(<font color="#0000FF">"Bitmap-Folge"</font>);
+<font color="#555555">025 </font> addWindowListener(<font color="#0000AA">new</font> WindowClosingAdapter(<font color="#006699">true</font>));
+<font color="#555555">026 </font> }
+<font color="#555555">027 </font>
+<font color="#555555">028 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> startAnimation()
+<font color="#555555">029 </font> {
+<font color="#555555">030 </font> th = <font color="#0000AA">new</font> Thread(<font color="#006699">this</font>);
+<font color="#555555">031 </font> actimage = -1;
+<font color="#555555">032 </font> th.start();
+<font color="#555555">033 </font> }
+<font color="#555555">034 </font>
+<font color="#555555">035 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> run()
+<font color="#555555">036 </font> {
+<font color="#555555">037 </font> <font color="#00AA00">//Bilder laden</font>
+<font color="#555555">038 </font> arImg = <font color="#0000AA">new</font> Image[30];
+<font color="#555555">039 </font> MediaTracker mt = <font color="#0000AA">new</font> MediaTracker(<font color="#006699">this</font>);
+<font color="#555555">040 </font> Toolkit tk = getToolkit();
+<font color="#555555">041 </font> <font color="#0000AA">for</font> (<font color="#006699">int</font> i = 1; i <= 30; ++i) {
+<font color="#555555">042 </font> arImg[i-1] = tk.getImage(<font color="#0000FF">"images/jana"</font>+i+<font color="#0000FF">".gif"</font>);
+<font color="#555555">043 </font> mt.addImage(arImg[i-1], 0);
+<font color="#555555">044 </font> actimage = -i;
+<font color="#555555">045 </font> repaint();
+<font color="#555555">046 </font> <font color="#0000AA">try</font> {
+<font color="#555555">047 </font> mt.waitForAll();
+<font color="#555555">048 </font> } <font color="#0000AA">catch</font> (InterruptedException e) {
+<font color="#555555">049 </font> <font color="#00AA00">//nothing</font>
+<font color="#555555">050 </font> }
+<font color="#555555">051 </font> }
+<font color="#555555">052 </font> <font color="#00AA00">//Animation beginnen</font>
+<font color="#555555">053 </font> actimage = 0;
+<font color="#555555">054 </font> <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
+<font color="#555555">055 </font> repaint();
+<font color="#555555">056 </font> actimage = (actimage + 1) % 30;
+<font color="#555555">057 </font> <font color="#0000AA">try</font> {
+<font color="#555555">058 </font> Thread.sleep(50);
+<font color="#555555">059 </font> } <font color="#0000AA">catch</font> (InterruptedException e) {
+<font color="#555555">060 </font> <font color="#00AA00">//nichts</font>
+<font color="#555555">061 </font> }
+<font color="#555555">062 </font> }
+<font color="#555555">063 </font> }
+<font color="#555555">064 </font>
+<font color="#555555">065 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> paint(Graphics g)
+<font color="#555555">066 </font> {
+<font color="#555555">067 </font> <font color="#0000AA">if</font> (actimage < 0) {
+<font color="#555555">068 </font> g.drawString(<font color="#0000FF">"Lade Bitmap "</font>+(-actimage),10,50);
+<font color="#555555">069 </font> } <font color="#0000AA">else</font> {
+<font color="#555555">070 </font> g.drawImage(arImg[actimage],10,30,<font color="#006699">this</font>);
+<font color="#555555">071 </font> }
+<font color="#555555">072 </font> }
+<font color="#555555">073 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/Listing3408.java"><font color="#000055" size=-1>Listing3408.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.8: Abspielen einer Folge von Bitmaps</i></p>
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Das vorliegende Beispiel verwendet die Bilddateien <font color="#660099">jana1.gif</font>
+bis <font color="#660099">jana30.gif</font>. Sie zeigen die verschiedenen
+Phasen des in Schreibschrift geschriebenen Namens »Jana«.
+Alternativ kann aber auch jede andere Sequenz von Bilddateien verwendet
+werden. Die folgenden Abbildungen zeigen einige Schnappschüsse
+der Programmausgabe:</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
+<tr>
+<td><font color="#FFFFFF"> Hinweis </font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+<p>
+<a name="imageid034005"></a>
+<img src="images/JanaAnim1.gif">
+<p>
+
+<p><i>
+Abbildung 34.5: Animation eines Schriftzugs, Schnappschuß 1</i></p>
+<p>
+<a name="imageid034006"></a>
+<img src="images/JanaAnim2.gif">
+<p>
+
+<p><i>
+Abbildung 34.6: Animation eines Schriftzugs, Schnappschuß 2</i></p>
+<p>
+<a name="imageid034007"></a>
+<img src="images/JanaAnim3.gif">
+<p>
+
+<p><i>
+Abbildung 34.7: Animation eines Schriftzugs, Schnappschuß 3</i></p>
+
+
+<!-- Section -->
+<a name="sectlevel3id034002003"></a>
+<h3>34.2.3 Animation mit Grafikprimitiven </h3>
+
+<p>
+Alternativ zur Anzeige von Bilddateien kann jedes Einzelbild der Animation
+natürlich auch mit den Ausgabeprimitiven der Klasse <a href="index_g.html#ixb101149"><font color=#000080><tt>Graphics</tt></font></a>
+erzeugt werden. Dies hat den Vorteil, dass der Anwender nicht auf
+das Laden der Bilder warten muss. Außerdem ist das Verfahren
+flexibler als der bitmap-basierte Ansatz. Der Nachteil ist natürlich,
+dass die Grafikoperationen zeitaufwändiger sind und eine zügige
+Bildfolge bei komplexen Sequenzen schwieriger zu erzielen ist.
+
+<p>
+Als Beispiel für diese Art von Animation wollen wir uns die Aufgabe
+stellen, eine aus rechteckigen Kästchen bestehende bunte Schlange
+über den Bildschirm laufen zu lassen. Sie soll an den Bildschirmrändern
+automatisch umkehren und auch innerhalb des Ausgabefensters von Zeit
+zu Zeit ihre Richtung wechseln.
+
+<p>
+Das folgende Programm stellt die Schlange als <a href="index_v.html#ixb100120"><font color=#000080><tt>Vector</tt></font></a>
+von Objekten des Typs <font color="#000077"><tt>ColorRectangle</tt></font>
+dar. <font color="#000077"><tt>ColorRectangle</tt></font> ist aus
+<a name="ixa102344"><a href="index_r.html#ixb101745"><font color=#000080><tt>Rectangle</tt></font></a></a>
+abgeleitet und besitzt zusätzlich eine Membervariable zur Darstellung
+der Farbe des Rechtecks.
+
+<p>
+Dieses Beispiel folgt dem allgemeinen Architekturschema für Animationen,
+das wir auch in den letzten Beispielen verwendet haben. Der erste
+Schritt innerhalb von <a href="index_r.html#ixb101108"><font color=#000080><tt>run</tt></font></a>
+besteht darin, die Schlange zu konstruieren. Dazu wird eine Folge
+von Objekten der Klasse <font color="#000077"><tt>ColorRectangle</tt></font>
+konstruiert, und ab Position <font color="#000077"><tt>(100,100)</tt></font>
+werden die Objekte horizontal nebeneinander angeordnet. Die Farben
+werden dabei so vergeben, dass die Schlange in fließenden Übergängen
+von rot bis blau dargestellt wird. Alle Elemente werden in dem <a href="index_v.html#ixb100120"><font color=#000080><tt>Vector</tt></font></a>
+<font color="#000077"><tt>snake</tt></font> gespeichert.
+
+<p>
+Nachdem die Schlange konstruiert wurde, beginnt die Animation. Dazu
+wird die aktuelle Schlange angezeigt, eine Weile pausiert und dann
+durch Aufruf der Methode <font color="#000077"><tt>moveSnake</tt></font>
+die nächste Position der Schlange berechnet. <font color="#000077"><tt>moveSnake</tt></font>
+ist relativ aufwändig, denn hier liegt der Löwenanteil der
+»Intelligenz« der Animation. Die Richtung der Bewegung der
+Schlange wird durch die Variablen <font color="#000077"><tt>dx</tt></font>
+und <font color="#000077"><tt>dy</tt></font> getrennt für die
+<i>x</i>- und <i>y</i>-Richtung bestimmt. Steht hier der Wert -1,
+bewegt sich die Schlange im nächsten Schritt um die Breite eines
+Rechtecks in Richtung kleinerer Koordinaten. Bei 1 vergrößert
+sie die Koordinate entsprechend, und wenn der Wert 0 enthalten ist,
+verändert sich der zugehörige Koordinatenwert im nächsten
+Schritt gar nicht.
+
+<p>
+<font color="#000077"><tt>dx</tt></font> und <font color="#000077"><tt>dy</tt></font>
+werden entweder dann verändert, wenn die Schlange an einem der
+vier Bildschirmränder angekommen ist und umkehren muss oder (im
+Mittel bei jedem zehnten Schritt) auch auf freier Strecke. Nachdem
+auf diese Weise die neue Richtung bestimmt wurde, wird das erste Element
+der Schlange auf die neue Position bewegt. Alle anderen Elemente der
+Schlange bekommen dann die Position zugewiesen, die zuvor ihr Vorgänger
+hatte.
+
+<p>
+Eine alternative Art, die Schlange neu zu berechnen, würde darin
+bestehen, lediglich ein neues erstes Element zu generieren, an vorderster
+Stelle in den <a href="index_v.html#ixb100120"><font color=#000080><tt>Vector</tt></font></a>
+einzufügen und das letzte Element zu löschen. Dies hätte
+allerdings den Nachteil, dass die Farbinformationen von vorne nach
+hinten durchgereicht würden und so jedes Element seine Farbe
+ständig ändern würde. Dieses (sehr viel performantere)
+Verfahren könnte verwendet werden, wenn alle Elemente der Schlange
+dieselbe Farbe hätten.
+
+<p>
+Hier ist der Quellcode zu der Schlangenanimation:
+<a name="listingid034009"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* Listing3409.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.awt.*;
+<font color="#555555">004 </font><font color="#0000AA">import</font> java.awt.event.*;
+<font color="#555555">005 </font><font color="#0000AA">import</font> java.util.*;
+<font color="#555555">006 </font>
+<font color="#555555">007 </font><font color="#0000AA">class</font> ColorRectangle
+<font color="#555555">008 </font><font color="#0000AA">extends</font> Rectangle
+<font color="#555555">009 </font>{
+<font color="#555555">010 </font> <font color="#0000AA">public</font> Color color;
+<font color="#555555">011 </font>}
+<font color="#555555">012 </font>
+<font color="#555555">013 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing3409
+<font color="#555555">014 </font><font color="#0000AA">extends</font> Frame
+<font color="#555555">015 </font><font color="#0000AA">implements</font> Runnable
+<font color="#555555">016 </font>{
+<font color="#555555">017 </font> <font color="#00AA00">//Konstanten</font>
+<font color="#555555">018 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> <font color="#006699">int</font> SIZERECT = 7;
+<font color="#555555">019 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> <font color="#006699">int</font> SLEEP = 40;
+<font color="#555555">020 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> <font color="#006699">int</font> NUMELEMENTS = 20;
+<font color="#555555">021 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> Color BGCOLOR = Color.lightGray;
+<font color="#555555">022 </font>
+<font color="#555555">023 </font> <font color="#00AA00">//Instanzvariablen</font>
+<font color="#555555">024 </font> <font color="#0000AA">private</font> Thread th;
+<font color="#555555">025 </font> <font color="#0000AA">private</font> Vector snake;
+<font color="#555555">026 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> dx;
+<font color="#555555">027 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> dy;
+<font color="#555555">028 </font>
+<font color="#555555">029 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">030 </font> {
+<font color="#555555">031 </font> Listing3409 frame = <font color="#0000AA">new</font> Listing3409();
+<font color="#555555">032 </font> frame.setSize(200,150);
+<font color="#555555">033 </font> frame.setVisible(<font color="#006699">true</font>);
+<font color="#555555">034 </font> frame.startAnimation();
+<font color="#555555">035 </font> }
+<font color="#555555">036 </font>
+<font color="#555555">037 </font> <font color="#0000AA">public</font> Listing3409()
+<font color="#555555">038 </font> {
+<font color="#555555">039 </font> <font color="#006699">super</font>(<font color="#0000FF">"Animierte Schlange"</font>);
+<font color="#555555">040 </font> setBackground(BGCOLOR);
+<font color="#555555">041 </font> addWindowListener(<font color="#0000AA">new</font> WindowClosingAdapter(<font color="#006699">true</font>));
+<font color="#555555">042 </font> snake = <font color="#0000AA">new</font> Vector();
+<font color="#555555">043 </font> }
+<font color="#555555">044 </font>
+<font color="#555555">045 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> startAnimation()
+<font color="#555555">046 </font> {
+<font color="#555555">047 </font> th = <font color="#0000AA">new</font> Thread(<font color="#006699">this</font>);
+<font color="#555555">048 </font> th.start();
+<font color="#555555">049 </font> }
+<font color="#555555">050 </font>
+<font color="#555555">051 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> run()
+<font color="#555555">052 </font> {
+<font color="#555555">053 </font> <font color="#00AA00">//Schlange konstruieren</font>
+<font color="#555555">054 </font> ColorRectangle cr;
+<font color="#555555">055 </font> <font color="#006699">int</font> x = 100;
+<font color="#555555">056 </font> <font color="#006699">int</font> y = 100;
+<font color="#555555">057 </font> <font color="#0000AA">for</font> (<font color="#006699">int</font> i=0; i < NUMELEMENTS; ++i) {
+<font color="#555555">058 </font> cr = <font color="#0000AA">new</font> ColorRectangle();
+<font color="#555555">059 </font> cr.x = x;
+<font color="#555555">060 </font> cr.y = y;
+<font color="#555555">061 </font> cr.width = SIZERECT;
+<font color="#555555">062 </font> cr.height = SIZERECT;
+<font color="#555555">063 </font> x += SIZERECT;
+<font color="#555555">064 </font> cr.color = <font color="#0000AA">new</font> Color(
+<font color="#555555">065 </font> i*(256/NUMELEMENTS),
+<font color="#555555">066 </font> 0,
+<font color="#555555">067 </font> 240-i*(256/NUMELEMENTS)
+<font color="#555555">068 </font> );
+<font color="#555555">069 </font> snake.addElement(cr);
+<font color="#555555">070 </font> }
+<font color="#555555">071 </font>
+<font color="#555555">072 </font> <font color="#00AA00">//Vorzugsrichtung festlegen</font>
+<font color="#555555">073 </font> dx = -1;
+<font color="#555555">074 </font> dy = -1;
+<font color="#555555">075 </font>
+<font color="#555555">076 </font> <font color="#00AA00">//Schlange laufen lassen</font>
+<font color="#555555">077 </font> <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
+<font color="#555555">078 </font> repaint();
+<font color="#555555">079 </font> <font color="#0000AA">try</font> {
+<font color="#555555">080 </font> Thread.sleep(SLEEP);
+<font color="#555555">081 </font> } <font color="#0000AA">catch</font> (InterruptedException e){
+<font color="#555555">082 </font> <font color="#00AA00">//nichts</font>
+<font color="#555555">083 </font> }
+<font color="#555555">084 </font> moveSnake();
+<font color="#555555">085 </font> }
+<font color="#555555">086 </font> }
+<font color="#555555">087 </font>
+<font color="#555555">088 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> moveSnake()
+<font color="#555555">089 </font> {
+<font color="#555555">090 </font> Dimension size = getSize();
+<font color="#555555">091 </font> <font color="#006699">int</font> sizex = size.width-getInsets().left-getInsets().right;
+<font color="#555555">092 </font> <font color="#006699">int</font> sizey = size.height-getInsets().top-getInsets().bottom;
+<font color="#555555">093 </font> ColorRectangle cr = (ColorRectangle)snake.firstElement();
+<font color="#555555">094 </font> <font color="#006699">boolean</font> lBorder = <font color="#006699">false</font>;
+<font color="#555555">095 </font> <font color="#006699">int</font> xalt, yalt;
+<font color="#555555">096 </font> <font color="#006699">int</font> xtmp, ytmp;
+<font color="#555555">097 </font>
+<font color="#555555">098 </font> <font color="#00AA00">//Kopf der Schlange neu berechnen</font>
+<font color="#555555">099 </font> <font color="#0000AA">if</font> (cr.x <= 1) {
+<font color="#555555">100 </font> dx = 1;
+<font color="#555555">101 </font> lBorder = <font color="#006699">true</font>;
+<font color="#555555">102 </font> }
+<font color="#555555">103 </font> <font color="#0000AA">if</font> (cr.x + cr.width >= sizex) {
+<font color="#555555">104 </font> dx = -1;
+<font color="#555555">105 </font> lBorder = <font color="#006699">true</font>;
+<font color="#555555">106 </font> }
+<font color="#555555">107 </font> <font color="#0000AA">if</font> (cr.y <= 1) {
+<font color="#555555">108 </font> dy = 1;
+<font color="#555555">109 </font> lBorder = <font color="#006699">true</font>;
+<font color="#555555">110 </font> }
+<font color="#555555">111 </font> <font color="#0000AA">if</font> (cr.y + cr.height >= sizey) {
+<font color="#555555">112 </font> dy = -1;
+<font color="#555555">113 </font> lBorder = <font color="#006699">true</font>;
+<font color="#555555">114 </font> }
+<font color="#555555">115 </font> <font color="#0000AA">if</font> (! lBorder) {
+<font color="#555555">116 </font> <font color="#0000AA">if</font> (rand(10) == 0) {
+<font color="#555555">117 </font> <font color="#0000AA">if</font> (rand(2) == 0) {
+<font color="#555555">118 </font> <font color="#0000AA">switch</font> (rand(5)) {
+<font color="#555555">119 </font> <font color="#0000AA">case</font> 0: <font color="#0000AA">case</font> 1:
+<font color="#555555">120 </font> dx = -1;
+<font color="#555555">121 </font> <font color="#0000AA">break</font>;
+<font color="#555555">122 </font> <font color="#0000AA">case</font> 2:
+<font color="#555555">123 </font> dx = 0;
+<font color="#555555">124 </font> <font color="#0000AA">break</font>;
+<font color="#555555">125 </font> <font color="#0000AA">case</font> 3: <font color="#0000AA">case</font> 4:
+<font color="#555555">126 </font> dx = 1;
+<font color="#555555">127 </font> <font color="#0000AA">break</font>;
+<font color="#555555">128 </font> }
+<font color="#555555">129 </font> } <font color="#0000AA">else</font> {
+<font color="#555555">130 </font> <font color="#0000AA">switch</font> (rand(5)) {
+<font color="#555555">131 </font> <font color="#0000AA">case</font> 0: <font color="#0000AA">case</font> 1:
+<font color="#555555">132 </font> dy = -1;
+<font color="#555555">133 </font> <font color="#0000AA">break</font>;
+<font color="#555555">134 </font> <font color="#0000AA">case</font> 2:
+<font color="#555555">135 </font> dy = 0;
+<font color="#555555">136 </font> <font color="#0000AA">break</font>;
+<font color="#555555">137 </font> <font color="#0000AA">case</font> 3: <font color="#0000AA">case</font> 4:
+<font color="#555555">138 </font> dy = 1;
+<font color="#555555">139 </font> <font color="#0000AA">break</font>;
+<font color="#555555">140 </font> }
+<font color="#555555">141 </font> }
+<font color="#555555">142 </font> }
+<font color="#555555">143 </font> }
+<font color="#555555">144 </font> xalt = cr.x + SIZERECT * dx;
+<font color="#555555">145 </font> yalt = cr.y + SIZERECT * dy;
+<font color="#555555">146 </font> <font color="#00AA00">//Rest der Schlange hinterherziehen</font>
+<font color="#555555">147 </font> Enumeration e = snake.elements();
+<font color="#555555">148 </font> <font color="#0000AA">while</font> (e.hasMoreElements()) {
+<font color="#555555">149 </font> cr = (ColorRectangle)e.nextElement();
+<font color="#555555">150 </font> xtmp = cr.x;
+<font color="#555555">151 </font> ytmp = cr.y;
+<font color="#555555">152 </font> cr.x = xalt;
+<font color="#555555">153 </font> cr.y = yalt;
+<font color="#555555">154 </font> xalt = xtmp;
+<font color="#555555">155 </font> yalt = ytmp;
+<font color="#555555">156 </font> }
+<font color="#555555">157 </font> }
+<font color="#555555">158 </font>
+<font color="#555555">159 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> paint(Graphics g)
+<font color="#555555">160 </font> {
+<font color="#555555">161 </font> ColorRectangle cr;
+<font color="#555555">162 </font> Enumeration e = snake.elements();
+<font color="#555555">163 </font> <font color="#006699">int</font> inleft = getInsets().left;
+<font color="#555555">164 </font> <font color="#006699">int</font> intop = getInsets().top;
+<font color="#555555">165 </font> <font color="#0000AA">while</font> (e.hasMoreElements()) {
+<font color="#555555">166 </font> cr = (ColorRectangle)e.nextElement();
+<font color="#555555">167 </font> g.setColor(cr.color);
+<font color="#555555">168 </font> g.fillRect(cr.x+inleft,cr.y+intop,cr.width,cr.height);
+<font color="#555555">169 </font> }
+<font color="#555555">170 </font> }
+<font color="#555555">171 </font>
+<font color="#555555">172 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> rand(<font color="#006699">int</font> limit)
+<font color="#555555">173 </font> {
+<font color="#555555">174 </font> <font color="#0000AA">return</font> (<font color="#006699">int</font>)(Math.random() * limit);
+<font color="#555555">175 </font> }
+<font color="#555555">176 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/Listing3409.java"><font color="#000055" size=-1>Listing3409.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.9: Die animierte Schlange</i></p>
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Die Schlange kann in einem beliebig kleinen oder großen Fenster
+laufen. Hier sind ein paar Beispiele für die Ausgabe des Programms,
+nachdem das Fenster in der Größe verändert wurde:</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
+<tr>
+<td><font color="#FFFFFF"> Hinweis </font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+<p>
+<a name="imageid034008"></a>
+<img src="images/SchlangeAnim1.gif">
+<p>
+
+<p><i>
+Abbildung 34.8: Die animierte Schlange, Schnappschuß 1</i></p>
+<p>
+<a name="imageid034009"></a>
+<img src="images/SchlangeAnim2.gif">
+<p>
+
+<p><i>
+Abbildung 34.9: Die animierte Schlange, Schnappschuß 2</i></p>
+<p>
+<a name="imageid034010"></a>
+<img src="images/SchlangeAnim3.gif">
+<p>
+
+<p><i>
+Abbildung 34.10: Die animierte Schlange, Schnappschuß 3</i></p>
+
+
+<!-- Section -->
+<a name="flackernreduzieren"></a>
+<h3>34.2.4 Reduktion des Bildschirmflackerns<a name="ixa102345"></a>
+</h3>
+
+<p>
+Alle bisher entwickelten Animationen zeigen während der Ausführung
+ein ausgeprägtes Flackern, das um so stärker ist, je später
+ein Bildanteil innerhalb eines Animationsschrittes angezeigt wird.
+Der Grund für dieses Flackern liegt darin, dass vor jedem Aufruf
+von <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+zunächst das Fenster gelöscht wird und dadurch unmittelbar
+vor der Ausgabe des nächsten Bildes ganz kurz ein vollständig
+leerer Hintergrund erscheint.
+
+<p>
+Leider besteht die Lösung für dieses Problem nicht einfach
+darin, das Löschen zu unterdrücken. Bei einer animierten
+Bewegung beispielsweise ist es erforderlich, all die Bestandteile
+des vorigen Bildes zu löschen, die im aktuellen Bild nicht mehr
+oder an einer anderen Stelle angezeigt werden.
+
+<p>
+Auch wenn <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+deshalb aufgerufen wird, weil ein bisher verdeckter Bildausschnitt
+wieder sichtbar wird, muss natürlich der entsprechende Bildausschnitt
+zunächst gelöscht werden, um die Bestandteile des anderen
+Fensters zu entfernen. Im Grunde ist es also eine ganz vernünftige
+Vorgehensweise, das Fenster vor jedem Aufruf von <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+zu löschen.
+
+<p>
+Das Flackern kann nun auf unterschiedliche Weise unterdrückt
+werden. Die drei gebräuchlichsten Methoden sind folgende:
+<ul>
+<li>den Bildschirm gar nicht zu löschen (was - wie zuvor erwähnt
+- problematisch ist)
+<li>nur den wirklich benötigten Teil des Bildschirms zu löschen
+<li>das Verfahren der Doppelpufferung anzuwenden
+</ul>
+
+<p>
+Jedes dieser Verfahren hat Vor- und Nachteile und kann in verschiedenen
+Situationen unterschiedlich gut angewendet werden. Wir werden sie
+in den folgenden Unterabschnitten kurz vorstellen und ein Beispiel
+für ihre Anwendung geben. Es gibt noch einige zusätzliche
+Möglichkeiten, das Flackern zu unterdrücken oder einzuschränken,
+wie beispielsweise das Clipping der Ausgabe auf den tatsächlich
+veränderten Bereich, aber darauf wollen wir hier nicht näher
+eingehen.
+
+<!-- Section -->
+
+<a name="sectlevel4id034002004001"></a>
+<h4>Bildschirm nicht löschen </h4>
+
+<p>
+Den Bildschirm überhaupt nicht zu löschen, um das Flackern
+zu unterdrücken, ist nur bei nicht bewegten Animationen möglich.
+Wir wollen uns als Beispiel für ein Programm, das hierfür
+geeignet ist, das folgende Lauflicht ansehen:
+<a name="listingid034010"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* Listing3410.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.awt.*;
+<font color="#555555">004 </font><font color="#0000AA">import</font> java.awt.event.*;
+<font color="#555555">005 </font>
+<font color="#555555">006 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing3410
+<font color="#555555">007 </font><font color="#0000AA">extends</font> Frame
+<font color="#555555">008 </font><font color="#0000AA">implements</font> Runnable
+<font color="#555555">009 </font>{
+<font color="#555555">010 </font> <font color="#00AA00">//Konstanten</font>
+<font color="#555555">011 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> <font color="#006699">int</font> NUMLEDS = 20;
+<font color="#555555">012 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> <font color="#006699">int</font> SLEEP = 60;
+<font color="#555555">013 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> <font color="#006699">int</font> LEDSIZE = 10;
+<font color="#555555">014 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> Color ONCOLOR = <font color="#0000AA">new</font> Color(255,0,0);
+<font color="#555555">015 </font> <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#0000AA">final</font> Color OFFCOLOR = <font color="#0000AA">new</font> Color(100,0,0);
+<font color="#555555">016 </font>
+<font color="#555555">017 </font> <font color="#00AA00">//Instanzvariablen</font>
+<font color="#555555">018 </font> <font color="#0000AA">private</font> Thread th;
+<font color="#555555">019 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> switched;
+<font color="#555555">020 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> dx;
+<font color="#555555">021 </font>
+<font color="#555555">022 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">023 </font> {
+<font color="#555555">024 </font> Listing3410 frame = <font color="#0000AA">new</font> Listing3410();
+<font color="#555555">025 </font> frame.setSize(270,150);
+<font color="#555555">026 </font> frame.setVisible(<font color="#006699">true</font>);
+<font color="#555555">027 </font> frame.startAnimation();
+<font color="#555555">028 </font> }
+<font color="#555555">029 </font>
+<font color="#555555">030 </font> <font color="#0000AA">public</font> Listing3410()
+<font color="#555555">031 </font> {
+<font color="#555555">032 </font> <font color="#006699">super</font>(<font color="#0000FF">"Leuchtdiodenkette"</font>);
+<font color="#555555">033 </font> setBackground(Color.lightGray);
+<font color="#555555">034 </font> addWindowListener(<font color="#0000AA">new</font> WindowClosingAdapter(<font color="#006699">true</font>));
+<font color="#555555">035 </font> }
+<font color="#555555">036 </font>
+<font color="#555555">037 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> startAnimation()
+<font color="#555555">038 </font> {
+<font color="#555555">039 </font> th = <font color="#0000AA">new</font> Thread(<font color="#006699">this</font>);
+<font color="#555555">040 </font> th.start();
+<font color="#555555">041 </font> }
+<font color="#555555">042 </font>
+<font color="#555555">043 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> run()
+<font color="#555555">044 </font> {
+<font color="#555555">045 </font> switched = -1;
+<font color="#555555">046 </font> dx = 1;
+<font color="#555555">047 </font> <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
+<font color="#555555">048 </font> repaint();
+<font color="#555555">049 </font> <font color="#0000AA">try</font> {
+<font color="#555555">050 </font> Thread.sleep(SLEEP);
+<font color="#555555">051 </font> } <font color="#0000AA">catch</font> (InterruptedException e){
+<font color="#555555">052 </font> <font color="#00AA00">//nichts</font>
+<font color="#555555">053 </font> }
+<font color="#555555">054 </font> switched += dx;
+<font color="#555555">055 </font> <font color="#0000AA">if</font> (switched < 0 || switched > NUMLEDS - 1) {
+<font color="#555555">056 </font> dx = -dx;
+<font color="#555555">057 </font> switched += 2*dx;
+<font color="#555555">058 </font> }
+<font color="#555555">059 </font> }
+<font color="#555555">060 </font> }
+<font color="#555555">061 </font>
+<font color="#555555">062 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> paint(Graphics g)
+<font color="#555555">063 </font> {
+<font color="#555555">064 </font> <font color="#0000AA">for</font> (<font color="#006699">int</font> i = 0; i < NUMLEDS; ++i) {
+<font color="#555555">065 </font> g.setColor(i == switched ? ONCOLOR : OFFCOLOR);
+<font color="#555555">066 </font> g.fillOval(10+i*(LEDSIZE+2),80,LEDSIZE,LEDSIZE);
+<font color="#555555">067 </font> }
+<font color="#555555">068 </font> }
+<font color="#555555">069 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/Listing3410.java"><font color="#000055" size=-1>Listing3410.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.10: Bildschirmflackern reduzieren bei stehenden Animationen</i></p>
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Das Programm zeigt eine Kette von 20 Leuchtdioden, die nacheinander
+an- und ausgeschaltet werden und dadurch ein Lauflicht simulieren,
+das zwischen linkem und rechtem Rand hin- und herläuft:</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
+<tr>
+<td><font color="#FFFFFF"> Hinweis </font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+<p>
+<a name="imageid034011"></a>
+<img src="images/LauflichtAnim.gif">
+<p>
+
+<p><i>
+Abbildung 34.11: Die Lauflicht-Animation</i></p>
+
+<p>
+Wie kann nun aber das Löschen verhindert werden? Die Lösung
+basiert auf der Tatsache, dass bei einem Aufruf von <a href="index_r.html#ixb101509"><font color=#000080><tt>repaint</tt></font></a>
+nicht gleich <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>,
+sondern zunächst die Methode <a href="index_u.html#ixb101747"><font color=#000080><tt>update</tt></font></a>
+aufgerufen wird. In der Standardversion der Klasse <a href="index_c.html#ixb101302"><font color=#000080><tt>Component</tt></font></a>
+könnte <a name="ixa102346"><a href="index_u.html#ixb101747"><font color=#000080><tt>update</tt></font></a></a>
+etwa so implementiert sein:
+<a name="listingid034011"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#0000AA">public</font> <font color="#006699">void</font> update(Graphics g)
+<font color="#555555">002 </font>{
+<font color="#555555">003 </font> g.setColor(getBackground());
+<font color="#555555">004 </font> g.fillRect(0, 0, width, height);
+<font color="#555555">005 </font> g.setColor(getForeground());
+<font color="#555555">006 </font> paint(g);
+<font color="#555555">007 </font>}</pre>
+</font>
+</td>
+</tr>
+</table>
+<i>
+Listing 34.11: Standard-Implementierung von update</i></p>
+
+<p>
+Zunächst wird die aktuelle Hintergrundfarbe ausgewählt,
+um in dieser Farbe ein ausgefülltes Rechteck in der Größe
+des Bildschirms zu zeichnen. Erst nach diesem Löschvorgang wird
+die Vordergrundfarbe gesetzt und <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+aufgerufen.
+
+<p>
+Da in Java alle Methodenaufrufe dynamisch gebunden werden, kann das
+Löschen dadurch verhindert werden, dass <a href="index_u.html#ixb101747"><font color=#000080><tt>update</tt></font></a>
+durch eine eigene Version überlagert wird, die den Hintergrund
+unverändert läßt. Durch einfaches Hinzufügen
+der folgenden drei Zeilen kann das Flackern des Lauflichts vollkommen
+unterdrückt werden:
+<a name="listingid034012"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* update1.inc */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">public</font> <font color="#006699">void</font> update(Graphics g)
+<font color="#555555">004 </font>{
+<font color="#555555">005 </font> paint(g);
+<font color="#555555">006 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/update1.inc"><font color="#000055" size=-1>update1.inc</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.12: Modifizierte Version von update</i></p>
+
+
+<!-- Section -->
+<a name="sectlevel4id034002004002"></a>
+<h4>Nur den wirklich benötigten Teil des Bildschirms löschen
+</h4>
+
+<p>
+Wie schon erwähnt, kann auf das Löschen des Bildschirms
+nur dann komplett verzichtet werden, wenn die Animation keine Bewegung
+enthält. Ist sie dagegen bewegt, kann es sinnvoll sein, nur die
+Teile des Bildes zu löschen, die beim aktuellen Animationsschritt
+leer sind, im vorigen Schritt aber Grafikelemente enthielten.
+
+<p>
+Um welche Teile der Grafik es sich dabei handelt, ist natürlich
+von der Art der Animation abhängig. Zudem muss jeder Animationsschritt
+Informationen über den vorigen Schritt haben, um die richtigen
+Stellen löschen zu können. Ein Beispiel, bei dem diese Technik
+gut angewendet werden kann, ist die bunte Schlange aus dem Abschnitt
+»Animation mit Grafikprimitiven«.
+
+<p>
+Da die Schlange bei jedem Schritt einen neuen Kopf bekommt und alle
+anderen Elemente die Plätze ihres jeweiligen Vorgängers
+einnehmen, bleibt als einziges wirklich zu löschendes Element
+das letzte Element der Schlange aus dem vorherigen Animationsschritt
+übrig. Dessen Position könnte man sich bei jedem Schritt
+merken und im nächsten Schritt in der Hintergrundfarbe neu zeichnen.
+
+<p>
+Noch einfacher geht es, indem man an die Schlange einfach ein zusätzliches
+unsichtbares Element anhängt. Wird nämlich das letzte Element
+grundsätzlich in der Hintergrundfarbe dargestellt, hinterlässt
+es keine Spuren auf dem Bildschirm und braucht damit auch nicht explizit
+gelöscht zu werden! Wir brauchen also nur hinter die <a href="index_f.html#ixb100078"><font color=#000080><tt>for</tt></font></a>-<font color="#000077"><tt>next</tt></font>-Schleife
+zur Konstruktion der Schlange ein weiteres, unsichtbares Element an
+den <font color="#000077"><tt>snake</tt></font>-<a href="index_v.html#ixb100120"><font color=#000080><tt>Vector</tt></font></a>
+anzuhängen (in <a href="k100226.html#schlange2">Listing 34.13</a>
+in den Zeilen <a href="k100226.html#schlange2.a">025</a> bis <a href="k100226.html#schlange2.b">031</a>
+eingefügt):
+<a name="schlange2"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* Schlange2.inc */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">public</font> <font color="#006699">void</font> run()
+<font color="#555555">004 </font>{
+<font color="#555555">005 </font> <font color="#00AA00">//Schlange konstruieren</font>
+<font color="#555555">006 </font> ColorRectangle cr;
+<font color="#555555">007 </font> <font color="#006699">int</font> x = 100;
+<font color="#555555">008 </font> <font color="#006699">int</font> y = 100;
+<font color="#555555">009 </font> <font color="#0000AA">for</font> (<font color="#006699">int</font> i=0; i < NUMELEMENTS; ++i) {
+<font color="#555555">010 </font> cr = <font color="#0000AA">new</font> ColorRectangle();
+<font color="#555555">011 </font> cr.x = x;
+<font color="#555555">012 </font> cr.y = y;
+<font color="#555555">013 </font> cr.width = SIZERECT;
+<font color="#555555">014 </font> cr.height = SIZERECT;
+<font color="#555555">015 </font> x += SIZERECT;
+<font color="#555555">016 </font> cr.color = <font color="#0000AA">new</font> Color(
+<font color="#555555">017 </font> i*(256/NUMELEMENTS),
+<font color="#555555">018 </font> 0,
+<font color="#555555">019 </font> 240-i*(256/NUMELEMENTS)
+<font color="#555555">020 </font> );
+<font color="#555555">021 </font> snake.addElement(cr);
+<font color="#555555">022 </font> }
+<font color="#555555">023 </font>
+<font color="#555555">024 </font> <font color="#00AA00">//Löschelement anhängen</font>
+<font color="#555555">025 </font> cr = <font color="#0000AA">new</font> ColorRectangle(); <a name="schlange2.a"></a>
+<font color="#555555">026 </font> cr.x = x;
+<font color="#555555">027 </font> cr.y = y;
+<font color="#555555">028 </font> cr.width = SIZERECT;
+<font color="#555555">029 </font> cr.height = SIZERECT;
+<font color="#555555">030 </font> cr.color = BGCOLOR;
+<font color="#555555">031 </font> snake.addElement(cr); <a name="schlange2.b"></a>
+<font color="#555555">032 </font>
+<font color="#555555">033 </font> <font color="#00AA00">//Vorzugsrichtung festlegen</font>
+<font color="#555555">034 </font> dx = -1;
+<font color="#555555">035 </font> dy = -1;
+<font color="#555555">036 </font>
+<font color="#555555">037 </font> <font color="#00AA00">//Schlange laufen lassen</font>
+<font color="#555555">038 </font> <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
+<font color="#555555">039 </font> repaint();
+<font color="#555555">040 </font> <font color="#0000AA">try</font> {
+<font color="#555555">041 </font> Thread.sleep(SLEEP);
+<font color="#555555">042 </font> } <font color="#0000AA">catch</font> (InterruptedException e){
+<font color="#555555">043 </font> <font color="#00AA00">//nichts</font>
+<font color="#555555">044 </font> }
+<font color="#555555">045 </font> moveSnake();
+<font color="#555555">046 </font> }
+<font color="#555555">047 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/Schlange2.inc"><font color="#000055" size=-1>Schlange2.inc</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.13: Modifizierte Schlangenanimation</i></p>
+
+<p>
+Wird nun zusätzlich die Methode <a href="index_u.html#ixb101747"><font color=#000080><tt>update</tt></font></a>
+überlagert, wie es auch im vorigen Abschnitt getan wurde, läuft
+die Schlange vollkommen flackerfrei.
+
+<!-- Section -->
+
+<a name="sectlevel4id034002004003"></a>
+<h4><a name="ixa102347">Doppelpufferung</a></h4>
+
+<p>
+Das Doppelpuffern bietet sich immer dann an, wenn die beiden vorigen
+Methoden versagen. Das kann beispielsweise dann der Fall sein, wenn
+es bei einer bewegten Animation zu aufwändig ist, nur den nicht
+mehr benötigten Teil der Bildschirmausgabe zu löschen, oder
+wenn der aktuelle Animationsschritt keine Informationen darüber
+besitzt, welcher Teil zu löschen ist.
+
+<p>
+Beim Doppelpuffern wird bei jedem Animationsschritt zunächst
+die gesamte Bildschirmausgabe in ein <a name="ixa102348"><i>Offscreen-Image</i></a>
+geschrieben. Erst wenn alle Ausgabeoperationen abgeschlossen sind,
+wird dieses Offscreen-Image auf die Fensteroberfläche kopiert.
+Im Detail sind dazu folgende Schritte erforderlich:
+<ul>
+<li>Das Fensterobjekt beschaft sich durch Aufruf von <a name="ixa102349"><a href="index_c.html#ixb100644"><font color=#000080><tt>createImage</tt></font></a></a>
+ein Offscreen-Image und speichert es in einer Instanzvariablen.
+<li>Durch Aufruf von <a name="ixa102350"><a href="index_g.html#ixb101294"><font color=#000080><tt>getGraphics</tt></font></a></a>
+wird ein Grafikkontext zu diesem Image beschafft.
+<li>Alle Bildschirmausgaben (inklusive Löschen des Bildschirms)
+gehen zunächst auf den Offscreen-Grafikkontext.
+<li>Wenn alle Ausgabeoperationen abgeschlossen sind, wird das Offscreen-Image
+mit <a name="ixa102351"><a href="index_d.html#ixb101733"><font color=#000080><tt>drawImage</tt></font></a></a>
+in das Ausgabefenster kopiert.
+</ul>
+
+<p>
+Durch diese Vorgehensweise wird erreicht, dass das Bild komplett aufgebaut
+ist, bevor es angezeigt wird. Da beim anschließenden Kopieren
+die neuen Pixel direkt über die alten kopiert werden, erscheinen
+dem Betrachter nur die Teile des Bildes verändert, die auch tatsächlich
+geändert wurden. Ein Flackern, das entsteht, weil Flächen
+für einen kurzen Zeitraum gelöscht und dann wieder gefüllt
+werden, kann nicht mehr auftreten.
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#0099CC"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=1></td>
+<td width=1 align=left valign=top bgcolor="#0099CC"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Die Anwendung des Doppelpufferns ist nicht immer sinnvoll. Sollte
+eine der anderen Methoden mit vertretbarem Aufwand implementiert werden
+können, kann es sinnvoller sein, diese zu verwenden. Nachteilig
+sind vor allem der Speicherbedarf für die Konstruktion des Offscreen-Images
+und die Verzögerungen durch das doppelte Schreiben der Bilddaten.
+Hier muss im Einzelfall entschieden werden, welche Variante zum Einsatz
+kommen soll. In vielen Fällen allerdings können die genannten
+Nachteile vernachlässigt werden, und die Doppelpufferung ist
+ein probates Mittel, um das Bildschirmflackern zu verhindern.</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#0099CC">
+<tr>
+<td><font color="#FFFFFF"> Tipp </font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#0099CC"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+
+<p>
+Das folgende Programm ist ein Beispiel für die Anwendung des
+Doppelpufferns bei der Ausgabe einer bewegten Animation. Wir wollen
+uns dafür die Aufabe stellen, eine große Scheibe über
+den Bildschirm laufen zu lassen, über deren Rand zwei stilisierte
+»Ameisen« mit unterschiedlicher Geschwindigkeit in entgegengesetzte
+Richtungen laufen.
+
+<p>
+Das folgende Programm löst diese Aufgabe. Dabei folgt die Animation
+unserem bekannten Architekturschema für bewegte Grafik und braucht
+hier nicht weiter erklärt zu werden. Um das Flackern zu verhindern,
+deklarieren wir zwei Instanzvariablen, <font color="#000077"><tt>dbImage</tt></font>
+und <font color="#000077"><tt>dbGraphics</tt></font>:
+<font color="#000077">
+<pre>
+private Image dbImage;
+private Graphics dbGraphics;
+</pre>
+</font>
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Glücklicherweise können die zum Doppelpuffern erforderlichen
+Schritte gekapselt werden, wenn man die Methode <a href="index_u.html#ixb101747"><font color=#000080><tt>update</tt></font></a>
+geeignet überlagert:
+<a name="updatedoppelpuffer"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* update2.inc */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">public</font> <font color="#006699">void</font> update(Graphics g)
+<font color="#555555">004 </font>{
+<font color="#555555">005 </font> <font color="#00AA00">//Double-Buffer initialisieren</font>
+<font color="#555555">006 </font> <font color="#0000AA">if</font> (dbImage == <font color="#006699">null</font>) {
+<font color="#555555">007 </font> dbImage = createImage(
+<font color="#555555">008 </font> <font color="#006699">this</font>.getSize().width,
+<font color="#555555">009 </font> <font color="#006699">this</font>.getSize().height
+<font color="#555555">010 </font> );
+<font color="#555555">011 </font> dbGraphics = dbImage.getGraphics();
+<font color="#555555">012 </font> }
+<font color="#555555">013 </font> <font color="#00AA00">//Hintergrund löschen</font>
+<font color="#555555">014 </font> dbGraphics.setColor(getBackground());
+<font color="#555555">015 </font> dbGraphics.fillRect(
+<font color="#555555">016 </font> 0,
+<font color="#555555">017 </font> 0,
+<font color="#555555">018 </font> <font color="#006699">this</font>.getSize().width,
+<font color="#555555">019 </font> <font color="#006699">this</font>.getSize().height
+<font color="#555555">020 </font> );
+<font color="#555555">021 </font> <font color="#00AA00">//Vordergrund zeichnen</font>
+<font color="#555555">022 </font> dbGraphics.setColor(getForeground());
+<font color="#555555">023 </font> paint(dbGraphics);
+<font color="#555555">024 </font> <font color="#00AA00">//Offscreen anzeigen</font>
+<font color="#555555">025 </font> g.drawImage(dbImage,0,0,<font color="#006699">this</font>);
+<font color="#555555">026 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/update2.inc"><font color="#000055" size=-1>update2.inc</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.14: update-Methode mit Doppelpufferung</i></p>
+</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
+<tr>
+<td><font color="#FFFFFF"> Hinweis </font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+
+<p>
+Falls nicht schon geschehen, werden hier zunächst die beiden
+Variablen <font color="#000077"><tt>dbImage</tt></font> und <font color="#000077"><tt>dbGraphics</tt></font>
+initialisiert. Anschließend wird der Hintergrund gelöscht,
+wie es auch in der Standardversion von <a href="index_u.html#ixb101747"><font color=#000080><tt>update</tt></font></a>
+der Fall ist. Im Gegensatz zu dieser erfolgt das Löschen aber
+auf dem Offscreen-Image und ist somit für den Anwender nicht
+zu sehen. Nun wird <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+aufgerufen und bekommt anstelle des normalen den Offscreen-Grafikkontext
+übergeben. Ohne selbst etwas davon zu wissen, sendet <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+damit alle seine Grafikbefehle auf das Offscreen-Image. Nachdem <a href="index_p.html#ixb101148"><font color=#000080><tt>paint</tt></font></a>
+beendet wurde, wird durch Aufruf von <a href="index_d.html#ixb101733"><font color=#000080><tt>drawImage</tt></font></a>
+das Offscreen-Image auf dem Bildschirm angezeigt.
+
+<p>
+Hier ist der komplette Quellcode des Programms:
+<a name="listingid034015"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* Listing3415.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.awt.*;
+<font color="#555555">004 </font><font color="#0000AA">import</font> java.awt.event.*;
+<font color="#555555">005 </font>
+<font color="#555555">006 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing3415
+<font color="#555555">007 </font><font color="#0000AA">extends</font> Frame
+<font color="#555555">008 </font><font color="#0000AA">implements</font> Runnable
+<font color="#555555">009 </font>{
+<font color="#555555">010 </font> <font color="#0000AA">private</font> Thread th;
+<font color="#555555">011 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> actx;
+<font color="#555555">012 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> dx;
+<font color="#555555">013 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> actarc1;
+<font color="#555555">014 </font> <font color="#0000AA">private</font> <font color="#006699">int</font> actarc2;
+<font color="#555555">015 </font> <font color="#0000AA">private</font> Image dbImage;
+<font color="#555555">016 </font> <font color="#0000AA">private</font> Graphics dbGraphics;
+<font color="#555555">017 </font>
+<font color="#555555">018 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">019 </font> {
+<font color="#555555">020 </font> Listing3415 frame = <font color="#0000AA">new</font> Listing3415();
+<font color="#555555">021 </font> frame.setSize(210,170);
+<font color="#555555">022 </font> frame.setVisible(<font color="#006699">true</font>);
+<font color="#555555">023 </font> frame.startAnimation();
+<font color="#555555">024 </font> }
+<font color="#555555">025 </font>
+<font color="#555555">026 </font> <font color="#0000AA">public</font> Listing3415()
+<font color="#555555">027 </font> {
+<font color="#555555">028 </font> <font color="#006699">super</font>(<font color="#0000FF">"Ameisenanimation"</font>);
+<font color="#555555">029 </font> addWindowListener(<font color="#0000AA">new</font> WindowClosingAdapter(<font color="#006699">true</font>));
+<font color="#555555">030 </font> }
+<font color="#555555">031 </font>
+<font color="#555555">032 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> startAnimation()
+<font color="#555555">033 </font> {
+<font color="#555555">034 </font> Thread th = <font color="#0000AA">new</font> Thread(<font color="#006699">this</font>);
+<font color="#555555">035 </font> th.start();
+<font color="#555555">036 </font> }
+<font color="#555555">037 </font>
+<font color="#555555">038 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> run()
+<font color="#555555">039 </font> {
+<font color="#555555">040 </font> actx = 0;
+<font color="#555555">041 </font> dx = 1;
+<font color="#555555">042 </font> actarc1 = 0;
+<font color="#555555">043 </font> actarc2 = 0;
+<font color="#555555">044 </font> <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
+<font color="#555555">045 </font> repaint();
+<font color="#555555">046 </font> actx += dx;
+<font color="#555555">047 </font> <font color="#0000AA">if</font> (actx < 0 || actx > 100) {
+<font color="#555555">048 </font> dx = -dx;
+<font color="#555555">049 </font> actx += 2*dx;
+<font color="#555555">050 </font> }
+<font color="#555555">051 </font> actarc1 = (actarc1 + 1) % 360;
+<font color="#555555">052 </font> actarc2 = (actarc2 + 2) % 360;
+<font color="#555555">053 </font> <font color="#0000AA">try</font> {
+<font color="#555555">054 </font> Thread.sleep(40);
+<font color="#555555">055 </font> } <font color="#0000AA">catch</font> (InterruptedException e) {
+<font color="#555555">056 </font> <font color="#00AA00">//nichts</font>
+<font color="#555555">057 </font> }
+<font color="#555555">058 </font> }
+<font color="#555555">059 </font> }
+<font color="#555555">060 </font>
+<font color="#555555">061 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> update(Graphics g)
+<font color="#555555">062 </font> {
+<font color="#555555">063 </font> <font color="#00AA00">//Double-Buffer initialisieren</font>
+<font color="#555555">064 </font> <font color="#0000AA">if</font> (dbImage == <font color="#006699">null</font>) {
+<font color="#555555">065 </font> dbImage = createImage(
+<font color="#555555">066 </font> <font color="#006699">this</font>.getSize().width,
+<font color="#555555">067 </font> <font color="#006699">this</font>.getSize().height
+<font color="#555555">068 </font> );
+<font color="#555555">069 </font> dbGraphics = dbImage.getGraphics();
+<font color="#555555">070 </font> }
+<font color="#555555">071 </font> <font color="#00AA00">//Hintergrund löschen</font>
+<font color="#555555">072 </font> dbGraphics.setColor(getBackground());
+<font color="#555555">073 </font> dbGraphics.fillRect(
+<font color="#555555">074 </font> 0,
+<font color="#555555">075 </font> 0,
+<font color="#555555">076 </font> <font color="#006699">this</font>.getSize().width,
+<font color="#555555">077 </font> <font color="#006699">this</font>.getSize().height
+<font color="#555555">078 </font> );
+<font color="#555555">079 </font> <font color="#00AA00">//Vordergrund zeichnen</font>
+<font color="#555555">080 </font> dbGraphics.setColor(getForeground());
+<font color="#555555">081 </font> paint(dbGraphics);
+<font color="#555555">082 </font> <font color="#00AA00">//Offscreen anzeigen</font>
+<font color="#555555">083 </font> g.drawImage(dbImage,0,0,<font color="#006699">this</font>);
+<font color="#555555">084 </font> }
+<font color="#555555">085 </font>
+<font color="#555555">086 </font> <font color="#0000AA">public</font> <font color="#006699">void</font> paint(Graphics g)
+<font color="#555555">087 </font> {
+<font color="#555555">088 </font> <font color="#006699">int</font> xoffs = getInsets().left;
+<font color="#555555">089 </font> <font color="#006699">int</font> yoffs = getInsets().top;
+<font color="#555555">090 </font> g.setColor(Color.lightGray);
+<font color="#555555">091 </font> g.fillOval(xoffs+actx,yoffs+20,100,100);
+<font color="#555555">092 </font> g.setColor(Color.red);
+<font color="#555555">093 </font> g.drawArc(xoffs+actx,yoffs+20,100,100,actarc1,10);
+<font color="#555555">094 </font> g.drawArc(xoffs+actx-1,yoffs+19,102,102,actarc1,10);
+<font color="#555555">095 </font> g.setColor(Color.blue);
+<font color="#555555">096 </font> g.drawArc(xoffs+actx,yoffs+20,100,100,360-actarc2,10);
+<font color="#555555">097 </font> g.drawArc(xoffs+actx-1,yoffs+19,102,102,360-actarc2,10);
+<font color="#555555">098 </font> }
+<font color="#555555">099 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/Listing3415.java"><font color="#000055" size=-1>Listing3415.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 34.15: Animation mit Doppelpufferung</i></p>
+
+<p>
+Ein Schnappschuß des laufenden Programms sieht so aus (die beiden
+»Ameisen« sind in der Abbildung etwas schwer zu erkennen,
+im laufenden Programm sieht man sie besser):
+<p>
+<a name="imageid034012"></a>
+<img src="images/AmeisenAnim.gif">
+<p>
+
+<p><i>
+Abbildung 34.12: Eine Animation mit Doppelpufferung</i></p>
+
+<p>
+Durch die Kapselung des Doppelpufferns können Programme sogar
+nachträglich flackerfrei gemacht werden, ohne dass in den eigentlichen
+Ausgaberoutinen irgend etwas geändert werden müsste. Man
+könnte beispielsweise aus <a href="index_f.html#ixb101144"><font color=#000080><tt>Frame</tt></font></a>
+eine neue Klasse <font color="#000077"><tt>DoubleBufferFrame</tt></font>
+ableiten, die die beiden privaten Membervariablen <font color="#000077"><tt>dbImage</tt></font>
+und <font color="#000077"><tt>dbGraphics</tt></font> besitzt und <a href="index_u.html#ixb101747"><font color=#000080><tt>update</tt></font></a>
+in der beschriebenen Weise implementiert. Alle Klassen, die dann von
+<font color="#000077"><tt>DoubleBufferFrame</tt></font> anstelle von
+<a href="index_f.html#ixb101144"><font color=#000080><tt>Frame</tt></font></a>
+abgeleitet werden, unterstützen das Doppelpuffern ihrer Grafikausgaben
+automatisch.
+<hr>
+<table border=0 cellpadding=0 cellspacing=1 width="100%">
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html"> Titel </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html"> Inhalt </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html"> Suchen </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html"> Index </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()"> DOC </a>
+<td align="right">Handbuch der Java-Programmierung, 5. Auflage, Addison
+Wesley, Version 5.0.1
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100224.html"> << </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100225.html"> < </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100227.html"> > </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100228.html"> >> </a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()"> API </a>
+<td align="right">© 1998, 2007 Guido Krüger & Thomas
+Stark, <a href="http://www.javabuch.de">http://www.javabuch.de</a>
+</table>
+<a name="endofbody"></a>
+</body>
+</html>
|
