das java codebook - *isbn 3-8273-2059-3 ......334 multimedia für die definition eigener rahmen...

10
Core I/O GUI Multi- media Daten- bank Netz- werk XML RegEx Daten Threads Web- Server Applets Sonsti- ges Multimedia 84 Wie kann ich einfache Strukturen zeichnen? Seit Java2 (JDK 1.2) steht das Java2D-API zur Verfügung. Mit dieser Einführung sind viele erweiterte Grafikmöglichkeiten zur Verfügung gestellt worden, obgleich die Kompatibilität zu den früheren Funktionen gewahrt wurde. Es stellt viele Funk- tionen zum Zeichnen von grundlegenden, geometrischen Figuren zur Verfügung. Dazu gehören Linien, Rechtecke, Kreise bzw. Ellipsen, Kreisbögen und Polygone. Die entsprechenden Klassen finden sich im Paket java.awt.geom. Sie sind alle Unter- klassen der Klasse java.awt.Shape. Damit ist es möglich, sie alle auf die gleiche Art und Weise in den Zeichenmethoden der Klasse Graphics2D zu behandeln. In der Klasse SimpleDraw werden einige grundlegende Figuren gezeichnet, die mit dem Java2D-API sehr einfach zu erstellen sind. Abbildung 67: Grundlegende Zeichenfunktionen package javacodebook.media.draw.simple; import java.awt.*; import java.awt.geom.*; import javax.swing.*; public class SimpleDraw extends JPanel{ //In Swing immer die Methode paintComponent überschreiben public void paintComponent(Graphics graphics) { Listing 139: SimpleDraw

Upload: others

Post on 03-Mar-2021

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

Core

I/O

GUI

Multi-media

Daten-bank

Netz-werk

XML

RegEx

Daten

Threads

Web-Server

Applets

Sonsti-ges

Multimedia

84 Wie kann ich einfache Strukturen zeichnen?Seit Java2 (JDK 1.2) steht das Java2D-API zur Verfügung. Mit dieser Einführungsind viele erweiterte Grafikmöglichkeiten zur Verfügung gestellt worden, obgleichdie Kompatibilität zu den früheren Funktionen gewahrt wurde. Es stellt viele Funk-tionen zum Zeichnen von grundlegenden, geometrischen Figuren zur Verfügung.Dazu gehören Linien, Rechtecke, Kreise bzw. Ellipsen, Kreisbögen und Polygone.Die entsprechenden Klassen finden sich im Paket java.awt.geom. Sie sind alle Unter-klassen der Klasse java.awt.Shape. Damit ist es möglich, sie alle auf die gleiche Artund Weise in den Zeichenmethoden der Klasse Graphics2D zu behandeln.

In der Klasse SimpleDraw werden einige grundlegende Figuren gezeichnet, die mitdem Java2D-API sehr einfach zu erstellen sind.

Abbildung 67: Grundlegende Zeichenfunktionen

package javacodebook.media.draw.simple;import java.awt.*;import java.awt.geom.*;import javax.swing.*;

public class SimpleDraw extends JPanel{ //In Swing immer die Methode paintComponent überschreiben public void paintComponent(Graphics graphics) {

Listing 139: SimpleDraw

Page 2: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

330 Multimedia

85 Wie zeichne ich verschiedene Rahmen?

Wenn Sie keinen Standard-Rahmen um eine geometrische Figur zeichnen wollen,sondern beispielsweise einen gestrichelten Rahmen, oder einen Rahmen in eineranderen Strichstärke verwenden wollen, so können Sie die Methode setStroke() derKlasse Graphics2D verwenden. In Verbindung mit der Klasse java.awt.BasicStroke

super.paintComponent(graphics); //Graphics-Objekt ist in Wahrheit ein Graphics2D-Objekt Graphics2D g = (Graphics2D) graphics; //Aktuelle Zeichenfarbe setzen g.setColor(Color.black); //Eine Linie zeichnen g.draw(new Line2D.Double(0,100,319,100)); //Ein Rechteck zeichnen g.draw(new Rectangle2D.Double(10, 10, 80, 60)); //Einen Kreis gefüllt zeichnen g.draw(new Ellipse2D.Double(130,10,60,60)); //Eine Ellipse mit Farbverlauf gefüllt zeichnen g.draw(new Ellipse2D.Double(230, 10, 80, 60)); //Ein Rechteck mit abgerundeten Ecken zeichnen g.draw(new RoundRectangle2D.Double(10, 110, 80, 60, 15, 15)); //Einen Kreisbogen zeichnen g.draw(new Arc2D.Double(120, 110, 80, 70, 90, 135, Arc2D.OPEN)); //Ein Tortenstück zeichnen g.draw(new Arc2D.Double(240, 110, 80, 80, 90, 45, Arc2D.PIE)); } //Größe des Panels festlegen public Dimension getPreferredSize() { return new Dimension(320, 200); } //Frame erzeugen Panel anzeigen public static void main(String[] args) { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().setLayout(new BorderLayout()); f.getContentPane().add(new SimpleDraw(), BorderLayout.CENTER); f.pack(); f.show(); }}

Listing 139: SimpleDraw (Forts.)

Page 3: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

Wie zeichne ich verschiedene Rahmen? 331

Core

I/O

GUI

Multi-media

Daten-bank

Netz-werk

XML

RegEx

Daten

Threads

Web-Server

Applets

Sonsti-ges

lassen sich sehr viele Einstellungen für den zu zeichnenden Rahmen vornehmen. Mitihrer Hilfe können Strichstärke, Linienenden, Linienverbindungen und unterbro-chene Linien erzeugt werden. Sie stellt einige Konstanten bereit, über die das Endeund die Verbindung von Linien definiert werden können. Die Werte CAP_BUTT,CAP_ROUND und CAP_SQUARE bestimmen den Stil, in dem ein Linienende gezeichnetwird (gerade, abgerundet oder mit geradem Anhang).

Die Werte JOIN_BEVEL, JOIN_MITER und JOIN_ROUND legen fest, wie das Zusammentref-fen von zwei Linienenden behandelt wird. Es kann ohne Effekt (BEVEL), mit spitzemEnde (MITER) oder abgerundet (ROUND) gezeichnet werden.

Die Klasse BasicStroke bietet verschiedene Konstruktoren an, um die gewünschtenEffekte zu erzielen. Die meisten sind sehr einfach zu benutzen. Der Konstruktor fürdas Erzeugen von gestrichelten Linien ist etwas komplexer. Er hat die Form publicBasicStroke(float width, int cap, int join, float miterlimit, float[] dash,

float dash_phase). Die Parameter width, cap, join sind leicht erkennbar (Strich-stärke und die oben genannten Stile). Miterlimit beschreibt, wie lang zwei Linienam Ende verbunden werden. Das wird wichtig, wenn zwei Linien in sehr spitzemWinkel aufeinander treffen. Wird eine Spitze gezeichnet, so kann diese sehr langwerden. Dies wird durch das miterlimit begrenzt (würde die Spitze länger als derWert miterlimit, wird stattdessen mit der BEVEL-Funktion gezeichnet). Die Parame-ter dash und dash_phase beschreiben gestrichelte Linien. Im Array dash werden dieLängen der einzelnen Strichabschnitte angegeben. Dabei wird alternierend zwischengezeichnetem und nicht gezeichnetem Strich gewechselt. Ein Array in der Form{5,5} macht dasselbe wie {5}, da abwechselnd 5 Punkte gezeichnet werden und dienächsten 5 nicht. Der Wert dash_phase dient als Offset für das Zeichnen der Striche-lung, d.h. die ersten x Punkte werden übersprungen.

Die Klasse StrokeExamples zeigt, wie die verschiedenen Rahmenarten und Linien-enden gezeichnet werden.

package javacodebook.media.draw.stroke;import java.awt.*;import java.awt.geom.*;import javax.swing.*;

public class StrokeExamples extends JPanel{ public void paintComponent(Graphics graphics) {

Listing 140: StrokeExamples

Page 4: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

332 Multimedia

super.paintComponent(graphics); //Graphics-Objekt ist in Wahrheit ein Graphics2D-Objekt Graphics2D g = (Graphics2D) graphics; //aktuelle Zeichenfarbe setzen g.setColor(Color.black); //Ein Rechteck mit Rahmendicke 5 zeichnen BasicStroke fatBorder = new BasicStroke(5.0f); g.setStroke(fatBorder); g.draw(new Rectangle2D.Double(10, 10, 80, 60)); //Ein Rechteck mit gestricheltem Rahmen zeichnen BasicStroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.0f, new float[] {5.0f}, 0.0f); g.setStroke(stroke); g.draw(new RoundRectangle2D.Double(110, 10, 80, 60, 15, 15)); //Rahmen mit verschiedenen Strichlängen zeichnen stroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.0f, new float[] {5.0f, 5.0f, 2.0f, 5.0f}, 0.0f); g.setStroke(stroke); g.draw(new RoundRectangle2D.Double(210, 10, 80, 60, 15, 15)); //Linien überschneiden sich am Ende ohne Effekt stroke = new BasicStroke(10.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); g.setStroke(stroke); int x = 25; g.draw(new Line2D.Double(x, 160, x+25, 135)); g.draw(new Line2D.Double(x+25, 135, x+50, 160)); //Linien überschneiden sich am Ende, Spitze wird gezeichnet stroke = new BasicStroke(10.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER); g.setStroke(stroke); x = 125; g.draw(new Line2D.Double(x, 160, x+25, 135)); g.draw(new Line2D.Double(x+25, 135, x+50, 160)); //Linien überschneiden sich am Ende, Spitze wird abgerundet

Listing 140: StrokeExamples (Forts.)

Page 5: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

Wie zeichne ich verschiedene Rahmen? 333

Core

I/O

GUI

Multi-media

Daten-bank

Netz-werk

XML

RegEx

Daten

Threads

Web-Server

Applets

Sonsti-ges

Und so sieht das Ergebnis aus.

stroke = new BasicStroke(10.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); g.setStroke(stroke); x = 225; g.draw(new Line2D.Double(x, 160, x+25, 135)); g.draw(new Line2D.Double(x+25, 135, x+50, 160)); } /** Die gewünschte Größe des Panels festlegen */ public Dimension getPreferredSize() { return new Dimension(300, 180); } /** Einen Frame erzeugen und das Panel anzeigen */ public static void main(String[] args) { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().setLayout(new BorderLayout()); f.getContentPane().add(new StrokeExamples(), BorderLayout.CENTER); f.pack(); f.show(); }}

Abbildung 68: Verschiedene Möglichkeiten, Rahmen zu zeichnen

Listing 140: StrokeExamples (Forts.)

Page 6: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

334 Multimedia

Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann können selbst definierte Rahmen innerhalb der Zeichenfunk-tionen der Graphics2D-Klasse verwendet werden. Der mit Hilfe von setStroke()festgelegte Zeichenstrich kann auf alle Zeichenobjekte angewendet werden, die eineUnterklasse von java.awt.Shape sind.

86 Wie kann ich etwas mit Farbverläufen füllen?Ein Farbverlauf wird mit Hilfe der Klasse java.awt.GradientPaint definiert. Er ver-läuft von einem Startpunkt hin zu einem Endpunkt, die beide in Koordinatenformangegeben werden. Eine Ausgangs- und eine Endfarbe müssen angegeben werden,dazwischen wird entlang einer Geraden zwischen Start- und Endpunkt ein linearerFarbverlauf berechnet. Mit der Methode fill(Shape shape) aus der Klasse Graphics2Dwird der Farbverlauf gezeichnet. Auch zyklisches Füllen ist möglich.

Die Klasse GradientPaint hat zwei Konstruktoren, die es in zwei Variationen gibt,einmal mit einzelnen Koordinaten und einmal mit Point2D-Objekten als Parameter,um die Endpunkte der Farbverläufe festzulegen. Wir beschränken uns hier auf dieVariante mit einzelnen Koordinaten:

Mit der ersten Variante wird ein einfacher, azyklischer Farbverlauf vom Punkt x1,y1hin zu Punkt x2, y2 erzeugt. Die zweite Variante ermöglicht sowohl einen azykli-schen als auch einen zyklischen Farbverlauf. Mit dem Parameter cyclic kann ange-geben werden, ob der Farbverlauf zyklisch wiederholt werden soll. Er wird allerdingsnur dann zyklisch verlaufen, wenn der angegebene Endpunkt {x2,y2} nicht auch derEndpunkt des zu füllenden Shapes ist. Wird der Endpunkt {x2, y2} z.B. in der Mittedes zu füllenden Shapes angegeben, so wird der Farbverlauf einmal vom Rand biszur Mitte von Farbe 1 zu Farbe 2 verlaufen und dann von der Mitte zum anderenRand von Farbe 2 zu Farbe 1.

Das vorherige Bild zeigt die Möglichkeiten, die sich mit GradientPaint ergeben.

public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2);

public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2, boolean cyclic);

