Textausgabe



XML und Java ... Die Java 2D API ... Next: Rendering

[nach oben]


Einführung

Die Java 2D API hat sehr ausgeprägte Fähigkeiten im Bereich der Textdarstellung. Von den vielen Möglichen Vorgehensweisen möchte ich mich hier auf zwei beschränken:

  1. Textausgabe mit Graphics2D.drawString(): restriktiv, aber unkompliziert
  2. Textausgabe mit java.text.AttributedCharacterIterator: aufwendig, aber vielfältiger

[nach oben]


Schriftarten

Um Text darstellen zu können, braucht man zunächst eine Schriftart. Schriftarten werden durch die die Klasse java.awt.Font repräsentiert. Die Font-Klasse stellt u.a. folgenden Konstruktor zur Verfügung:

Konstruktor Beschreibung
Font(String name,int style,int size) Erstellt eine neue Schriftart mit der Schriftart name. Unklar ist, was bei Mehrdeutigkeiten bezüglich des Namens der Schriftart passiert.
style ist ein Bitmaske, die durch Kombination der Bitmasken BOLD, ITALIC, PLAIN entsteht. Die Kombination erfolgt mit Hilfe des |-Operators.
size gibt die Größe der Schriftart in Punkt an.

Die Methode

liefert ein Feld mit allen auf der jeweiligen Plattform verfügbaren Schriftarten.
Bei der Konstruktion von Schriftarten wird zwischen folgenden Arten von Bezeichnern für Schriftarten unterschieden:

Codebeispiel für das instantiieren einer Schriftart:


	...
	Font myFont=new Font( "Times New Roman",Font.BOLD|Font.ITALIC,18 );
	...

[nach oben]


Abmessungen von Schriftarten

Wann man mit Schriftarten arbeitet und Text in mehreren Zeilen darstellen möchte, ist es sinnvoll, die Abmessungen des auszugebenden Strings in der jeweiligen Schriftart zu kennen, um z.B. die Zeilenhöhe ermitteln zu können. Die allgemein gebräuchlichen Bezeichnungen möchte ich hier kurz anhand eines Schaubildes vorstellen:

Diese Abmessungen können für einen beliebigen String vom Font-Objekt ermittelt werden. Hierzu verwendet man die überladene getLineMetrics-Methode aus der Font-Klasse. Sie liefert ein java.awt.LineMetrics-Objekt, dessen get...-Methoden die dargestellten Abmessungen des übergebenen Strings zurückgeben.

Das folgende Beispielprogramm erzeugt zunächst ein font-Objekt und gibt dann die Werte für leading, descent und ascent für einen bestimmten String aus (Zugriff auf die Quelle):


import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;

public class MyFontMetrics
{
	public static void main( String[] kommandozeilenargumente )
	{
		//Font erzeugen
		Font myFont=new Font("Arial", Font.ITALIC|Font.PLAIN, 26);
		
		String s="Wieso ist das Kapitel über Schriftarten nur so interessant?";
		
		// hole die Line Metrics für s
		LineMetrics lm = myFont.getLineMetrics(
					s,
					new FontRenderContext(	
						new AffineTransform(), 
						true, //antialiased
						true  //use fractional metrics?
						)
					);

		// Abmessungen für den String ausgeben:					
		System.out.println("String: "+s);
		System.out.println("Schriftart: "+myFont.getFontName());
		System.out.println("Schriftgröße: "+myFont.getSize());
		System.out.println("-------------");
		System.out.println("Ascent: "+lm.getAscent());
		System.out.println("+Descent: "+lm.getDescent());
		System.out.println("+Leading: "+lm.getLeading());
		System.out.println("=Height: "+lm.getHeight());
	}
}

[nach oben]


Textausgabe I: drawString()

Die Textausgabe mittels der überladenen Methode Graphics2D.drawString() ist die einfachste Variante. Der Nachteil hierbei ist, daß zu einzelnen Segementen eines Strings keine Formatinformationen gespeichert werden können. Des weiteren kann es bei der Animation von Text zu rundungsbedingten, unerwünschten Nebeneffekten der Animation kommen (Text bewegt sich unregelmäßig), wenn im Graphics2D-Objekt der Rendering-Hint KEY_FRACTIONALMETRICS deaktiviert ist. Für animierten Text ist drawString deshalb ungeeignet.

Folgende drawString()-Methoden existieren in Graphics2D für die Ausgabe von Strings:

Methode Beschreibung
drawString( String s, int x, int y ) zeichnet den String s in der aktuellen Schriftart bei der Position (x,y) (als linke untere Ecke des Rechtecks, daß den String einschließt) in die Zeichenfläche.
drawString(String s, float x, float y) wie vorherige Methode, aber mit float-Koordinaten

Folgende paint-Routine zeichnet einen String mit der Schriftart "Arial" in ein Graphics2D-Objekt.


public void paint(Graphics g) {
				//Upcast --> mehr Funktionen in Graphics2D
				Graphics2D g2d=(Graphics2D)g;
				
				//Font erzeugen
				Font myFont=new Font("Arial", Font.ITALIC|Font.PLAIN, 26);
		
				String s="Textausgabe mit drawString()";
				
				g2d.setFont( myFont ); //Schriftart setzen
				g2d.drawString(s,50,50); //String rendern

			}

