12.2.1 | Fliesenleger: Transparente Applets |
Wenn ein Applet in eine HTML-Seite eingebunden wird, kann man nur eine feste Hintergrundfarbe angeben. Wird der Hintergrund für die HTML-Seite mit einem Bild ausgelegt, ist dieser Hintergrund an der Stelle des Applets ausgeschnitten, da transparente Applets derzeit noch nicht unterstützt werden.
Um das Applet trotzdem fließend in den Hintergrund der Seite integrieren zu können, muss man denselben Hintergrund für die Seite und das Applet verwenden.
Folgendes Applet ist »unsichtbar« in eine HTML-Seite eingebunden:public class TransparentAppletDemo extends Applet { Image background; // Hintergrundbild Font f; // Textfont FontMetrics fm; // FontMetrics zu obigem Font int x,y; // Textposition final String text = "How to make an applet transparent!"; public void init () { // Laden des Hintergrundbildes MediaTracker tracker = new MediaTracker(this); background = getImage( getCodeBase(),"images/background_grey.gif"); tracker.addImage(background, 0); try { tracker.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } // Erzeugen und setzen des Fonts f = new Font("SansSerif", Font.PLAIN, 30); setFont(f); } public void paint(Graphics g) { // Auslegen des Applets mit dem Bild 'background' tiling(g, background, 0, 0, getSize().width, getSize().height, 0, 0); // Zentrieren der Schrift fm = getFontMetrics(g.getFont()); x = (int)(getSize().width - fm.stringWidth(text)) / 2; y = (int)(getSize().height - fm.getHeight()) / 2 + fm.getAscent(); // Schrift ausgeben g.drawString(text, x, y); } public void tiling(Graphics g, Image background, int x, int y, int width, int height, int deltax, int deltay) { // Speichern der Bildgröße int imagewidth = background.getWidth(this); int imageheight = background.getHeight(this); // Berechnen der Position der ersten Bildkachel int aktx = -((imagewidth - deltax) % imagewidth) + x; int akty = -((imageheight - deltay) % imageheight) + y; // Setzen des neuen Zeichenbereiches g.setClip(x, y, width, height); // Kacheln des Zeichenbereiches while((akty - y) < height) { while ((aktx - x) < width) { g.drawImage(background, aktx, akty, this); aktx += imagewidth; } akty += imageheight; aktx = -((imagewidth - deltax) % imagewidth) + x; } } }Die Fläche, die das Applet auf der HTML-Seite belegt, wird fliesenartig mit einem bestimmten Hintergrundbild ausgelegt. Die Methode tiling() besitzt die Hauptfunktion. tiling() erwartet mehrere Parameter:Werden nun dieser Methode das gewünschte Hintergrundbild, das Graphics-Objekt des Applets und die Ausmaße des Applets übergeben, wird das komplette Applet mit dem Hintergrund ausgelegt:
- g
Ist das Graphics-Objekt der Komponente, die mit dem Hintergrundbild ausgelegt werden soll.- background
Ist das Bild, mit dem die Komponente ausgelegt wird.- x, y, width, height
Definieren das Rechteck innerhalb des Grafikkontexts der Komponente, das ausgelegt werden soll.- deltax, deltay
Bilden den Versatz in Pixel, um den die einzelnen Bilder verschoben werden. deltax und deltay werden relativ zu x und y angegeben.tiling(g, background, 0, 0, getSize().width, getSize().height, 0, 0);Diese Methode funktioniert allerdings nur, wenn das Muster keine signifikanten Übergänge besitzt. Ist dies nicht gegeben, muss man durch Angabe des Versatzes das Muster innerhalb des Applets an das Muster auf der Seite anpassen.
Dies muss leider von Hand geschehen, d. h., es muss so lange ausprobiert werden, bis die beiden Muster passen, da die Position des Applets innerhalb der Seite nicht abgefragt werden kann. Jede Komponente besitzt zwar die Methode getLocation(), die die Position innerhalb seiner übergeordneten Komponente als Ergebnis liefert, bei der Verwendung des Internet Explorers wird dadurch jedoch nur die absolute Position des Applets auf dem Bildschirm geliefert.
Es ist deshalb ratsam, »transparente Applets« nur als oberstes Element in eine Seite einzubinden. Befindet sich oberhalb eines Applets eine Schrift und wird deren Größe vom Benutzer des Browsers geändert, rutscht das Applet auf der Seite weiter nach unten, und somit stimmt der Versatz der Hintergrundkacheln nicht mehr. Ist der Hintergrund sehr fein gemustert, kann das Applet an jeder Stelle der Seite stehen, ohne dass der Übergang ins Auge fällt.
Eine weitere Einschränkung dieser Methode ist bei der Verwendung einiger Browser (z. B. Netscape Navigator) zu beobachten. Ist die Farbtiefe des Systems zu gering, kann es vorkommen, dass ein Browser eine andere Farbpalette für Applets als für die übrigen HTML-Elemente verwendet (z. B. Bilder, die direkt in HTML-Seiten eingebunden sind). Beim Netscape Navigator wird dies beim Start eines Applets durch eine entsprechende Meldung angezeigt. Wird nun dasselbe Bild sowohl in einem Applet als auf auf der HTML-Seite als Hintergrund verwendet, kann es vorkommen, dass die Farben der Bilder nicht übereinstimmen, weil dasselbe Bild jeweils mit einer anderen Farbpalette angezeigt wird. Abhilfe kann eine Erhöhung der Farbtiefe schaffen, die von der grafischen Oberfläche verwendet wird.
Um das Auslegen auch auf einen Teilbereich eines Graphics-Objekts beschränken zu können, wird in der Methode tiling() mit setClip() gearbeitet:g.setClip(x, y, width, height);Mit setClip() wird ein Bereich innerhalb des Grafikkontexts ausgewählt, in den gezeichnet werden darf. Zeichnet man über ihn hinaus, dann wird die Zeichnung an den Rändern des angegebenen Bereichs abgeschnitten. Per Voreinstellung ist dieser Bereich auf die gesamte Größe der Komponente gesetzt. Die Angabe der Koordinaten an die Zeichenmethoden wie z. B. drawLine(), erfolgt immer relativ zu der linken obere Ecke des Bereichs, der setClip() übergeben wurde.Das hier vorgestellte Beispiel kann mit der Texturfüllung der Java 2D-API etwas einfacher implementiert werden. Folgende Implementierung der Methode tiling() wurde mit dem Java-2D-API erstellt:
public void tiling(Graphics g, Image back, int x, int y, int width, int height, int deltax, int deltay) { // Breite und Höhe einer Kachel merken int w = back.getWidth(this)+deltax; int h = back.getHeight(this)+deltay; BufferedImage bi; // Kachel erzeugen bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D big = bi.createGraphics(); big.drawImage(back, 0, 0, this); big.dispose(); Rectangle r = new Rectangle(0, 0, w, h); Graphics2D g2 = (Graphics2D)g; // Füllung einstellen TexturePaint tp = new TexturePaint(bi, r); g2.setPaint(tp); g.setClip(x, y, width, height); // Texturfüllung anwenden g2.fillRect(0, 0, width, height); }Zunächst muss eine Kachel erzeugt werden, die das Applet ausfüllen soll. Hierzu benötigt man ein Exemplar der Klasse BufferedImage. BufferedImage stellt ein Bild dar, das im Speicher gehalten wird. Es kann als Grundlage für so genannte Offscreen-Images verwendet werden. Ein BufferedImage wird mit einer vordefinierten Höhe und Breite, sowie einer speziellen Speicherungsform der Bildpunkte initialisiert. In diesem Beispiel wird die Speicherungsform TYPE_INT_ARGB gewählt. Bei dieser Form werden Rot, Grün, Blau und der Alphawert eines Pixels in einem int-Wert gespeichert. In der Klasse BufferedImage sind noch weitere Konstanten für andere Speicherungsformen definiert.
Die Klasse BufferedImage definiert die Methode createGraphics(), die es erlaubt, einen Grafikkontext zu ermitteln. Mit diesem Grafikkontext kann dann genauso gearbeitet werden, wie mit dem Grafikkontext, der paint() als Argument übergeben wird. Durch drawImage() wird anschließend das Hintergrundbild in das BufferedImage gezeichnet. Damit wäre die Kachel erstellt. Dabei muss in diesem Fall bereits der Zwischenraum zwischen zwei Kacheln berücksichtigt werden. Deshalb wird das BufferedImage um deltax bzw. deltay größer initialisiert, als das eigentliche Hintergrundbild. Nun erfolgt das Ausfüllen des Applets mit der Textur. Hierzu wird zunächst der Grafikkontext in den Typ Graphics2D umgewandelt, damit die Funktionen des Java-2D-API zur Verfügung stehen. Danach wird ein Exemplar der Klasse TexturePaint angelegt und mit dem zuvor erstellten BufferedImage initialisiert. Das ebenfalls dem Konstruktor übergebene Exemplar von Rectangle gibt die Größe an, mit der eine Kachel am Bildschirm angezeigt wird. Im vorliegenden Beispiel hat das Rechteck dieselben Ausmaße wie das BufferedImage, d. h., es wird in Originalgröße dargestellt.
Durch Aufruf der Methode setPaint() wird nun die Texturfüllung eingestellt. Ein nachfolgender Aufruf von fillRect() nimmt die Füllung des angegebenen Rechtecks in der zuvor definierten Füllform vor. Es ist zu beachten, dass die Füllform sowohl mit setColor() (bei normalen Farben) als auch mit setPaint() (bei Texturen und Gradientenfüllungen) eingestellt werden kann. Die Füllform wirkt sich z. B. auch auf das Zeichnen von Text aus. Deshalb wird bei Verwendung des Java-2D-API in paint() vor Ausgabe der Schrift die Farbe explizit auf schwarz eingestellt:// Schrift ausgeben g.setColor(Color.black); g.drawString(text, x, y);Wenn man dies nicht tut, wird die Schrift ebenfalls mit der Textur ausgefüllt, da sie als letzte Füllform eingestellt wurde.