Page 7: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

Wie kann ich etwas mit Farbverläufen füllen? 335

Core

I/O

GUI

Multi-media

Daten-bank

Netz-werk

XML

RegEx

Daten

Threads

Web-Server

Applets

Sonsti-ges

Abbildung 69: Füllen mit Farbverläufen

public void paintComponent(Graphics graphics) { super.paintComponent(graphics); Graphics2D g = (Graphics2D) graphics;

float startx = 10, starty = 10; float width=80, height=60; //Farbverlauf definieren und ein gefülltes Rechteck zeichnen //Farbverlauf von links (schwarz) nach rechts (weiß) linear GradientPaint gradient = new GradientPaint(startx, starty, Color.black, startx + width, starty, Color.white); g.setPaint(gradient); g.fill(new Rectangle2D.Double(startx, starty, width, height)); startx = 110; //Farbverlauf diagonal von links oben nach rechts unten gradient = new GradientPaint(startx, starty, Color.black, startx + width, starty + height, Color.white); g.setPaint(gradient); g.fill(new Rectangle2D.Double(startx, starty, width, height));

startx = 20; starty = 110; //Zyklischer Farbverlauf mit Zentrum in der Mitte gradient = new GradientPaint(startx, starty, Color.black, startx + width, starty, Color.white, true);

Page 8: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

336 Multimedia

87 Wie kann ich eine Grafik laden und anzeigen?Eine Grafik wird in Java von der Klasse java.awt.Image repräsentiert. Java unter-stützt von sich aus die Formate GIF und JPEG. Sie haben mehrere Möglichkeiten,ein Bild zu laden. Innerhalb eines Applets kann die Methode getImage() verwendetwerden, in einer Anwendung die Methode getImage() der Klasse java.awt.Toolkit.Dabei kann letztere nur über das Default-Toolkit, das von der Java Runtime bereit-gestellt wird, verwendet werden. Das Default-Toolkit wird von der Klasse Toolkitüber die Methode getDefaultToolkit() geliefert. Somit sieht ein entsprechenderAufruf in einer Anwendung so aus:

Die Methode getImage() kehrt sofort zurück und das Laden der Grafik erfolgt imHintergrund. Dies hat zur Folge, dass ein Bild u.U. noch nicht vollständig geladenist, wenn es verwendet werden soll. Die Kontrolle über den Ladevorgang können Siedurch den Einsatz eines MediaTrackers (java.awt.MediaTracker) behalten. Im Kapitelüber Applets wird dies gezeigt.

Wenn Sie das Bild sofort verwenden wollen, nehmen Sie die Klasse javax.swing.ImageIcon. Sie verwendet intern einen MediaTracker und erspart so diverse Codezei-len. Der Konstruktor erhält als Parameter eine Datei oder URL, von der das Bildgeladen wird. Mit der Methode getImage() kann das Bild anschließend genutzt wer-den.

Um das Bild anzuzeigen, kann eine entsprechende Swing-Komponente verwendetwerden, die ImageIcons unterstützt (z.B. ein JLabel). Es ist jedoch auch sehr einfach,eine eigene Komponente zu schreiben, die Grafiken anzeigt. Eine eigene Kompo-nente kann oft flexibler innerhalb von GUI-Anwendungen eingesetzt werden. DieKlasse ImagePanel ist als Komponente realisiert, die von JPanel erbt. Damit kann siean beliebiger Stelle verwendet werden, z.B. innerhalb einer JScrollPane. Im Kons-truktor wird die Grafik übergeben. Das ImagePanel nimmt danach die Größe derGrafik als seine optimale Größe an.

g.setPaint(gradient); g.fill(new Rectangle2D.Double(startx, starty, width*2, height)); }

