Grafikprogrammierung in Java: Grundlagen 11.1 11.2 11.3 11.4 11.5 11.6 Grundlagen Grafische Grundelemente Fensterklassen Ereignisse und Widgets Applets Die Swing-Klassen 11.1 Grundlagen 11-1 Schnittstellen für Anwenderprogramme • Eine Schnittstelle für Anwenderprogramme (application programming interface, API) stellt wohldefinierte und standardisierte Klassen und Methoden zur Verfügung, die von Anwenderprogrammen genutzt werden können. • APIs ermöglichen es, vorhandene Software um weitere Funktionen zu ergänzen. Einige APIs kennen wir ja bereits. • Java stellt beispielsweise APIs für die folgenden Zwecke zur Verfügung: ◦ Grafikprogrammierung (mit AWT, Swing) ◦ Datenbankzugriffe (mit JDBC) ◦ Netzwerkprogrammierung ◦ Verarbeitung, Auswertung und Transformation von XML-Dokumenten ◦ Verschlüsselung von Daten (Sicherheit, Kryptografie, SecurityManager) ◦ Sound ◦ ... 11.1 Grundlagen 11-2 Grafikprogrammierung Java bietet den Programmierern zwei Bibliotheken zur Programmierung von grafischen Benutzeroberflächen (graphical user interface, GUI) an: • Abstract Window Toolkit (AWT) Das AWT ermöglicht die Ausführung grundlegender grafischer Operationen. Die Klassen und Methoden des AWTs sind im Standardpaket java.awt enthalten. • Swing Seit der Version 1.1 gibt es eine zweite Grafikbibliothek im Java Development Kit. Sie heißt Swing und ist Bestandteil des Erweiterungspakets javax.swing. Diese Bibliothek beseitigt etliche Schwächen des AWTs und bietet eine weitgehend plattformunabhängige Schnittstelle. Die Möglichkeiten, die Swing bietet, übersteigen die des AWTs. 11.1 Grundlagen 11-3 Grafikprogrammierung Neben AWT und Swing gibt es eine verbreitete Bibliothek zur Programmierung grafischer Benutzeroberflächen: • Standard Widget Toolkit (SWT) SWT ist eine Bibliothek für die Erstellung grafischer Oberflächen mit Java. Sie wurde im Jahr 2001 von IBM für die Entwicklungsumgebung Eclipse entwickelt und kommt in einer ganzen Reihe von Anwendungen zum Einsatz, beispielsweise Eclipse selbst. SWT leidet auf einigen Nicht-Windows-Plattformen unter Effizienzproblemen. SWT gehört nicht zum JDK. Wir gehen hier (aus Zeitgründen) nicht auf SWT ein. Es gibt weitere Bibliotheken. 11.1 Grundlagen 11-4 Das Abstract Window Toolkit Die Fähigkeiten des AWTs lassen sich in vier Gruppen einteilen: • Grundoperationen zum Zeichnen von Linien und Flächen und zur Ausgabe von Text • Methoden zur Programmsteuerung durch die Behandlung von Maus-, Tastaturund Fensterereignissen • Dialogelemente zur Kommunikation mit dem Anwender • Fortgeschrittene Operationen zur Ausgabe von Bitmaps und Tönen 11.1 Grundlagen 11-5 Ein einführendes Beispiel import java.awt.*; public class Fenster extends Frame { Fenster() { setBackground(Color.yellow); setSize(200,150); setLocation(500,500); setVisible(true); } public static void main(String[] args) { new Fenster(); } } 11.1 Grundlagen 11-6 Das Abstract Window Toolkit • Zum Ableiten einer eigenen Fensterklasse wird in der Regel entweder die Klasse Frame oder die Klasse Dialog verwendet. • Um ein neues Fenster zu erhalten, muss ein Objekt der Klasse Frame erzeugt, auf die gewünschte Größe gebracht und durch Aufruf der Methode setVisible sichtbar gemacht werden. • Die Ausgabe in ein Fenster erfolgt durch Überlagern der Methode paint. Diese Methode wird immer dann aufgerufen, wenn das Fenster neu gezeichnet werden muss, z. B. beim Programmstart oder beim Verändern der Größe. • Die Methode void paint(Graphics g) erhält als Parameter einen grafischen Kontext. Hierunter versteht man allgemeine Einstellungen für Schrift und Grafik, beispielsweise den aktuellen Font und die aktuelle Farbe. 11.1 Grundlagen 11-7 Ein einführendes Beispiel import java.awt.*; class Rechteck extends Canvas { public void paint(Graphics g) { g.setColor(Color.red); g.fillRect(20,20,100,40); g.setColor(Color.black); g.drawString("Ein rotes Rechteck",20,80); setLocation(20,15); } } // Vokabeltest: canvas = Leinwand 11.1 Grundlagen 11-8 class EinfachesFenster extends Frame { EinfachesFenster() { add(new Rechteck()); setBackground(Color.yellow); setSize(200,150); setVisible(true); setLocation(200,200); } public static void main(String[] args) { new EinfachesFenster(); } } 11.1 Grundlagen 11-9 Ereignisgesteuerte Programmierung • Die Programme, die wir bisher betrachtet haben, arbeiten nach dem Prinzip der Ein-Ausgabe-Programmierung. • Dieses Modell wird jetzt zur ereignisgesteuerten Programmierung erweitert. Ereignisse sind beispielsweise das Drücken einer Taste, die Betätigung des Rollbalkens oder die Bewegung der Maus. • Es gibt viele Varianten der ereignisgesteuerten Programmierung. In Java wird das sogenannte Delegation Based Event Handling verwendet. Es bietet die Möglichkeit, GUI-Ereignisse an beliebige Objekte weiterzuleiten und dort zu behandeln. Auf diese Weise können die Oberfläche und die eigentliche Anwendung klar voneinander getrennt werden. 11.1 Grundlagen 11-10 Ereignisgesteuerte Programmierung • Jedes Ereignis besitzt eine Quelle (Source). Ein Ereignis kann von Beobachtern (Listener) wahrgenommen werden. Die Anmeldung von Beobachtern zur Benachrichtigung vom Eintreten eines Ereignisses ist frei programmierbar und muss immer explizit erfolgen. • Es ist nicht festgelegt, in welcher Reihenfolge die Beobachter vom Eintreten eines Ereignisses informiert werden. Sichergestellt ist lediglich, dass jeder Beobachter eine Kopie des ursprünglichen Ereignisses erhält. • Bei der Verbreitung von Ereignissen ist zwischen den Modi single-cast und multi-cast zu unterscheiden. Für Single-Cast-Ereignisse wird der Beobachter mit einer setxxListener-Methode gesetzt, für Multi-Cast-Ereignisse wird ein Beobachter mit einer addxxListener-Methode der Menge der Beobachter hinzugefügt. 11.1 Grundlagen 11-11 Beispiel: Schließen eines Fensters • Um ein Fenster zu schließen, muss ein WindowListener registriert werden. • Hierbei handelt es sich um einen Beobachter, dessen Methode windowClosing aufgerufen wird, wenn der Anwender das Fenster über ein System-Menü oder einen Button schließen möchte. • Das Fenster wird durch setVisible(false) unsichtbar gemacht, seine Ressourcen durch dispose() wieder freigegeben. 11.1 Grundlagen 11-12 Beispiel: Schließen eines Fensters import java.awt.*; import java.awt.event.*; public class WindowClosingAdapter extends WindowAdapter { public void windowClosing(WindowEvent event) { event.getWindow().setVisible(false); event.getWindow().dispose(); System.out.println("Das Fenster wurde geschlossen!"); } } Frame wnd = new Frame(); wnd.addWindowListener(new WindowClosingAdapter()); wnd.setSize(400,300); wnd.setVisible(true); 11.1 Grundlagen 11-13 Adapter-Klassen • Eine Adapter-Klasse ist eine Klasse, die eine gegebene Schnittstelle implementiert, indem sie jede abstrakte Methode durch einen leeren Rumpf realisiert. • Adapter-Klassen werden verwendet, wenn von einer Schnittstelle lediglich ein Teil der Methoden benötigt wird, der Rest aber uninteressant ist. In diesem Fall leitet man eine neue Klasse aus der Adapter-Klasse ab und überlagert nur die erforderlichen Methoden. • Beispiel: Die Klasse WindowAdapter implementiert die Schnittstellen WindowListener, WindowStateListener und WindowFocusListener durch leere Rümpfe. Hierbei handelt es sich um die folgenden Methoden: 11.1 Grundlagen 11-14 Die Klasse WindowAdapter void void void void void void void void void void windowActivated(WindowEvent e) windowClosed(WindowEvent e) windowClosing(WindowEvent e) windowDeactivated(WindowEvent e) windowDeiconified(WindowEvent e) windowGainedFocus(WindowEvent e) windowIconified(WindowEvent e) windowLostFocus(WindowEvent e) windowOpened(WindowEvent e) windowStateChanged(WindowEvent e) 11.1 Grundlagen 11-15 Ein einführendes Beispiel Wir fassen zusammen: import java.awt.*; import java.awt.event.*; class WindowClosingAdapter extends WindowAdapter { public void windowClosing(WindowEvent event) { event.getWindow().setVisible(false); event.getWindow().dispose(); System.out.println("Das Fenster wurde geschlossen!"); } } 11.1 Grundlagen 11-16 class Rechteck extends Canvas { public void paint(Graphics g) { g.setColor(Color.red); g.fillRect(20,20,100,40); g.setColor(Color.black); g.drawString("Ein rotes Rechteck",20,80); setLocation(20,15); } } 11.1 Grundlagen 11-17 public class EinfachesFenster extends Frame { EinfachesFenster(String title) { super(title); addWindowListener(new WindowClosingAdapter()); setBackground(Color.yellow); setSize(400,200); add(new Rechteck()); setVisible(true); } } 11.1 Grundlagen 11-18 EinfachesFenster e1 = new EinfachesFenster("Erstes Fenster"), e2 = new EinfachesFenster("Zweites Fenster"), e3 = new EinfachesFenster("Drittes Fenster"); e1.setLocation(200,200); e2.setLocation(400,300); e3.setLocation(600,400); 11.1 Grundlagen 11-19 Grafikprogrammierung in Java: Grafische Grundelemente 11.1 11.2 11.3 11.4 11.5 11.6 Grundlagen Grafische Grundelemente Fensterklassen Ereignisse und Widgets Applets Die Swing-Klassen 11.2 Grafische Grundelemente 11-20 Das grafische Koordinatensystem • Die Ausgabe von grafischen Objekten basiert auf einem zweidimensionalen Koordinatensystem, dessen Ursprung (0,0) in der linken oberen Ecke liegt. x ? y • Positive x-Werte erstrecken sich nach rechts, positive y-Werte nach unten. Die Maßeinheit entspricht einem Bildschirmpixel und ist somit geräteabhängig. 11.2 Grafische Grundelemente 11-21 Der Benutzerbereich • Es steht nicht das gesamte Fenster für Ausgaben zur Verfügung. Oben, unten, links und rechts wird Platz zur Ausgabe von Rahmen und Titelzeile benötigt. • Mit ◦ getSize().width und getSize().height kann die Gesamtbreite bzw. -höhe eines Fensters ermittelt werden. Durch ◦ getInsets().left, getInsets().right, getInsets().top und getInsets().bottom lässt sich die Abmessung des Rahmens und durch Differenzbildung die des Benutzerbereichs (client area) bestimmen. 11.2 Grafische Grundelemente 11-22 Elementare Grafikroutinen (Auswahl) • void drawString(String s, int x, int y) drawString schreibt den String s an die Position (x,y). Diese Koordinaten stellen das linke Ende der Basislinie von s dar. • void drawChars(char[] c, int offset, int length, int x, int y) Diese Methode schreibt ein Zeichenfeld. Die Parameter offset und length können zur Angabe des ersten Zeichens und der Anzahl der auszugebenden Zeichen verwendet werden. 11.2 Grafische Grundelemente 11-23 Elementare Grafikroutinen (Auswahl) Beispiel: Die Anweisungen char[] c = {’a’,’b’,’c’,’d’,’e’,’f’}; g.drawString("Zeichenkette",50,50); g.drawChars(c,1,4,50,150); schreiben den String "Zeichenkette" an die Position (50,50) und darunter die Zeichen "bcde" an die Position (50,150). 11.2 Grafische Grundelemente 11-24 Elementare Grafikroutinen (Auswahl) • void drawLine(int x1, int y1, int x2, int y2) Diese Methode zieht eine Linie von der Position (x1,y1) zur Position (x2,y2). • void drawRect(int x, int y, int width, int height) drawRect zeichnet ein Rechteck der Breite width und der Höhe height, dessen linke obere Ecke an der Position (x,y) liegt. • void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) Es wird ein Rechteck mit abgerundeten Ecken gezeichnet. arcWidth und arcHeight bestimmen die Halbachsen der Ellipse, die zur Darstellung der Ecken verwendet wird. 11.2 Grafische Grundelemente 11-25 Elementare Grafikroutinen (Auswahl) • void drawPolygon(int[] x, int[] y, int anzahl) Diese Methode zeichnet einen Linienzug. Die x-Koordinaten der Punkte werden dem ersten Parameter, die y-Koordinaten dem zweiten Parameter entnommen. Die Anzahl der Koordinatenpaare wird durch den dritten Parameter festgelegt. Der Polygonzug wird geschlossen. Durch drawPolyline kann ein nichtgeschlossener Linienzug dargestellt werden. Eine andere Möglichkeit, ein Polygon zu erzeugen, besteht darin, einen Konstruktor der Klasse Polygon aufzurufen: • Polygon(int[] x, int[] y, int anzahl) Polygon() Durch addPoint kann ein Polygon erweitert werden. 11.2 Grafische Grundelemente 11-26 Elementare Grafikroutinen (Auswahl) • void drawOval(int x, int y, int width, int height) Mit dieser Methode können Kreise und Ellipsen gezeichnet werden. Die Parameter spezifizieren ein Rechteck wie in der Methode drawRect. Es wird die größte Ellipse gezeichnet, die in dieses Rechteck hineinpasst. • void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) Mit drawArc kann ein Kreisbogen dargestellt werden. Die ersten vier Parameter geben den Kreis, startAngle den Anfangswinkel und arcAngle den Winkel an. 11.2 Grafische Grundelemente 11-27 Elementare Grafikroutinen (Auswahl) Die folgenden Funktionen stellen die gleichen geometrischen Objekte dar wie die obigen, zeichnen aber nicht nur deren Umrisse, sondern füllen auch ihre Fläche aus. • void fillRect( ... ) • void fillRoundRect( ... ) • void fillPolygon( ... ) • void fillOval( ... ) • void fillArc( ... ) 11.2 Grafische Grundelemente 11-28 Elementare Grafikroutinen (Auswahl) • void clearRect(int x, int y, int width, int height) Die Methode clearRect überschreibt das angegebene Rechteck mit der aktuellen Hintergrundfarbe. • void copyArea(int x, int y, int width, int height, int dx, int dy) copyArea kopiert das ausgewählte Rechteck an die Position (x + dx, y + dy). • Mit einer Clipping-Region kann die Ausgabe auf einen bestimmten Bereich eingeschränkt werden. 11.2 Grafische Grundelemente 11-29 Schriftarten • Ohne zusätzliche Anweisungen wird Text in einem systemabhängigen Standard-Font ausgegeben. Um einen anderen Font zur Textausgabe zu verwenden, muss zuerst ein Font-Objekt erzeugt und dann in den Grafik-Kontext eingetragen werden. • Ein Font-Objekt kann mit einem Konstruktor der Klasse Font erzeugt werden: Font(String name, int style, int size) • Mit void setFont(Font font) und Font getFont() kann der Font gesetzt bzw. abgefragt werden. 11.2 Grafische Grundelemente 11-30 Schriftarten • Der Parameter name gibt den Namen der gewünschten Schrift an. Font-Namen sind beispielsweise Times New Roman, Helvetica oder Courier. • Schriften können Serifen besitzen oder auch serifenlos sein. • Ein weiteres Kennzeichen einer Schrift ist die Zeichenbreite. Diese kann variabel oder konstant sein. Bei konstanter Zeichenbreite bezeichnet man eine Schrift als monospaced. • Beispiel: Der Font, in dem diese Folien geschrieben wurden, ist die serifenlose Variante der „Latin Computer Modern“. • Es können auch die Font-Namen Serif, SansSerif und Monospaced verwendet werden. Sie werden auf entsprechende Fonts abgebildet. 11.2 Grafische Grundelemente 11-31 Schriftarten • Der Parameter size gibt die Schriftgröße an. Übliche Schriftgrößen für Text liegen zwischen 10 pt und 12 pt. • Die Schriftart wird durch den Parameter style beschrieben: Name Font.PLAIN Font.BOLD Font.ITALIC 11.2 Grafische Grundelemente Wert 0 1 2 3 Bedeutung Standard-Font Fettdruck Kursivdruck fetter Kursivdruck 11-32 Schriftarten Beispiel: Die folgenden Anweisungen bewirken, dass der String "Zeichenkette" in einer Schrift mit konstanter Zeichenbreite in fettem Kursivdruck in 12-Punkt-Schrift an die Position (50,350) geschrieben wird: Font f = new Font("Monospaced",3,12); g.setFont(f); g.drawString("Zeichenkette",50,350); 11.2 Grafische Grundelemente 11-33 Schriftarten Das folgende Beispiel gibt die drei Standardschriften in 36 Punkt aus: public void paint(Graphics g) { Font font; String[] arfonts = {"Serif","SansSerif","Monospaced"}; for (int i = 0; i < arfonts.length; ++i) { font = new Font(arfonts[i],Font.PLAIN,36); g.setFont(font); g.drawString(arfonts[i],10,30 + (i + 1) * (36 + 5)); } } 11.2 Grafische Grundelemente 11-34 Schriftarten • Die Klasse Font besitzt Methoden, um Informationen über den aktuellen Font zu gewinnen: ◦ String getFamily() ◦ int getStyle() ◦ int getSize() • Die Klasse FontMetrics stellt Methoden zur Verfügung, mit denen die Größenmaßzahlen einzelner Zeichen – wie Oberlänge, Unterlänge oder Breite –, Größen wie der Zeilenabstand oder die Länge eines Strings ermittelt werden können. ◦ int charWidth(char ch) ◦ int stringWidth(String str) 11.2 Grafische Grundelemente 11-35 Farbmodell Eine Möglichkeit, in Java Farben zu benutzen, basiert auf dem RGB-Farbmodell (Rot-Grün-Blau-Farbmodell). Jede dieser drei Grundfarben wird durch 8 Bits dargestellt. Der Anteil einer Grundfarbe kann also durch eine Dezimalzahl zwischen 0 und 255 beschrieben werden. Für die gesamte Farbtiefe ergeben sich somit 24 Bits. Farbe Weiß Grau Schwarz Rot Grün Blau Gelb Magenta Cyan Rot 255 127 0 255 0 0 255 255 0 Grün 255 127 0 0 255 0 255 0 255 Blau 255 127 0 0 0 255 0 255 255 Java unterstützt weitere Farbmodelle, in denen Farben z. B. durch Farbton, Intensität und Helligkeit dargestellt werden. 11.2 Grafische Grundelemente 11-36 Erzeugung von Farben • Farben werden durch die Klasse Color dargestellt. Jedes Objekt repräsentiert eine Farbe, die durch ihren RGB-Wert eindeutig gekennzeichnet ist. • Konstruktoren: ◦ Color(int r, int g, int b) ◦ Color(float r, float g, float b) Der erste Konstruktor erwartet ganzzahlige Werte im Bereich von 0 bis 255, der zweite Fließkommazahlen zwischen 0.0 und 1.0. Der Wert 0.0 entspricht der ganzzahligen 0, der Wert 1.0 der ganzzahligen 255. 11.2 Grafische Grundelemente 11-37 Erzeugung von Farben • Die Klasse Color stellt etliche Farben als statische Objekte zur Verfügung: ◦ ◦ ◦ ◦ ◦ static static static static ... Color Color Color Color black red green blue • Von einem bestehenden Farbobjekt kann der RGB-Wert mit den Methoden ◦ int getRed(), ◦ int getGreen() und ◦ int getBlue() ermittelt werden. 11.2 Grafische Grundelemente 11-38 Verwendung von Farben • Um Farben bei der Ausgabe von Schrift oder Grafik zu verwenden, muss ein Objekt der Klasse Color erzeugt und mithilfe der Methode void setColor(Color c) dem grafischen Kontext zugewiesen werden. • Die Ausgabe erfolgt solange in der neuen Farbe, bis dem Kontext eine neue Farbe zugeordnet wird. • Mit Color getColor() wird die aktuelle Farbe abgefragt. 11.2 Grafische Grundelemente 11-39 Verwendung von Farben Beispiel: public void paint(Graphics g) { g.setColor(Color.red); g.drawString("Zeichenkette",200,500); g.setColor(new Color(200,200,0)); g.drawOval(50,400,60,160); ... } 11.2 Grafische Grundelemente 11-40 Die Klasse SystemColor • Die Klasse SystemColor stellt eine Reihe von Farben zur Verfügung, die den Farben des Desktops entsprechen. Damit können Anwendungen entwickelt werden, die im Aussehen an die Betriebssystemumgebung angepasst sind. • Beispiele: ◦ SystemColor.desktop Hintergrundfarbe des Desktops ◦ SystemColor.window Hintergrundfarbe für Fenster ◦ SystemColor.text Hintergrundfarbe für Text 11.2 Grafische Grundelemente 11-41 Grafikprogrammierung in Java: Fensterklassen 11.1 11.2 11.3 11.4 11.5 11.6 Grundlagen Grafische Grundelemente Fensterklassen Ereignisse und Widgets Applets Die Swing-Klassen 11.3 Fensterklassen 11-42 Fensterklassen Das AWT enthält eine Reihe von Fensterklassen, die über eine Vererbungslinie miteinander verbunden sind. An der Spitze steht die Klasse Component: • Component ◦ Container ∗ Panel - Applet ∗ Window - Frame - Dialog · FileDialog 11.3 Fensterklassen ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ Button Canvas Checkbox Choice Label List Scrollbar Textcomponent 11-43 Fensterklassen • Component ist eine abstrakte Klasse, deren Objekte Programmelemente darstellen, die eine Größe und eine Position besitzen und die Ereignisse senden und auf Ereignisse reagieren können. • Container ist eine konkrete Klasse. Sie erlaubt es, innerhalb einer Komponente weitere Komponenten aufzunehmen. Container stellt Methoden, um Komponenten hinzuzufügen oder zu entfernen, bereit. Mit den LayoutManager-Klassen werden die Komponenten positioniert. • LayoutManager, LayoutManager2 sind Interfaces. Implementierende Klassen sind beispielsweise BorderLayout, FlowLayout, GridLayout, . . . 11.3 Fensterklassen 11-44 Fensterklassen • Panel ist die einfachste konkrete Klasse mit den Eigenschaften von Component und Container. • Applet ist eine direkte Unterklasse von Panel. Ein Applet besitzt also die Fähigkeiten der Klassen Component und Container. Diese Klasse spielt eine entscheidende Rolle in der Entwicklung von Applets. • Die Klasse Window abstrahiert ein Top-Level-Window ohne Rahmen, Titelleiste und Menü. Sie ist für Anwendungen geeignet, die die Kontrolle über das gesamte Fenster benötigen. • Frame repräsentiert ein Top-Level-Window mit Rahmen, Titelleiste und optionalem Menü. Einem Frame kann ein Icon zugeordnet werden, das angezeigt wird, wenn ein Fenster minimiert wird. 11.3 Fensterklassen 11-45 Aufrufen und Schließen eines Fensters • Um ein Fenster auf dem Bildschirm anzuzeigen, muss zunächst eine geeignete Fensterklasse instanziiert werden. Dafür kommen Klassen wie Window, Frame, Dialog, Applet und FileDialog in Frage. Die Klassen haben unterschiedliche Konstruktoren. • Nach der Instanziierung wird die Methode setVisible(boolean visible) aufgerufen, um das Fenster anzuzeigen. Wird true übergeben, wird das Fenster angezeigt, andernfalls geschlossen. • Um ein Fenster zu schließen, sind die Methoden setVisible(false) und dispose() aufzurufen. 11.3 Fensterklassen 11-46 Eigenschaften eines Fensters • Größe und Position, geerbt von Component • Aktivierungskomponente, geerbt von Component • Fensterelemente ◦ Titelleiste, Menü, Icon, Mauscursor, Standardfont, Vorder- und Hintergrundfarbe • Die Eigenschaften eines Fensters können mithilfe spezieller Methoden gesetzt und abgefragt werden. • Beispiel: Objekte der Klasse Frame besitzen einen Rahmen, eine Titelleiste und optional ein Menü, Objekte der Klasse Window hingegen nicht. 11.3 Fensterklassen 11-47 Grafikprogrammierung in Java: Ereignisse und Widgets 11.1 11.2 11.3 11.4 11.5 11.6 Grundlagen Grafische Grundelemente Fensterklassen Ereignisse und Widgets Applets Die Swing-Klassen 11.4 Ereignisse und Widgets 11-48 Ereignisgesteuerte Programmierung • Ereignisse sind beispielsweise das Drücken einer Taste, die Betätigung des Rollbalkens oder die Bewegung der Maus. • Jedes Ereignis besitzt eine Quelle (Source). • Ein Ereignis kann von Beobachtern (Listener) wahrgenommen werden. Die Anmeldung von Beobachtern zur Benachrichtigung vom Eintreten eines Ereignisses ist frei programmierbar und muss immer explizit erfolgen. • Es ist nicht festgelegt, in welcher Reihenfolge die Beobachter vom Eintreten eines Ereignisses informiert werden. Sichergestellt ist lediglich, dass jeder Beobachter eine Kopie des ursprünglichen Ereignisses erhält. 11.4 Ereignisse und Widgets 11-49 Ereignisgesteuerte Programmierung • Bei der Verbreitung von Ereignissen ist zwischen den Modi single-cast und multi-cast zu unterscheiden. Für Single-Cast-Ereignisse wird der Beobachter mit einer setxxListener-Methode gesetzt, für Multi-Cast-Ereignisse wird ein Beobachter mit einer addxxListener-Methode der Menge der Beobachter hinzugefügt. • Eine Adapter-Klasse ist eine Klasse, die eine gegebene Schnittstelle implementiert, indem sie jede abstrakte Methode durch einen leeren Rumpf realisiert. Adapter-Klassen werden verwendet, wenn von einer Schnittstelle lediglich ein Teil der Methoden benötigt wird, der Rest aber uninteressant ist. In diesem Fall leitet man eine neue Klasse aus der Adapter-Klasse ab und überlagert nur die erforderlichen Methoden. 11.4 Ereignisse und Widgets 11-50 Ereignisklassen • EventObject ◦ AWTEvent ∗ ComponentEvent - FocusEvent - InputEvent - KeyEvent - MouseEvent - ContainerEvent - WindowEvent ∗ ActionEvent ∗ AdjustmentEvent ∗ ItemEvent ∗ TextEvent 11.4 Ereignisse und Widgets 11-51 EventListener-Schnittstellen • EventListener ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ FocusListener ActionListener AdjustmentListener ItemListener TextListener KeyListener MouseListener MouseMotionListener WindowListener ContainerListener ComponentListener 11.4 Ereignisse und Widgets 11-52 Low-Level-Events Beispiel: Window-Events • windowOpened • windowActivated, windowDeactivated • windowClosed • windowClosing • windowIconified, windowDeiconified 11.4 Ereignisse und Widgets 11-53 Widgets Fensterelemente mit Ein- und/oder Ausgabefunktionalität werden als Widgets (window gadgets) bezeichnet. Die Anordnung der Widgets in einem Fenster wird durch den Layout-Manager durchgeführt. Widgets sind beispielsweise: • Label • Rollbalken • Schaltflächen (buttons) • Checkboxen und Checkboxgruppen (radio buttons) 11.4 Ereignisse und Widgets 11-54 Widgets • Textfelder und Textbereiche • Auswahlboxen • Listen • Canvas • Panels • Dateidialogboxen (nicht für Applets) • Menüs (nicht für Applets) 11.4 Ereignisse und Widgets 11-55 Schritte zur Realisierung eines Widgets • Schnittstelle angeben • Widget deklarieren und initialisieren • Widget dem Layout hinzufügen • Beobachter registrieren • Ereignis behandeln Man beachte, dass mehrere Widgettypen dieselbe Ereignisklasse verwenden, z. B. benutzen Schaltflächen und Textfelder die Klasse ActionListener. 11.4 Ereignisse und Widgets 11-56 Beispiel: Rollbalken Als erstes Beispiel betrachten wir jetzt die Programmierung eines Rollbalkens. import java.awt.*; import java.awt.event.*; public class WindowBlind extends Frame implements AdjustmentListener { private Scrollbar schieber; private int schieberWert; 11.4 Ereignisse und Widgets 11-57 public WindowBlind() { setLayout(new FlowLayout()); setBackground(Color.white); schieber = new Scrollbar(Scrollbar.HORIZONTAL,0,1,0,101); add(schieber); addWindowListener(new WindowClosingAdapter()); schieber.addAdjustmentListener(this); } 11.4 Ereignisse und Widgets 11-58 public void paint(Graphics g) { g.drawString("Rollbalkenwert ist " + schieberWert,120,200); g.setColor(Color.red); g.drawRect(40,80,60,100); g.fillRect(40,80,60,schieberWert); g.setColor(Color.blue); g.drawRect(120,80,60,100); g.fillRect(120,80 + schieberWert,60,100 - schieberWert); g.setColor(Color.green); g.drawRect(200,80,60,100); g.fillRect(200,80,60,100 - schieberWert); } 11.4 Ereignisse und Widgets 11-59 public void adjustmentValueChanged(AdjustmentEvent e) { schieberWert = schieber.getValue(); repaint(); } 11.4 Ereignisse und Widgets 11-60 public static void main(String[] args) { WindowBlind f = new WindowBlind(); f.setSize(400,300); f.setVisible(true); } } 11.4 Ereignisse und Widgets 11-61 Beispiel: Label und Button ... implements ActionListener { private Label title; private Button knopf1, knopf2; private int anzahl = 0; public Konstruktor() { setLayout(new FlowLayout()); title = new Label("Zählknopf:"); knopf1 = new Button("Drück mich!"); knopf2 = new Button("Ende"); add(title); add(knopf1); add(knopf2); knopf1.addActionListener(this); knopf2.addActionListener(this); } 11.4 Ereignisse und Widgets 11-62 public void paint(Graphics g) { g.drawString("Der Knopf wurde " + anzahl + " mal gedrückt.",10,80); } public void actionPerformed(ActionEvent event) { anzahl++; if (event.getSource() == knopf2) System.exit(0); repaint(); } } 11.4 Ereignisse und Widgets 11-63 AbstractButton • Die abstrakte Klasse AbstractButton ist eine Unterklasse der Klasse JComponent (s. Abschnitt Swing-Klassen). • Die abstrakte Klasse AbstractButton enthält die Methode void doClick() durch die in Implementierungen dieser Klasse ein Klick programmatisch ausgeführt werden kann. • Beispiele für Unterklassen von AbstractButton sind die Klassen JButton, JToggleButton und JMenuItem. 11.4 Ereignisse und Widgets 11-64 Weitere Widgets • Textfield: ActionListener, addActionListener void actionPerformed(ActionEvent event) • Checkbox, Checkboxgroup: ItemListener, addItemListener void itemStateChanged(ItemEvent event) • Choice: ItemListener, addItem, addItemListener void itemStateChanged(ItemEvent event) 11.4 Ereignisse und Widgets 11-65 Grafikprogrammierung in Java: Applets 11.1 11.2 11.3 11.4 11.5 11.6 Grundlagen Grafische Grundelemente Fensterklassen Ereignisse und Widgets Applets Die Swing-Klassen 11.5 Applets 11-66 Anwendungen und Applets • Anwendungen (Applikationen) ◦ Anwendungen bilden eigenständige Programme. Zur Ausführung benötigen sie nur den Java-Interpreter und die .class-Dateien der beteiligten Klassen. ◦ Jede Klasse, die die Methode public static void main enthält, kann als Anwendung benutzt werden. • Applets (little applications) ◦ Applets sind kleine Programme, die in eine Html-Seite eingebettet sind und nur innerhalb eines Web-Browsers oder eines Applet-Viewers ausgeführt werden können. ◦ Applets werden nicht durch die Methode main gestartet, sondern müssen aus der Klasse Applet abgeleitet und entsprechend konstruiert werden. 11.5 Applets 11-67 Ein kleines Applet: Java-Datei import java.awt.*; import java.applet.*; public class MinimalApplet extends Applet { public void paint(Graphics g) { g.drawString("Test-Ausgabe",0,20); } } 11.5 Applets 11-68 Ein kleines Applet: Html-Seite <html> <head> <title>Applet-Test</title> </head> <body> <applet code="MinimalApplet" width=600 height=800> Hier steht das Applet.</applet> </body> </html> 11.5 Applets 11-69 Anwendungen und Applets • Ein Applet wird immer aus der Klasse Applet abgeleitet. Bei einer Anwendung ist es dagegen gleichgültig, woraus die Hauptklasse abgeleitet wird. • Eine Anwendung wird gestartet, indem vom Java-Interpreter die Methode main aufgerufen wird. Das Starten eines Applets wird dadurch erreicht, dass der Browser oder der Applet-Viewer die Applet-Klasse instanziiert und die Methoden init und start aufruft. • Aus Gründen der Sicherheit darf ein Applet in der Regel weder auf Dateien des lokalen Rechners zugreifen noch externe Programme auf dem Rechner starten. 11.5 Applets 11-70 Anwendungen und Applets • Ein Applet arbeitet immer ereignisorientiert. Im Gegensatz dazu kann eine Anwendung auf die Behandlung von Ereignissen verzichten und alle Ein- und Ausgaben textbasiert durchführen. • Im Vergleich zu Anwendungen bieten Applets einige zusätzliche Möglichkeiten. 11.5 Applets 11-71 Die Klasse Applet Die Klasse Applet steht in der Vererbungshierarchie unter der Klasse Component und Container. Sie besitzt damit deren Eigenschaften. • Component ◦ Container ∗ Panel - Applet Bezüglich der Reaktion auf Ereignisse und die Registrierung und Programmierung von Listener-Klassen verhält sich ein Applet wie jedes andere Fenster. 11.5 Applets 11-72 Methoden • init(): Initialisierung eines Applets • start(): Start eines Applets • stop(): Stopp eines Applets, z. B. beim Laden einer anderen Seite. start und stop können mehrfach während der Lebensdauer eines Applets aufgerufen werden. • paint(Graphics g): Methode zum Zeichnen • destroy(): Beenden eines Applets 11.5 Applets 11-73 Beispiel: Rollbalken Als Beispiel schreiben wir das Rollbalkenprogramm als Applet. import java.awt.*; import java.awt.event.*; import java.applet.Applet; public class WindowBlind extends Applet implements AdjustmentListener { private Scrollbar schieber; private int schieberWert; 11.5 Applets 11-74 public void init () { setBackground(Color.white); schieber = new Scrollbar(Scrollbar.HORIZONTAL,0,1,0,101); add(schieber); schieber.addAdjustmentListener(this); } 11.5 Applets 11-75 public void paint(Graphics g) { showStatus("Rollbalkenwert ist " + schieberWert); g.setColor(Color.red); g.drawRect(40,80,60,100); g.fillRect(40,80,60,schieberWert); g.setColor(Color.blue); g.drawRect(120,80,60,100); g.fillRect(120,80 + schieberWert,60,100 - schieberWert); g.setColor(Color.green); g.drawRect(200,80,60,100); g.fillRect(200,80,60,100 - schieberWert); } 11.5 Applets 11-76 public void adjustmentValueChanged(AdjustmentEvent e) { schieberWert = schieber.getValue(); repaint(); } } 11.5 Applets 11-77 Anwendungen und Applets Dies sind die wesentlichen Schritte, um eine Anwendung in ein Applet zu konvertieren. Die Anwendung darf nur Elemente benutzen, die auch für Applets erlaubt sind. • Html-Seite erzeugen • main-Methode löschen • Aus dem Paket java.applet importieren, JApplet statt JFrame erweitern • Konstruktor in init umbenennen, ggf. start, stop, destroy schreiben • Layout festlegen • Bei mehreren Klassen: jar-Datei erzeugen 11.5 Applets 11-78 Anwendungen und Applets Dies sind die wesentlichen Schritte, um ein Applet in eine Anwendung zu konvertieren. Das Applet darf keine speziellen Methoden der applet-Klasse verwenden. • import applet löschen • frame statt applet erweitern • init als Konstruktor schreiben • main-Methode erzeugen • Methode zum Fenster schließen hinzufügen • Layout festlegen 11.5 Applets 11-79 Grafikprogrammierung in Java: Die Swing-Klassen 11.1 11.2 11.3 11.4 11.5 11.6 Grundlagen Grafische Grundelemente Fensterklassen Ereignisse und Widgets Applets Die Swing-Klassen 11.6 Die Swing-Klassen 11-80 Die Java Foundation Classes Seit der Version 1.2 des JDK werden die grafischen Fähigkeiten von Java unter dem Begriff Java Foundation Classes (JFC) zusammengefasst. Die drei wichtigsten Bestandteile sind: • Das Abstract Window Toolkit (AWT) stellt elementare Grafik- und Fensterfunktionen auf der Basis der jeweiligen Zielmaschine zur Verfügung. • Das Swing Toolset bietet darüber hinausgehende Möglichkeiten zur Konstruktion komplexer grafischer Oberflächen. Insbesondere wird ein „pluggable look and feel“ ermöglicht. • Die dritte wichtige Komponente ist die Java 2D API (Klassen für zweidimensionale Grafikverarbeitung) mit diversen Grafikoperationen und Bildbearbeitungsroutinen. 11.6 Die Swing-Klassen 11-81 Die Java Foundation Classes Die Klassen lassen sich in vier Gruppen einteilen: • Behälter (container) bestehen aus Komponenten, die auch selbst Komponenten enthalten können. Beispielsweise sind die Objekte der Klassen JFrame und JWindow Behälter. • Komponenten enthalten die Bestandteile der Fenster. Komponenten sind beispielsweise Beschriftungen (label), Auswahlfelder, Knöpfe (buttons), . . . • Layout-Manager, Fonts und Farben bestimmen die Anordnung und das Aussehen der Komponenten in einem Behälter. • Mit den Ereignisklassen werden mögliche Ereignisse, Beobachter und Reaktionen festgelegt. 11.6 Die Swing-Klassen 11-82 Die Java Foundation Classes • Die Swing-Bibliothek ersetzt und erweitert die Komponenten- und Behälterklassen des AWTs. • Die AWT-Klassen zu Schrift, Farbe und Layout-Manager sowie die Ereignisklassen werden weiterverwendet. • Die AWT-Klassen befinden sich im Paket java.awt, die Swingklassen in javax.swing. • Die Klassen der Swing-Bibliothek beginnen in der Regel mit dem Buchstaben J. 11.6 Die Swing-Klassen 11-83 AWT und Swing im Vergleich • Im AWT wird der Peer-Ansatz verfolgt: Alle AWT-Komponenten reichen die auszuführenden Aktionen an plattformspezifische GUI-Objekte, sogenannte Peers, weiter. Komponenten, die solche Peer-Objekte benötigen, werden als schwergewichtig bezeichnet. Diese Komponenten sehen auf unterschiedlichen Betriebssystemen unterschiedlich aus. Es können nur die Funktionalitäten bereitgestellt werden, die auf dem jeweiligen Betriebssystem zur Verfügung stehen. • Fast alle Swing-Komponenten sind vollständig in Java geschrieben und werden deshalb leichtgewichtig genannt. Form und Funktion sind daher weitgehend unabhängig vom Betriebssystem. Die Oberfläche kann plattformunabhängig gestaltet werden und ist noch zur Laufzeit veränderbar (pluggable look and feel). 11.6 Die Swing-Klassen 11-84 Eigenschaften von Swing • Im Gegensatz zum AWT benutzen Swing-Komponenten nur noch in sehr eingeschränkter Weise plattformspezifische GUI-Ressourcen. • Abgesehen von Top-Level-Fenstern, Dialogen und grafischen Primitivoperationen werden alle GUI-Elemente von Swing selbst erzeugt. • Ein Swing-Button unter Windows wird nicht mehr vom Windows-UI-Manager dargestellt, sondern von Swing selbst gezeichnet. • Diese Vorgehensweise bietet Vorteile. Zwei Beispiele: ◦ Plattformspezifische Besonderheiten fallen weg. ◦ Es entfallen auch Unterschiede in der Bedienung. 11.6 Die Swing-Klassen 11-85 Eigenschaften von Swing Guido Krüger, Heiko Hansen: Handbuch der Java-Programmierung. • Eine bemerkenswerte Eigenschaft von Swing ist die Möglichkeit, das Look-and-Feel (Aussehen und Bedienung einer Anwendung) zur Laufzeit umzuschalten. • Dieses als Pluggable Look-and-Feel bezeichnete Feature ermöglicht es beispielsweise einem Windows-Anwender, zwischen unterschiedlichen vordefinierten Look-and-Feels (zum Beispiel Metal, Motif und Windows) zu wählen. • Benutzer anderer Betriebssysteme können andere Auswahlmöglichkeiten haben oder eigene Look-and-Feels zu schreiben. • Seit Java 7 gibt es ein viertes Standard-Look-and-Feel, das Nimbus-Look-and-Feel. 11.6 Die Swing-Klassen 11-86 Wiederholung: Ein einfaches AWT-Beispiel import java.awt.*; public class FrameOhneInhaltAWT { public static void main(String[] args) { Frame fenster = new Frame(); fenster.setTitle("Ein AWT-Fenster"); fenster.setLocation(500,400); fenster.setSize(300,150); fenster.setVisible(true); } } 11.6 Die Swing-Klassen 11-87 Ein einfaches Swing-Beispiel import javax.swing.*; public class FrameOhneInhaltSwing { public static void main(String[] args) { JFrame fenster = new JFrame(); fenster.setTitle("Ein Swing-Fenster"); fenster.setLocation(500,400); fenster.setSize(300,150); fenster.setVisible(true); fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 11.6 Die Swing-Klassen 11-88 AWT und Swing im Vergleich • Es wird aus unterschiedlichen Paketen importiert: import java.awt.* bzw. import javax.swing.*. • Die Behälterklassen sind verschieden: Frame bzw. JFrame. • In der Swing-Variante gibt es eine einfache Möglichkeit zum Schließen eines Fensters: setDefaultCloseOperation. • Beim Lauf erzeugt die Swingklasse einen grauen Hintergrund. 11.6 Die Swing-Klassen 11-89 Eine abgeleitete Swing-Klasse import javax.swing.*; public class FrameOhneInhalt extends JFrame { public FrameOhneInhalt () { } public static void main(String[] args) { FrameOhneInhalt fenster = new FrameOhneInhalt(); fenster.setTitle("Frame ohne Inhalt"); fenster.setLocation(500,500); fenster.setSize(300,150); fenster.setVisible(true); fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 11.6 Die Swing-Klassen 11-90 Ein Fenster mit Text public class FrameMitText extends JFrame { Container c; // Container dieses Frames JLabel beschriftung; // Label, das im Frame erscheinen soll public FrameMitText() { c = getContentPane(); c.setLayout(new FlowLayout()); beschriftung = new JLabel("Label-Text im Frame"); c.add(beschriftung); } public static void main(String[] args) { FrameMitText fenster = new FrameMitText(); fenster.setTitle("Frame mit Text im Label"); fenster.setLocation(200,200); fenster.setSize(300,150); fenster.setVisible(true); fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }} 11.6 Die Swing-Klassen 11-91 Einordnung der Swingklassen • Component ◦ Container ∗ Panel - Applet · JApplet ∗ Window - JWindow - Frame · JFrame - Dialog · JDialog ∗ JComponent ◦ Button, Label, weitere AWT-Komponenten 11.6 Die Swing-Klassen 11-92 Einordnung der Swingklassen • JComponent ◦ JLabel ◦ AbstractButton ◦ JComboBox ◦ JMenuBar ◦ JList ◦ JScrollBar ◦ JProgressBar ◦ JTextComponent ◦ JPanel ◦ JTable ◦ ... 11.6 Die Swing-Klassen 11-93 Einordnung der Swingklassen • Die Swing-Behälter-Klassen JFrame, JWindow, . . . sind Erweiterungen der entsprechenden AWT-Klassen. • Die Swing-Komponenten-Klassen bilden eine eigene Hierarchie unterhalb von Container. • Alle Swing-Klassen stehen unterhalb von Container und erben somit von Component und Container. Die gleichzeitige Verwendung von AWT- und Swing-Komponenten ist zu vermeiden. 11.6 Die Swing-Klassen 11-94 Wiederholung: Die Klasse Component Die abstrakte Klasse Component steht an oberster Stelle der JFC-Hierachie. Sie stellt Basismethoden zur Verfügung, die alle AWT- und Swingkomponenten gemeinsam nutzen können. Die wichtigsten sind: • • • • • • • • Color getBackground(), Color getForeground() void setBackground(Color c), void setForeground(Color c) Font getFont, void setFont(Font c) int getHeight(), int getWidth() void setSize(int width, int height) setLocation(int x, int y) boolean isEnabled(), void setEnabled(boolean b) boolean isVisible(), void setVisible(boolean b) 11.6 Die Swing-Klassen 11-95 Wiederholung: Die Klasse Container Behälter sind spezielle Komponenten, die andere Komponenten enthalten können. Die Klasse Container stellt demzufolge Methoden zum Einfügen, Verwalten und Entfernen von Komponenten zu Verfügung. Die Komponenten werden in einer Liste geführt, wobei die Reihenfolge sich durch die Reihenfolge der Einfügungen ergibt oder durch einen Listenindex bestimmt werden kann. Die Liste wird zur Anordnung der Komponenten in dem Behälterobjekt benötigt. • • • • • Component add(Component comp) Component add(Component comp, int index) Component[] getComponents() void remove(Component comp) void setLayout(LayoutManager mgr) 11.6 Die Swing-Klassen 11-96 Die Klasse JComponent Die abstrakte Klasse JComponent dient als Basisklasse für die Swingkomponenten mit Ausnahme der Klassen Component und Container. Von diesen beiden Klassen erbt JComponent und überschreibt dabei einige Methoden. Komponenten können sowohl durchsichtig (opaque: false) als auch undurchsichtig (opaque: true) sein und mit einem erläuternden Text, dem sog. Tooltip, versehen werden. Der Text erscheint, wenn der Mauszeiger einige Sekunden auf der Komponente ruht. • • • • boolean isOpaque() void setOpaque(boolean b) String getToolTipText() void setToolTipText(String text) 11.6 Die Swing-Klassen 11-97 Die Klasse JComponent All Implemented Interfaces: ImageObserver, MenuContainer, Serializable Direct Known Subclasses: AbstractButton, BasicInternalFrameTitlePane, Box, Box.Filler, JColorChooser, JComboBox, JFileChooser, JInternalFrame, JInternalFrame.JDesktopIcon, JLabel, JLayeredPane, JList, JMenuBar, JOptionPane, JPanel, JPopupMenu, JProgressBar, JRootPane, JScrollBar, JScrollPane, JSeparator, JSlider, JSpinner, JSplitPane, JTabbedPane, JTable, JTableHeader, JTextComponent, JToolBar, JToolTip, JTree, JViewport 11.6 Die Swing-Klassen 11-98 Komponenten: Inhalt und Anordnung Ein Behälterobjekt enthält in der Regel eine oder mehrere Komponenten. Die Komponenten können Texte, Bilder, Zeichnungen, . . . enthalten. Mithilfe eines Layoutmanagers werden die Komponenten innerhalb des Behälters angeordnet. • Mit der Klasse Font (java.awt) können Schriften ausgewählt werden. • Die Klasse Color (java.awt) stellt Farben zur Verfügung. • Die abstrakte Klasse Graphics (java.awt) bietet Möglichkeiten zur Erstellung von Zeichnungen. • Die Schnittstellen LayoutManager und LayoutManager2 (java.awt) offerieren Methoden zur Anordnung der Komponenten. Die Schnittstelle Border und die Klasse BorderFactory (javax.swing) bieten Möglichkeiten zur Gestaltung der Grenzen zwischen Komponenten. 11.6 Die Swing-Klassen 11-99 Die Klasse FlowLayout Bei Verwendung der Klasse FlowLayout werden die Komponenten fließend, d. h. zeilenweise von links nach rechts, angeordnet. Per Default werden die Komponenten zentriert. Zwischen den Zeilen befindet sich ein Standardabstand von 5 Pixeln, der aber geändert werden kann. Mit dem Parameter align kann bestimmt werden, ob die Komponenten links- oder rechtsbündig bzw. zentriert dargestellt werden. hgap und vgap geben die Abstände zwischen den Komponenten und Zeilen an. • FlowLayout() • FlowLayout(int align) • FlowLayout(int align, int hgap, int vgap) Der Parameter align kann ein statisches int-Attribut sein: FlowLayout.LEFT, FlowLayout.RIGHT, FlowLayout.CENTER, FlowLayout.LEADING, FlowLayout.TRAILING. 11.6 Die Swing-Klassen 11-100 Die Klasse BorderLayout Bei diesem Layout wird die Behälterfläche in die fünf Bereiche Nord, Ost, Süd, West und Zentrum aufgeteilt. In jedes dieser Gebiete kann eine Komponente eingefügt werden. Die Größe von Nord, Ost, Süd und West ergibt sich aus dem jeweiligen Objekt, während die Größe des Zentrums an die Gesamtgröße des Behälters angepasst wird. Beispielsweise wird durch add(...,BorderLayout.NORTH) ein Objekt im oberen und durch add(...,BorderLayout.CENTER) im mittleren Bereich hinzugefügt. • BorderLayout() • BorderLayout(int hgap, int vgap) 11.6 Die Swing-Klassen 11-101 Die Klasse GridLayout Die Behälterfläche wird gitterartig in z Zeilen und s Spalten aufgeteilt. Die Werte z und s werden bereits dem Konstruktor übergeben. • GridLayout() • GridLayout(int z, int s) • GridLayout(int z, int s, int hgap, int vgap) Es gibt etliche weitere Layout-Klassen, z. B. GridBagLayout, BoxLayout, SpringLayout, OverlayLayout. Im Package java.awt befinden sich die zwei Schnittstellen LayoutManager und LayoutManager2. Sie enthalten Hinweise auf Klassen, die diese Schnittstellen implementieren. 11.6 Die Swing-Klassen 11-102 Die Klasse Graphics • Die abstrakte Klasse Graphics stellt zahlreiche Methoden bereit, die es ermöglichen, innerhalb des Koordinatensystems einer Komponente zu zeichnen. Hierzu zählen die Methoden, die wir bereits kennengelernt haben: drawLine, drawRect, . . . . In einem grafischen Kontext sind die gegenwärtigen Einstellungen zu Schrift und Farbe sowie die zu bearbeitende Komponente gespeichert. • Die Klasse Graphics2D ist aus Graphics abgeleitet und erweitert diese um viele Aspekte, insbesondere um solche zur Darstellung von zweidimensionalen Zeichnungen. • Für die Darstellung einer einzelnen Swing-Komponente ist der Repaint-Manager zuständig. Er sorgt dafür, dass beim erstmaligen Erscheinen und bei Veränderungen die Methode public void paint(Graphics g) aufgerufen wird. 11.6 Die Swing-Klassen 11-103 Die Komponentenklasse JLabel Die Klasse JLabel dient zur Darstellung von Texten und Bildern. public class MyFrame extends JFrame { Container c; // Container dieses Frames JLabel lab; // Label, das im Frame erscheinen soll public MyFrame() { c = getContentPane(); c.setLayout(new FlowLayout()); Icon bild = new ImageIcon("xxx.jpg"); lab = new JLabel("Text", bild, JLabel.CENTER); lab.setHorizontalTextPosition(JLabel.CENTER); lab.setVerticalTextPosition(JLabel.BOTTOM); c.add(lab); } ... } 11.6 Die Swing-Klassen 11-104 Die Komponentenklasse AbstractButton Die abstrakte Klasse bietet verschiedene Arten von Schaltflächen und Knöpfen. Die wichtigsten Implementierungen sind: • JButton • JToggleButton ◦ JCheckBox ◦ JRadioButton • JMenuItem (einfache Schaltfläche zum Auslösen von Aktionen) (Schalter mit zwei Zuständen) (Kennzeichnung durch Häkchen) (sich ausschließende Schalter) (Schaltflächen in einem Menü) ◦ JMenu ◦ JCheckBoxMenuItem ◦ JRadioButtonMenuItem 11.6 Die Swing-Klassen 11-105 Beispiel: JRadioButton Container c; JRadioButton rb[] = new JRadioButton[4]; ... public Konstruktor() { c = getContentPane(); c.setLayout(new FlowLayout()); ButtonGroup bg = new ButtonGroup(); for (int i = 0; i < 4; i++) { rb[i] = new JRadioButton("Box " + (i+1)); bg.add(rb[i]); c.add(rb[i]); } } 11.6 Die Swing-Klassen 11-106 Die Komponentenklasse JComboBox • Ein Objekt der Klasse JComboBox ist eine aufklappbare Auswahlliste, die man mithilfe der Maus oder der Tastatur aufklappen und in der man einen Eintrag auswählen kann. • Angezeigt wird dabei jeweils der ausgewählte Eintrag und ein Pfeil nach unten, der anzeigt, dass es sich um eine aufklappbare Liste handelt. 11.6 Die Swing-Klassen 11-107 Beispiel: JComboBox Container c; JComboBox vornamen, nachnamen; public Konstruktor() { c = getContentPane(); c.setLayout(new FlowLayout()); String[] namen = {"Hans", "Klaus", "Sabine", "Erika"}; vornamen = new JComboBox(namen); nachnamen = new JComboBox(); nachnamen.addItem("Meyer"); nachnamen.addItem("Müller"); nachnamen.addItem("Schulze"); nachnamen.addItem("Lehmann"); nachnamen.setSelectedIndex(2); c.add(vornamen); c.add(nachnamen); } 11.6 Die Swing-Klassen 11-108 Die Komponentenklasse JList • Im Unterschied zur JComboBox-Objekt stellt ein Objekt der Klasse JList eine Auswahlliste dar, die bereits aufgeklappt ist und daher komplett angezeigt wird. • In der API steht in der Klasse JList: A component that displays a list of objects and allows the user to select one or more items. • Durch Drücken der Taste Ctrl/Strg können mehrere Einträge ausgewählt werden. Die ausgewählten Einträge werden markiert. Mit der Shift-Taste kann ein ganzer Bereich markiert werden. 11.6 Die Swing-Klassen 11-109 Die Komponentenklasse JTextComponent Die abstrakte Klasse bietet verschiedene Möglichkeiten zur Eingabe von Text. Die wichtigsten Implementierungen sind: • JTextArea • JTextField ◦ JPasswordField • JTextPane ◦ JHTMLPane 11.6 Die Swing-Klassen (Eingabe mehrzeiliger Texte) (Eingabe einzeiliger Texte) (Eingabe einzeiliger geschützter Texte) (Eingabe von formatierten Texten) (z. B. HTML-Texte) 11-110 Die Komponentenklasse JScrollPane • Objekte der Klasse JScrollPane sind in der Lage, andere Komponenten aufzunehmen und in einen Darstellungsbereich einzubetten, der mit horizontalen und vertikalen Bildlaufleisten ausgestattet ist. • Hierdurch wird eine ausschnittsweise Sicht auf die Komponenten ermöglicht. • Der jeweilige Ausschnitt wird mit Schiebereglern (scrollbars), die sich am Bildrand befinden, festgelegt. 11.6 Die Swing-Klassen 11-111 Die Komponentenklasse JPanel • Objekte der Klasse JPanel können andere Komponenten enthalten. Sie sind daher eigentlich keine Komponenten, sondern Behälter. • JPanel ist die Basisklasse für Container, die nicht Hauptfenster sind. Standardmäßig verwendet JPanel das FlowLayout. • Objekte der Klasse JPanel werden zum Strukturieren von Behältern verwendet – und sind aus dieser Sicht Komponenten anderer Behälter. 11.6 Die Swing-Klassen 11-112 Die Behälterklasse JFrame • Die Klasse JFrame ist die wichtigste Top-Level-Behälterklasse. • Sie erbt von Frame, ihre Objekte sind daher Fenster mit Rahmen. • In der Titelleiste des Rahmens befinden sich die üblichen System-Menü-Einträge. • Zusätzlich zu den Methoden von Frame stellt JFrame weitere zur Verfügung, z. B. zum Schließen von Fenstern. 11.6 Die Swing-Klassen 11-113 Die Behälterklasse JWindow • Wie JFrame ist auch JWindow eine Top-Level-Behälterklasse. • Sie erbt von Window, die Objekte sind daher rahmenlose Fenster. • Ein JWindow-Objekt kann einem JFrame-Objekt oder einem anderem JWindow-Objekt gehören. In diesem Fall wird das JWindow-Objekt mit seinem Besitzer gemeinsam minimiert und maximiert. • Die Konstruktoren JWindow(Frame owner) und JWindow(Window owner) erzeugen rahmenlose Fenster, die dem owner gehören. Sie werden zusammen mit dem owner minimiert und maximiert. 11.6 Die Swing-Klassen 11-114 Die Behälterklasse JDialog • Die Klasse JDialog wird dazu benutzt, um Dialogfenster darzustellen. • Dies sind Fenster, die nur solange erscheinen, bis ein Dialog mit dem Benutzer/der Benutzerin abgewickelt wurde. • Ein JDialog-Fenster kann einem übergeordneten Fenster gehören. Dieses übergeordnete kann solange für Benutzereingaben gesperrt werden, bis der Dialog im Dialogfenster beendet ist. 11.6 Die Swing-Klassen 11-115 Die Klassen JMenuBar und JToolBar • Einem JFrame-Objekt kann eine Menüleiste hinzugefügt werden. Dies erfolgt mit Objekten der Klasse JMenuBar. • Eine Menüleiste verwaltet eine Liste von Menüs vom Typ JMenu. • Neben Menüleisten sieht man häufig Werkzeugleisten (toolbars). Hierbei handelt es sich um spezielle Behälter, die meistens Button-Objekte enthalten, die häufig verwendete Funktionalitäten auslösen können. • Eine Werkzeugleiste kann als Objekt der Klasse JToolBar erzeugt werden. 11.6 Die Swing-Klassen 11-116 Die Klasse JApplet • Zur Programmierung von Applets stellt die Swing-Bibliothek die Klasse JApplet zur Verfügung. • JApplet ist direkt aus Applet abgeleitet. • Die Klasse JApplet steht also in der Hierachie unter Component, Container und Applet und erbt daher die Methoden dieser Klassen. 11.6 Die Swing-Klassen 11-117 Prinzipielle Vorgehensweise • Durch Instanziieren einer (eigenen) Fensterklasse wird ein Fensterobjekt erzeugt. Für das Objekt werden Location, Size und Title festgelegt, es wird sichtbar gemacht, ... Die Klasse geht in der Regel aus der Ableitung einer Behälterklasse (zum Beispiel JFrame, JWindow, ...) hervor. • Das Layout und der grafische Kontext werden festgelegt. • Die Komponenten werden dem Fensterobjekt hinzugefügt (zum Beispiel im Konstruktor der Fensterklasse). • Für jede Ereignisquelle werden ein oder mehrere Ereignisempfänger (Beobachter) sowie die Aktionen zur Ereignisbehandlung definiert. Die Ereignisempfänger werden bei der zuständigen Ereignisquelle registriert. 11.6 Die Swing-Klassen 11-118 Wiederholung: Adapterklassen • Eine Adapterklasse implementiert eine Schnittstelle durch leere Rümpfe. • Zu jeder Low-Level-Listener-Schnittstelle mit mehr als einer Methode existiert eine Adapterklasse. Ist XxxListener der Name der Schnittstelle, so heißt die Adapterklasse XxxAdapter. Man schreibt also class MeinListener extends XxxAdapter statt class MeinListener implements XxxListener. • Beispielsweise enthält die Schnittstelle ActionListener nur eine Methode, WindowListener jedoch – wie bereits gesehen – mehrere. 11.6 Die Swing-Klassen 11-119 Strukturierung von Behälter- und Beobachterklasse • Die Beobachterklasse wird als innere Klasse realisiert. • Die Beobachterklasse wird als anonyme Klasse realisiert. • Die Fensterklasse wird selbst zur Beobachterklasse. • Die Beobachterklasse ist eine selbstständige Klasse. Ihr muss der Behälter als Parameter übergeben werden. Wir erläutern die Möglichkeiten an einem Beispiel zur Wechsel der Hintergrundfarbe. Die folgenden Programme wurden D. Ratz, J. Scheffler, D. Seese, J. Wiesenberger: Grundkurs Programmieren in Java entnommen. 11.6 Die Swing-Klassen 11-120 Realisierung als innere Klasse public class Farbwechsel1 extends JFrame { Container c; JButton button; public Farbwechsel1() { c = getContentPane(); button = new JButton("Hintergrundfarbe wechseln"); c.add(button, BorderLayout.NORTH); ButtonListener bL = new ButtonListener(); button.addActionListener(bL); } 11.6 Die Swing-Klassen 11-121 class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { float zufall = (float) Math.random(); Color grauton = new Color(zufall,zufall,zufall); c.setBackground(grauton); } } public static void main(String[] args) { Farbwechsel1 fenster = new Farbwechsel1(); fenster.setTitle("Farbwechsel"); fenster.setLocation(200,200); fenster.setSize(500,500); fenster.setVisible(true); fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 11.6 Die Swing-Klassen 11-122 Realisierung als anonyme Klasse public class Farbwechsel2 extends JFrame { Container c; JButton button; public Farbwechsel2() { c = getContentPane(); button = new JButton("Hintergrundfarbe wechseln"); c.add(button, BorderLayout.NORTH); ActionListener bL = new ActionListener() { public void actionPerformed(ActionEvent e) { ... } }; button.addActionListener(bL); } public static void main(String[] args) { ... } } 11.6 Die Swing-Klassen 11-123 Fensterklasse als Beobachterklasse public class Farbwechsel3 extends JFrame implements ActionListener { Container c; JButton button; public Farbwechsel3() { c = getContentPane(); button = new JButton("Hintergrundfarbe wechseln"); c.add(button, BorderLayout.NORTH); button.addActionListener(this); } public void actionPerformed(ActionEvent e) { ... } public static void main(String[] args) { ... } } 11.6 Die Swing-Klassen 11-124 Beobachterklasse als selbstständige Klasse public class Farbwechsel4 extends JFrame { Container c; JButton button; public Farbwechsel4() { c = getContentPane(); button = new JButton("Hintergrundfarbe wechseln"); c.add(button, BorderLayout.NORTH); ButtonListener bL = new ButtonListener(c); button.addActionListener(bL); } public static void main(String[] args) { ... } } 11.6 Die Swing-Klassen 11-125 Beobachterklasse als selbstständige Klasse public class ButtonListener implements ActionListener { Container c; public ButtonListener(Container c) { this.c = c; } public void actionPerformed(ActionEvent e) { float zufall = (float) Math.random(); Color grauton = new Color(zufall,zufall,zufall); c.setBackground(grauton); } } 11.6 Die Swing-Klassen 11-126 Beispiel: Fenster mit Menü- und Werkzeugleiste import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Bilderrahmen extends JFrame { Container c; JMenuBar menuBar; JMenu menu; JMenuItem menuItem; JToolBar toolBar; JButton button; JLabel bildLabel; 11.6 Die Swing-Klassen // // // // // // // Container dieses Frames Menueleiste Menue Menue-Eintrag Werkzeugleiste Knoepfe der Werkzeugleiste Label das im Frame erscheinen soll 11-127 public Bilderrahmen() { c = getContentPane(); MenuListener mL = new MenuListener(); menuBar = new JMenuBar(); menu = new JMenu("Bilder"); menu.setMnemonic(KeyEvent.VK_B); // kombiniert mit Alt_Taste // API sagt: KeyEvent indicates keystroke in a component // Wörterbuch sagt: keystroke = Tastendruck oder Tastenanschlag menuItem = new JMenuItem("Hund"); menuItem.setMnemonic(KeyEvent.VK_H); menuItem.addActionListener(mL); menuItem.setActionCommand("dog"); menu.add(menuItem); 11.6 Die Swing-Klassen 11-128 menuItem = new JMenuItem("Katze"); menuItem.setMnemonic(KeyEvent.VK_K); menuItem.addActionListener(mL); menuItem.setActionCommand("cat"); menu.add(menuItem); menuItem = new JMenuItem("Maus"); menuItem.setMnemonic(KeyEvent.VK_M); menuItem.addActionListener(mL); menuItem.setActionCommand("mouse"); menu.add(menuItem); 11.6 Die Swing-Klassen 11-129 menuBar.add(menu); setJMenuBar(menuBar); ToolBarListener tL = new ToolBarListener(); toolBar = new JToolBar("Rahmenfarbe"); button = new JButton(new ImageIcon("images/rot.gif")); button.setToolTipText("roter Rahmen"); button.addActionListener(tL); button.setActionCommand("rot"); toolBar.add(button); 11.6 Die Swing-Klassen 11-130 button = new JButton(new ImageIcon("images/gruen.gif")); button.setToolTipText("gruener Rahmen"); button.addActionListener(tL); button.setActionCommand("gruen"); toolBar.add(button); button = new JButton(new ImageIcon("images/blau.gif")); button.setToolTipText("blauer Rahmen"); button.addActionListener(tL); button.setActionCommand("blau"); toolBar.add(button); bildLabel = new JLabel(new ImageIcon("images/dog.gif")); 11.6 Die Swing-Klassen 11-131 c.setBackground(Color.red); c.add(bildLabel, BorderLayout.CENTER); c.add(toolBar, BorderLayout.NORTH); } class MenuListener implements ActionListener { public void actionPerformed(ActionEvent e) { bildLabel.setIcon(new ImageIcon("images/"+e.getActionCommand()+".gif")); } } 11.6 Die Swing-Klassen 11-132 class ToolBarListener implements ActionListener { public void actionPerformed(ActionEvent e) { if (e.getActionCommand() == "rot") c.setBackground(Color.red); else if (e.getActionCommand() == "gruen") c.setBackground(Color.green); else if (e.getActionCommand() == "blau") c.setBackground(Color.blue); } } 11.6 Die Swing-Klassen 11-133 public static void main(String[] args) { Bilderrahmen fenster = new Bilderrahmen(); fenster.setTitle("Bilderrahmen"); fenster.setLocation(200,200); fenster.setSize(180,280); fenster.setVisible(true); fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 11.6 Die Swing-Klassen 11-134 Swing-Klassen Als Beispiele für Swing-Klassen haben wir u. a. die Klassen/Schnittstellen JFrame, JWindow, JApplet, JComponent, JButton, JCheckBox, JComboBox, JDialog, JLabel, JList, JMenu, JMenuBar, JMenuItem, JPanel, JPassword, JRadioButton, JScrollBar, JTable, JTextArea, JTextComponent, JTextField, JToggleButton, JToolBar, ... kennengelernt. Es gibt etliche weitere Swing-Klassen/Schnittstellen: JFileChooser, JColorChooser, JInternalFrame, JSeparator, JSlider, JSpinner, JSplitPane, ... Als weiteres Beispiel sehen wir uns die Klasse JFileChooser an. 11.6 Die Swing-Klassen 11-135 Die Komponentenklasse JFileChooser Eine relativ häufige Aufgabe ist die Auswahl eines Dateinamens zum Öffnen oder Speichern einer Datei. Die Klasse JFileChooser aus dem Paket javax.swing bietet ein Dialogfenster an, mit dem man im Dateisystem navigieren und die gewünschte Datei auswählen kann. In der API steht: JFileChooser provides a simple mechanism for the user to choose a file. public class JFileChooser extends JComponent implements ... 11.6 Die Swing-Klassen 11-136 Die Komponentenklasse JFileChooser Konstruktoren: JFileChooser() JFileChooser(String ordner) JFileChooser(File ordner) Start: Home-Ordner Start: ordner Start: ordner Einige Methoden: int showOpenDialog(Component c) int showSaveDialog(Component c) Öffnet einen Dialog mit einem Button zum Öffnen bzw. Speichern. Der Dialog erscheint zentriert über der Komponente c. Rückgabe ist eine Konstante für den Button: APPROVE_OPTION Öffnen/Speichern CANCEL_OPTION Abbruch ERROR_OPTION Fehler oder das Fenster wurde vom Anwender geschlossen. 11.6 Die Swing-Klassen 11-137 Die Komponentenklasse JFileChooser Weitere Methoden (nicht alle): int showDialog(Component c, String text) Öffnet einen Dialog mit einem Button mit der Beschriftung text. Der Dialog erscheint über der Komponente c. void setSelectedFile(File datei) Setzt die ausgewählte Datei als Vorgabewert auf datei. File getSelectedFile() Liefert die vom Anwender ausgewählte Datei. void setFileFilter(FileFilter filter) Setzt den Dateifilter auf filter. 11.6 Die Swing-Klassen 11-138 Die Komponentenklasse JFileChooser Ein Beispiel für die Verwendung von JFileChooser: // Start: aktueller Ordner JFileChooser dateiAuswahl = new JFileChooser("."); int status = dateiAuswahl.showOpenDialog(this); if (status == JFileChooser.APPROVE_OPTION) { File datei = dateiAuswahl.getSelectedFile(); ..... } JFileChooser dient hier zur Ermittlung des Dateinamens. Das Laden oder Speichern muss noch programmiert werden. 11.6 Die Swing-Klassen 11-139 Die Komponentenklasse JFileChooser In der API steht das folgende Beispiel zum Einsatz eines Filters für die Datei: The following code pops up a file chooser for the user’s home directory that sees only .jpg and .gif images: JFileChooser chooser = new JFileChooser(); FileNameExtensionFilter filter = new FileNameExtensionFilter( "JPG & GIF Images", "jpg", "gif"); chooser.setFileFilter(filter); int returnVal = chooser.showOpenDialog(parent); if(returnVal == JFileChooser.APPROVE_OPTION) { System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName()); } 11.6 Die Swing-Klassen 11-140