Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 14 Grafikprogrammierung mit dem AWT
gp 14.1 Das Abstract-Window-Toolkit
gp 14.1.1 Java Foundation Classes
gp 14.2 Fenster unter grafischen Oberflächen
gp 14.2.1 Fenster öffnen
gp 14.2.2 Größe und Position des Fensters verändern
gp 14.2.3 Fenster- und Dialog-Dekoration
gp 14.3 Das Toolkit
gp 14.3.1 Einen Hinweis beepen
gp 14.4 Grundlegendes zum Zeichnen
gp 14.4.1 Die paint()-Methode
gp 14.4.2 Auffordern zum Neuzeichnen mit repaint()
gp 14.4.3 Fensterinhalte ändern und die ereignisorientierte Programmierung
gp 14.5 Punkte, Linien und Rechtecke aller Art
gp 14.5.1 Linien
gp 14.5.2 Rechtecke
gp 14.6 Alles was rund ist
gp 14.7 Polygone und Polylines
gp 14.7.1 Die Polygon-Klasse
gp 14.7.2 N-Ecke zeichnen
gp 14.7.3 Vollschlanke Linien zeichnen
gp 14.8 Zeichenketten schreiben
gp 14.8.1 Einen neuen Zeichensatz bestimmen
gp 14.8.2 Ableiten eines neuen Fonts aus einem gegebenen Font
gp 14.8.3 Zeichensätze des Systems ermitteln
gp 14.8.4 Die Klasse FontMetrics
gp 14.8.5 True Type Fonts
gp 14.9 Clipping-Operationen
gp 14.10 Farben
gp 14.10.1 Zufällige Farbblöcke zeichnen
gp 14.10.2 Farbanteile zurückgeben
gp 14.10.3 Vordefinierte Farben
gp 14.10.4 Farben aus Hexadezimalzahlen erzeugen
gp 14.10.5 Einen helleren oder dunkleren Farbton wählen
gp 14.10.6 Farbmodelle HSB und RGB
gp 14.10.7 Die Farben des Systems
gp 14.11 Bilder anzeigen und Grafiken verwalten
gp 14.11.1 Eine Grafik zeichnen
gp 14.11.2 Grafiken zentrieren
gp 14.11.3 Laden von Bildern mit dem MediaTracker beobachten
gp 14.11.4 Kein Flackern durch Double-Buffering
gp 14.11.5 Bilder skalieren
gp 14.12 Programm-Icon setzen
gp 14.12.1 VolatileImage
gp 14.13 Grafiken speichern
gp 14.13.1 Bilder im GIF-Format speichern
gp 14.13.2 Gif speichern mit dem ACME-Paket
gp 14.13.3 JPEG-Dateien mit dem Sun-Paket schreiben
gp 14.13.4 Java Image Management Interface (JIMI)
gp 14.14 Von Produzenten, Konsumenten und Beobachtern
gp 14.14.1 Producer und Consumer für Bilder
gp 14.14.2 Beispiel für die Übermittlung von Daten
gp 14.14.3 Bilder selbst erstellen
gp 14.14.4 Die Bildinformationen wieder auslesen
gp 14.15 Filter
gp 14.15.1 Grundlegende Eigenschaft von Filtern
gp 14.15.2 Konkrete Filterklassen
gp 14.15.3 Mit CropImageFilter Teile ausschneiden
gp 14.15.4 Transparenz
gp 14.16 Alles wird bunt mit Farbmodellen
gp 14.16.1 Die abstrakte Klasse ColorModel
gp 14.16.2 Farbwerte im Pixel mit der Klasse DirectColorModel
gp 14.16.3 Die Klasse IndexColorModel
gp 14.17 Drucken
gp 14.17.1 Drucken mit dem einfachen Ansatz
gp 14.17.2 Ein PrintJob
gp 14.17.3 Drucken der Inhalte
gp 14.17.4 Komponenten drucken
gp 14.17.5 Den Drucker am Parallelport ansprechen
gp 14.18 Java 2D-API
gp 14.18.1 Grafische Objekte zeichnen
gp 14.18.2 Geometrische Objekte durch Shape gekennzeichnet
gp 14.18.3 Eigenschaften geometrischer Objekte
gp 14.18.4 Transformationen mit einem AffineTransform-Objekt
gp 14.19 Graphic Layers Framework
gp 14.20 Grafikverarbeitung ohne grafische Oberfläche
gp 14.20.1 Xvfb-Server
gp 14.20.2 Pure Java AWT Toolkit (PJA)