Image image = Toolkit.getDefaultToolkit().getImage(dateiname);

Page 9: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

Wie kann ich eine Grafik laden und anzeigen? 337

Core

I/O

GUI

Multi-media

Daten-bank

Netz-werk

XML

RegEx

Daten

Threads

Web-Server

Applets

Sonsti-ges

Damit lässt sich ein einfacher Bildbetrachter erstellen. Die Klasse ImageViewer stellteine einfache Möglichkeit dar, Bilder zu laden und anzuzeigen. Dabei wird derFrame jeweils der Größe der anzuzeigenden Grafik angepasst.

package javacodebook.media.graphic.load;import java.awt.*;import javax.swing.JPanel;

public class ImagePanel extends javax.swing.JPanel { //Die Grafik, die angezeigt werden soll private Image image; public ImagePanel(Image image) { this.image = image; } //Grafik auf das Panel zeichnen public void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image, 0, 0, image.getWidth(this), image.getHeight(this), this); } //Größe der Grafik als PreferredSize zurückgegeben public Dimension getPreferredSize() { return new Dimension(image.getWidth(this), image.getHeight(this)); }}

Listing 141: ImagePanel

package javacodebook.media.graphic.load;import java.awt.*;import java.awt.event.*;import java.io.*;import javax.swing.*;

public class ImageViewer extends JFrame { //das ImagePanel ImagePanel imagePanel = null;

Listing 142: ImageViewer

Page 10: Das Java Codebook  - *ISBN 3-8273-2059-3 ......334 Multimedia Für die Definition eigener Rahmen muss das Interface java.awt.Stroke implemen-tiert werden, dann

338 Multimedia

public ImageViewer() { setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); getContentPane().setLayout(new BorderLayout()); //Einen Button zum Öffnen von Dateien erstellen JPanel buttonPanel = new JPanel(); getContentPane().add(buttonPanel, BorderLayout.NORTH); JButton openButton = new JButton("Datei öffnen"); buttonPanel.add(openButton); //Einen ActionListener auf den Button legen, der einen //FileChooser öffnet openButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { JFileChooser chooser = new JFileChooser(); int status = chooser.showOpenDialog(ImageViewer.this); if (status == JFileChooser.APPROVE_OPTION) { //ausgewählte Datei ermitteln und abspielen File file = chooser.getSelectedFile(); try { ImageIcon icon = new ImageIcon(file.getAbsolutePath()); //vorher vorhandenes ImagePanel entfernen if(imagePanel != null) getContentPane().remove(imagePanel); //das ImagePanel anzeigen imagePanel = new ImagePanel(icon.getImage()); getContentPane().add(imagePanel, BorderLayout.CENTER); //Frame auf die Bildgröße anpassen pack(); } catch(Exception e) { e.printStackTrace(System.out); } } } }); } public static void main(String[] args) { ImageViewer viewer = new ImageViewer(); viewer.pack(); viewer.show(); }}

Listing 142: ImageViewer (Forts.)