Das Ergebnis sieht so aus:

[nach oben]


Textausgabe II: AttributedCharacterIterator

Mit drawString ist es nicht möglich, einzelnen Teilen eines Strings auch Formatierungsanweisungen hinzuzufügen. Hierzu kann man z.B. auf das Interface java.text.AttributedCharacterIterator zurückgreifen, welches vorschreibt, welche Methoden eine Klasse für einen formatierten String zu implementieren hat. Ein AttributedCharacterIterator soll es ermöglichen, iterativ einen String mit verschiedenen Formatanweisungen zu durchlaufen und für die einzelnen Segemete den jeweiligen Substring und das damit verbundene Format auszulesen. Als Formatierungsanweisungen können z.B. Farben, Schriftarten- und -stile eingesetzt werden.

Das JDK 1.3 enthält eine Klasse, die ein AttributedCharacterIterator-Objekt, das von der überladenen Methode Graphics2D.drawString akzeptiert wird, zurückgeben kann: java.text.AttributedString. Diese Klasse kapselt einen attributierten String. Die Schritte vom Erstellen einer AttributedString-Instanz bis zur Ausgabe des Strings in ein Graphics2D-Objekt sind die folgenden:

  1. Erstellen einer Instanz von AttributedString, z.B. mit folgendem Konstruktor:
  2. Konstruktor Beschreibung
    AttributedString(String text) erstellt einen neuen AttributedString für den String text.

  3. beliebigen Teilen des Strings werden Zeichenformate zugewiesen. Hierzu verwendet man die addAttribute(...)-Methoden aus AttributedString:

    Methode Beschreibung
    addAttribute(AttributedCharacterIterator.Attribute attribute, Object value) fügt dem gesamten String ein Attribut hinzu. Das Attribut stammt aus der Klasse java.awt.font.Textattribute, die Ausprägung des Attributes ist ein zu dem jew. Attribut passendes Objekt. Welche Klassen zu welchen Attributen passen, entnimmt man der Beschreibung der Klasse TextAttribute, aus der Java API Spezifikation.
    addAttribute(AttributedCharacterIterator.Attribute attribute, Object value, int beginIndex, int endIndex) wie vorherige Methode, aber das Attribut wird nur auf den durch die beiden Indizes definierten Teilstring angewandt.
    Das erste Zeichen des Strings hat den Index 0.
    Das Hinzufügen von Attributen kann beliebig oft erfolgen.

  4. Nun muß der formatierte String zum Rendern vorbereitet werden. Da Graphics2D.drawString(...) unter anderem ein AttributedCharacterIterator-Objekt entgegennehmen kann, ist es an dieser Stelle notwendig, dieses unter Verwendung der Methode AttributedCharacterIterator AttributedString.getIterator() zu ermitteln.
  5. Das ermittelte AttributedCharacterIterator-Objekt wird an drawString() übergeben und der String wird in die Zeichenfläche gerendert.
Folgende paint-Routine zeichnet einen formatierten String in ein Graphics2D-Objekt:

public void paint(Graphics g) {
				
				//Upcast --> mehr Funktionen in Graphics2D
				Graphics2D g2d=(Graphics2D)g;
				
				// Antialiasing einschalten
				g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, 
					RenderingHints.VALUE_ANTIALIAS_ON );
				
				// benötigte Fonts erzeugen
				Font f1 = new Font("Arial", Font.PLAIN, 48);
				Font f2 = new Font("Times New Roman", Font.PLAIN, 48);

				// String mit Default-Attributen erzeugen
				AttributedString as = new AttributedString("Roses are red, violets are blue");
				
				// gesamter Text in Schrift f1
				as.addAttribute( TextAttribute.FONT, f1 );
				
				// "red" in rot-weißem, zyklischen Farbverlauf
				as.addAttribute( TextAttribute.FOREGROUND, new GradientPaint( 
										0,0, 
										Color.red, 
										0,10,
										Color.white ,true ), 
						10,13);
						
				// "red" in Times New Roman
				as.addAttribute( TextAttribute.FONT, f2, 10, 13 );
				
				// "blue" in schwarz-blauem Farbverlauf
				as.addAttribute( TextAttribute.FOREGROUND, new GradientPaint( 
										0,0, 
										Color.blue, 
										10,0,
										Color.black ,true ), 
						27,31);
				
				// "blue" auch in Times New Roman
				as.addAttribute( TextAttribute.FONT, f2, 27, 31 );		
				
				// "Roses" unterstrichen mit gestrichelter Linie
				as.addAttribute( TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_DASHED, 0,5 );
				
				// "Violets invertiert"
				as.addAttribute( TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON, 15,22 );
				
				// formatierten String ausgeben
				g2d.drawString( as.getIterator(), 100,100 );				
			}

Das Ergebnis sieht so aus:

Da die Verabeitung von Text in der Java 2D API ein sehr umfangreiches Themengebiet ist, möchte ich hier aus Gründen der Komplexität nicht auf weitere Möglichkeiten eingehen. Die Klasse java.awt.font.TextLayout bietet weitere Möglichkeiten der Textdarstellung, z.B. Editierfunktionen, Cursor-Support und mehrzeiligen, formatierten Text.


XML und Java ... Die Java 2D API ... Zum Seitenanfang