Galileo Computing

14.10 Farbendowntop

Der Einsatz von Farben in Java-Programmen ist Dank der Color-Klasse und der Farbräume einfach. Die Klasse stellt eine Vielzahl von Routinen zur Verfügung, mit denen Color-Objekte erzeugt und manipuliert werden können.


class java.awt.Color
implements Paint, Serializable

gp Color( float r, float g, float b )
Erzeugt ein Color-Objekt mit den Grundfarben Rot, Grün und Blau. Die Werte müssen im Bereich 0.0 bis 1.0 liegen.
gp Color( int r, int g, int b )
Erzeugt ein Color-Objekt mit den Grundfarben Rot, Grün und Blau. Die Werte müssen im Bereich 0 bis 255 liegen.
gp Color( int rgb )
Erzeugt ein Color-Objekt aus dem rgb-Wert, der die Farben Rot, Grün und Blau kodiert. Der Rotanteil befindet sich unter den Bits 16 bis 23, der Grünanteil in 8 bis 15 und der Blauanteil in 0 bis 7. Da ein Integer immer 32 Bit breit ist, ist jede Farbe durch ein Byte (8 Bit) repräsentiert.

Eine private Funktion testColorValueRange() der Color-Klasse überprüft, ob die Werte tatsächlich zwischen 0.0 und 1.0 (erster Fall) oder zwischen 0 und 255 (zweiter Fall) liegen. Wenn nicht, wird eine IllegalArgumentException ausgelöst. Im dritten Fall werden von der Ganzzahl nur die Farbinformationen aus den 24 Bit genommen. Sonstige Werte werden einfach nicht betrachtet und mit einem Alpha-Wert gleich 255 überschrieben. So zeigt es auch der Einzeiler aus dem Quelltext an:

public Color( int rgb ) {
  value = 0xff000000 | rgb;
}

abstract class java.awt.Graphics

gp abstract void setColor( Color c )
Setzt die aktuelle Farbe, die dann von den Zeichenfunktionen umgesetzt wird.
gp abstract Color getColor()
Liefert die aktuelle Farbe.
gp abstract void setXORMode( Color c )
Setzt die Pixel-Operation auf XOR. Abwechselnde Punkte werden in der aktuellen Farbe und der mit dieser Funktion gesetzten XOR-Farbe gesetzt.

Hinweis Die menschliche Farbwahrnehmung: Menschen unterscheiden Farben nach drei Eigenschaften: Farbton, Helligkeit und Sättigung. Der Mensch kann etwa zweihundert Farbtöne unterscheiden. Diese werden durch die Wellenlänge des Lichts bestimmt. Die Lichtintensität und Empfindlichkeit unserer Rezeptoren lässt uns etwa fünfhundert Helligkeitsstufen unterscheiden. Bei der Sättigung handelt es sich um eine Mischung mit weißem Licht. Hier erkennen wir etwa zwanzig Stufen. Damit kann unser visuelles System etwa zwei Millionen (200 x 500 x 20) Farbnuancen unterscheiden.


Galileo Computing

14.10.1 Zufällige Farbblöcke zeichnendowntop

Um die Möglichkeiten der Farbgestaltung einmal zu beobachten, betrachten wir die Ausgabe eines Programms, welches Rechtecke mit wahllosen Farben anzeigt.

Listing 14.12 ColorBox.java

import java.awt.*;
import java.util.*;
import javax.swing.*;
public class ColorBox extends JFrame
{
  public void paint( Graphics g )
  {
    g.setColor( Color.white );
    g.fillRect( 0, 0, getWidth(), getHeight() );
    
    Random r = new Random();
    
    for ( int y = 45; y < getHeight() - 25; y += 30 )
      for ( int x = 20; x < getWidth() - 25; x += 30 )
      {
        g.setColor( new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)) );
        g.fillRect( x, y, 25, 25);
        g.setColor( Color.black );
        g.drawRect( x-1, y-1, 25, 25 );
      }
  }
  
  public static void main( String args[] )
  {
    JFrame cb = new ColorBox();
    cb.setTitle( "Neoplastizismus" );
    cb.setSize( 300, 300 );
    cb.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    cb.show();
  }
}

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 14.4 Programmierter Neoplastizismus

Das Fenster der Applikation hat eine gewisse Größe, die wir mit size() in der Höhe und Breite abfragen. Anschließend erzeugen wir Blöcke, die mit einer zufälligen Farbe gefüllt sind. fillRect() übernimmt diese Aufgabe. Da die gefüllten Rechtecke immer in der Vordergrundfarbe gezeichnet werden, setzen wir den Zeichenstift durch die Funktion setColor(), die natürlich Objektmethode von Graphics ist. Entsprechend gibt es eine korrespondierende Funktion getColor(), die die aktuelle Vordergrundfarbe als Color-Objekt zurückgibt. Diese Funktion darf nicht mit den Funktionen getColor(String) beziehungsweise getColor(String, Color) aus der Color-Klasse verwechselt werden.


Galileo Computing

14.10.2 Farbanteile zurückgebendowntop

Mitunter müssen wir den umgekehrten Weg gehen und von einem gegebenen Color-Objekt wieder die Rot-, Grün- oder Blau-Anteile extrahieren. Dies ist einfach, und die Funktionsbibliothek bietet Entsprechendes an:


class java.awt.Color
implements Paint, Serializable

gp int getRed(), int getGreen(), int getBlue()
Liefert Rot-, Grün- und Blau-Anteile des Farb-Objekts im Bereich von 0 bis 255.
gp int getAlpha()
Gibt den Alpha-Anteil als Ganzzahl kodiert zurück.
gp int getRGB()
Gibt die RGB-Farbe als Ganzzahl kodiert zurück. Die Bits 24-31 sind für den Alpha-Wert, 16-23 für Rot, 8-15 für Grün und 0-7 für Blau.

Galileo Computing

14.10.3 Vordefinierte Farbendowntop

Wenn wir Farben benutzen wollen, dann sind schon viele Werte vordefiniert (wie im vorausgehenden Beispiel die Farbe Rot). Weitere sind: black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange, pink, white und yellow. In der Klasse jawa.awt.Color sind dazu viele Zeilen der Form

/**
 * The color white.
 */
public final static Color white = new Color(255, 255, 255);

platziert. Nachfolgend zeigt die Tabelle die Wertbelegung für die Farbtupel:


Farbname Rot Grün Blau
white 255 255 255
black 0 0 0
lightGray 192 192 192
darkGray 128 128 128
red 255 0 0
green 0 255 0
blue 0 0 255
yellow 255 255 0
purple 255 0 255

Tabelle 14.2 Farbanteile für die vordefinierten Standardfarben


Galileo Computing

14.10.4 Farben aus Hexadezimalzahlen erzeugendowntop

Um eine Farbbeschreibung im hexadezimalen Format in einzelne Farbkomponenten der Color-Klasse zu zerlegen, also zum Beispiel von FFFFFF nach (255,255,255), gibt es zwei einfache und elegante Wege. Der erste führt über die Wrapper-Klasse Integer. Die folgende Zeile erzeugt aus dem String colorHexString ein Color-Objekt:

Color color = new Color( Integer.parseInt(colorHexString, 16) );

Ein anderer Weg ist noch eleganter, da die Color-Klasse eine einfache Routine bereitstellt:

Color color = Color.decode( "#" + colorHexString );

decode(String) verlangt eine 24-Bit-Integer-Zahl als String kodiert. Durch das Hash-Symbol und das Plus erzeugen wir ein String-Objekt, welches als Hexadezimalzahl bewertet wird.


class java.awt.Color
implements Paint, Serializable

gp Color decode( String nm ) throws NumberFormatException
Liefert die Farbe vom übergebenen String. Die Zeichenkette ist als 24-Bit-Integer kodiert.

Nun wertet decode() den String aus, indem wiederum die decode()-Funktion der Integer-Klasse aufgerufen wird. Aus diesem Rückgabewert wird dann wiederum das Color-Objekt aufgebaut.

public static Color decode( String nm ) throws NumberFormatException
{
  Integer intval = Integer.decode( nm );
  int i = intval.intValue();
  return new Color( (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF );
}

Wir sehen, dass bei falschen Werten eine NumberFormatException ausgelöst wird. Diese Exception kommt von der decode()-Funktion der Integer-Klasse. Die Implementierung verrät uns die Arbeitsweise und zeigt uns auf, dass wir auch aus Oktalziffern ein Color-Objekt erzeugen könnten oder aber aus einem String, der nicht mit dem Hash-Zeichen, sondern mit dem gewohnten Präfix 0x beginnt.

public static Integer decode( String nm ) throws NumberFormatException
{
  if ( nm.startsWith("0x") ) {
    return Integer.valueOf(nm.substring(2), 16);
  }
  if ( nm.startsWith("#") ) {
    return Integer.valueOf(nm.substring(1), 16);
  }
  if ( nm.startsWith("0") && nm.length() > 1 ) {
    return Integer.valueOf( nm.substring(1), 8 );
  }
  return Integer.valueOf( nm );
}

Galileo Computing

14.10.5 Einen helleren oder dunkleren Farbton wählendowntop

Zwei besondere Funktionen sind brighter() und darker(). Sie liefern ein Farb-Objekt zurück, das jeweils eine Farbnuance heller beziehungsweise dunkler ist.


Beispiel Die Implementierung von draw3DRect() zeigt den Einsatz der Funktionen.
public void draw3DRect(int x, int y, int width, int height, boolean raised)
{
  Color c = getColor();
  Color brighter = c.brighter();
  Color darker = c.darker();
  setColor(raised ? brighter : darker);
  drawLine(x, y, x, y + height);
  drawLine(x + 1, y, x + width - 1, y);
  setColor(raised ? darker : brighter);
  drawLine(x + 1, y + height, x + width, y + height);
  drawLine(x + width, y, x + width, y + height - 1);
  setColor(c);
}

Wie viele andere Funktionen aus der Color-Klasse sind auch die Routinen sichtbar implementiert, also nicht nativ:

public Color brighter() {
    return new Color(Math.min((int)(getRed()  *(1/FACTOR)), 255),
                     Math.min((int)(getGreen()*(1/FACTOR)), 255),
                     Math.min((int)(getBlue() *(1/FACTOR)), 255));
}
public Color darker() {
    return new Color(Math.max((int)(getRed()  *FACTOR), 0),
                     Math.max((int)(getGreen()*FACTOR), 0),
                     Math.max((int)(getBlue() *FACTOR), 0));
}

FACTOR ist eine finale Konstante, die durch 0,7 vordefiniert ist. Sie lässt sich also nicht ändern.


class java.awt.Color
implements Paint, Serializable

gp Color brighter()
Gibt einen helleren Farbton zurück.
gp Color darker()
Gibt einen dunkleren Farbton zurück.

Farbveränderung mit Nullanteilen

Bei den Farbwerten müssen wir nun die Zusammensetzung aus Rot, Grün und Blau bedenken. Ein voller Wert ist mit 255 belegt. Die Berechnung kann diesen Wert noch modifizieren. Doch ist ein Eintrag mit 0 belegt, so erkennen wir aus der Berechnung, dass der Wert bei null bleiben wird. Daher sollten wir bedenken, was bei reinen Farben wie etwa Rot durch ein brighter() passiert. Ein reiner Rotton kann sich zwar in der Helligkeit ändern, aber ein Color.red.brighter() liefert immer noch Color.red.

System.out.println( Color.red.brighter() ); // java.awt.Color[r=255,g=0,b=0]
System.out.println( Color.red.darker() );   // java.awt.Color[r=178,g=0,b=0]

Es ist also nicht so, dass bei brighter() die Farben näher an Weiß herankommen und bei darker() an Schwarz.

Um also echte Helligkeitsveränderungen zu bekommen, müssen wir die Farben vorher umrechnen. Hierzu bieten sich andere Farbräume an, wie beispielsweise der HSB-Raum, in dem wir Komponenten für die Helligkeit haben. RGBtoHSB() gibt ein Feld mit den Werten für Hue, Saturation und Brightness für ein Tripel von Rot-, Grün- und Blau-Werten zurück. Nach einer Veränderung der Helligkeit können wir diesen Farbraum wieder mit HSBtoRGB() zurückkonvertieren.


Galileo Computing

14.10.6 Farbmodelle HSB und RGBdowntop

Zwei Farbmodelle sind in der Computergrafik geläufig. Das RGB-Modell, wo die Farben durch einen Rot-, Grün- und Blau-Anteil definiert werden, oder das HSB-Modell, das die Farben durch Grundton (Hue), Farbsättigung (Saturation) und Helligkeit (Brightness) definiert. Die Farbmodelle können die gleichen Farben beschreiben und umgerechnet werden.


class java.awt.Color
implements Paint, Serializable

gp static int HSBtoRGB( float hue, float saturation, float brightness )
Aus einem HSB-kodierten Farbwert wird ein RBG-Farbwert gemacht.
gp static float[] RGBtoHSB( int r, int g, int b, float hsbvals[] )
Verlangt ein Array hsbvals zur Aufnahme von HSB, in dem die Werte gespeichert werden sollen. Das Array kann null sein und wird somit angelegt. Das Feld wird zurückgegeben.
gp static Color getHSBColor( float h, float s, float b )
Die Funktion kann genutzt werden, um Color-Objekte aus einem HSB-Modell zu erzeugen.

Die Implementierung von getHSBColor() ist ein Witz:

public static Color getHSBColor(float h, float s, float b) {
  return new Color(HSBtoRGB(h, s, b));
}

Galileo Computing

14.10.7 Die Farben des Systemstoptop

Bei eigenen Java-Programmen ist es wichtig, dass diese sich so perfekt wie möglich in die Reihe der anderen Host-Programme einreihen, ohne großartig aufzufallen. Dafür muss ein Fenster die globalen Einstellungen wie den Zeichensatz und die Farben kennen. Für die Systemfarben gibt es die Klasse SystemColor, welche alle Farben einer grafischen Oberfläche auf symbolische Konstanten abbildet. Besonders praktisch ist dies bei Änderungen von Farben während der Laufzeit. Über diese Klasse können immer die aktuellen Werte eingeholt werden, denn ändert sich beispielsweise die Hintergrundfarbe der Laufleisten, so ändert sich damit auch der RGB-Wert. Die Systemfarben sind Konstanten von SystemColor und werden mit der Funktion getRGB() in eine Ganzzahl umgewandelt.

Die Klasse definiert folgende statischen finalen Variablen:


class java.awt.SystemColor
implements Serializable


SystemColor Welche Farbe anspricht
desktop Farbe des Desktop-Hintergrunds
activeCaption Hintergrundfarben für Text im Fensterrahmen
activeCaptionText Farbe für Text im Fensterrahmen
activeCaptionBorder Rahmenfarbe für Text im Fensterrahmen
inactiveCaption Hintergrundfarbe für inaktiven Text im Fensterrahmen
inactiveCaptionText Farbe für inaktiven Text im Fensterrahmen
inactiveCaptionBorder Rahmenfarbe für inaktiven Text im Fensterrahmen
window Hintergrundfarbe der Fenster
windowBorder Rahmenfarbe der Fenster
windowText Textfarbe für Fenster
menu Hintergrundfarbe für Menüs
menuText Textfarbe für Menüs
text Hintergrundfarbe für Textkomponenten
textText Textfarbe für Textkomponenten
textHighlight Hintergrundfarbe für hervorgehobenen Text
textHighlightText Farbe des Texts, wenn dieser hervorgehoben ist
textInactiveText Farbe für inaktiven Text
control Hintergrundfarbe für Kontroll-Objekte
controlText Textfarbe für Kontroll-Objekte
controlHighlight Normale Farbe, mit der Kontroll-Objekte hervorgehoben werden
controlLtHighlight Hellere Farbe, mit der Kontroll-Objekte hervorgehoben werden
controlShadow Normale Hintergrundfarbe für Kontroll-Objekte
controlDkShadow Dunklerer Schatten für Kontroll-Objekte
scrollbar Hintergrundfarbe der Schieberegler
info Hintergrundfarbe der Hilfe
infoText Textfarbe der Hilfe

Tabelle 14.3 Konstanten der Systemfarben

Um die Systemfarbe in eine brauchbare Variable zu konvertieren, gibt es die getRGB()-Funktion. So erzeugen wir mit

new Color( (SystemColor.window).getRGB() )

einfach ein Color-Objekt in der Farbe des Fensters.


final class java.awt.SystemColor
implements Serializable

gp int getRGB()
Liefert den RGB-Wert der Systemfarbe als Ganzzahl kodiert.

Um zu sehen, welche Farben auf dem laufenden System aktiv sind, formulieren wir ein Programm, das eine kleine Textzeile in der jeweiligen Farbe angibt. Da wir auf die internen Daten nicht zugreifen können, müssen wir ein Farbfeld mit SystemColor-Objekten aufbauen.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 14.5 Die Systemfarben unter einer Windows-Konfiguration

Listing 14.13 SystemColors.java

import java.awt.*;
import java.awt.event.*;
class SystemColors extends Frame
{
  private String systemColorString[] = {
    "desktop","activeCaption","activeCaptionText",
    "activeCaptionBorder", "inactiveCaption",
    "inactiveCaptionText", "inactiveCaptionBorder",
    "window", "windowText", "menu", "menuText",
    "text", "textText", "textHighlight",
    "textHighlightText","textInactiveText",
    "control", "controlText", "controlHighlight",
    "controlLtHighlight", "controlShadow",
    "controlDkShadow", "scrollbar",
    "info","infoText"
  };
  private SystemColor systemColor[] = {
    SystemColor.desktop,
    SystemColor.activeCaption,
    SystemColor.activeCaptionText,
    SystemColor.activeCaptionBorder,
    SystemColor.inactiveCaption,
    SystemColor.inactiveCaptionText,
    SystemColor.inactiveCaptionBorder,
    SystemColor.window,
    SystemColor.windowText,
    SystemColor.menu,
    SystemColor.menuText,
    SystemColor.text,
    SystemColor.textText,
    SystemColor.textHighlight,
    SystemColor.textHighlightText,
    SystemColor.textInactiveText,
    SystemColor.control,
    SystemColor.controlText,
    SystemColor.controlHighlight,
    SystemColor.controlLtHighlight,
    SystemColor.controlShadow,
    SystemColor.controlDkShadow,
    SystemColor.scrollbar,
    SystemColor.info,
    SystemColor.infoText
  };
  public SystemColors() {
    setSize( 200, 400 );
    addWindowListener(new WindowAdapter() {
      public void windowClosing( WindowEvent e ) {
        System.exit(0);
      }
    });
  }
  public void paint( Graphics g )
  {
    g.setFont( new Font( "Dialog", Font.BOLD, 12 ) );
    for ( int i=0; i < systemColorString.length; i++ ) {
      g.setColor( new Color( systemColor[i].getRGB() ) );
      g.drawString( systemColorString[i], 20, 40+(i*13) );
    }
  }
  public static void main( String args[] ) {
    SystemColors c = new SystemColors();
    c.show();
  }
}




Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de