Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Benutzeroberflächen mit Java 4.1.20111Michael Weiss.

Ähnliche Präsentationen


Präsentation zum Thema: "Benutzeroberflächen mit Java 4.1.20111Michael Weiss."—  Präsentation transkript:

1 Benutzeroberflächen mit Java Michael Weiss

2 import javax.swing.*; /** Michael Weiss */ public class Uhr { private JFrame hatJFrame; public Uhr() { hatJFrame = new JFrame("Fenster"); hatJFrame.setVisible(true); // <- vorher sieht man gar nichts! } public static void main(String args[]) { try { // 5 Zeilen, damit sich das Programm ins OS integriert UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { System.err.println("no system look and feel available"); }; new Uhr(); } import javax.swing.*; /** Michael Weiss */ public class Uhr { private JFrame hatJFrame; public Uhr() { hatJFrame = new JFrame("Fenster"); hatJFrame.setVisible(true); // <- vorher sieht man gar nichts! } public static void main(String args[]) { try { // 5 Zeilen, damit sich das Programm ins OS integriert UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { System.err.println("no system look and feel available"); }; new Uhr(); } Ausgangspunkt JFrame Michael Weiss

3 Ausgangspunkt JFrame Michael Weiss Das Resultat überzeugt noch nicht vollständig: import javax.swing.*; import java.awt.*; public Uhr() { hatJFrame = new JFrame("Fenster"); hatJFrame.setMinimumSize(new_Dimension(400,300)); hatJFrame.setVisible(true); } } import javax.swing.*; import java.awt.*; public Uhr() { hatJFrame = new JFrame("Fenster"); hatJFrame.setMinimumSize(new_Dimension(400,300)); hatJFrame.setVisible(true); } } Ergebnis: Verbesserung:

4 Fenster aufteilen Michael Weiss Das Fenster soll am Schluss etwa so aussehen: Wenn man das Fenster skaliert, soll der Bereich oben rechts nicht breiter werden.

5 JPanel Michael Weiss Die einzelnen Fensterteile sind Objekte vom Typ JPanel. Wir fügen nun gemäss dem gewünschten Layout 3 JPanels in das JFrame ein. public Uhr() { hatJFrame = new JFrame("Fenster"); hatJFrame.setMinimumSize(new Dimension(400,300)); hatJFrame.setLayout(new BorderLayout()); hatZeichenJPanel_=_new_JPanel(); hatJFrame.add(hatZeichenJPanel,_BorderLayout.CENTER); hatSliderJPanel_=_new_JPanel(); hatJFrame.add(hatSliderJPanel,_BorderLayout.SOUTH); hatButtonJPanel_=_new_JPanel(); hatJFrame.add(hatButtonJPanel,_BorderLayout.EAST); hatJFrame.setVisible(true); } public Uhr() { hatJFrame = new JFrame("Fenster"); hatJFrame.setMinimumSize(new Dimension(400,300)); hatJFrame.setLayout(new BorderLayout()); hatZeichenJPanel_=_new_JPanel(); hatJFrame.add(hatZeichenJPanel,_BorderLayout.CENTER); hatSliderJPanel_=_new_JPanel(); hatJFrame.add(hatSliderJPanel,_BorderLayout.SOUTH); hatButtonJPanel_=_new_JPanel(); hatJFrame.add(hatButtonJPanel,_BorderLayout.EAST); hatJFrame.setVisible(true); } Der sichtbare Effekt ist gleich null, daher fügen wir 2 Buttons ein.

6 GridLayout und JButton Michael Weiss hatButtonJPanel.setLayout(new GridLayout(2,1)); // Zeilen, Spalten hatPauseJButton = new JButton("Pause"); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatButtonJPanel.add(hatStellenJButton); hatButtonJPanel.setLayout(new GridLayout(2,1)); // Zeilen, Spalten hatPauseJButton = new JButton("Pause"); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatButtonJPanel.add(hatStellenJButton); Wir fügen 2 Buttons in das hatButtonJPanel ein. Dazu soll der Platz in diesem Panel in gleich grosse Rechteckzellen eingeteilt werden, was durch Zuweisung eines GridLayouts geschieht. Wieder überzeugt das Resultat nur teilweise: Der "Pause"-Knopf blinkt blau, wie wenn er aktiv wäre (man sagt: wie wenn er den Focus hätte). Die beiden Knöpfe füllen den gesamten "EAST"-Raum aus.

7 Keine Buttons mit Focus Michael Weiss hatButtonJPanel.setLayout(new GridLayout(2,1)); // Zeilen, Spalten hatPauseJButton = new JButton("Pause"); hatPauseJButton.setFocusable(false); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatStellenJButton.setFocusable(false); hatButtonJPanel.add(hatStellenJButton); hatButtonJPanel.setLayout(new GridLayout(2,1)); // Zeilen, Spalten hatPauseJButton = new JButton("Pause"); hatPauseJButton.setFocusable(false); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatStellenJButton.setFocusable(false); hatButtonJPanel.add(hatStellenJButton);...und bitte nicht so riesig! Eigentlich sollen die Buttons nur den oberen Teil des EAST-Gebiets füllen: Dazu unterteilen wir das EAST-Gebiet erneut mit einem BorderLayout und stecken das ButtonJPanel in das NORTH-Gebiet dieser Unterteilung.

8 Geschachtelte Layouts Michael Weiss hatEastJPanel_=_new_JPanel(); hatJFrame.add(hatEastJPanel,_BorderLayout.EAST); hatEastJPanel.setLayout(new_BorderLayout()); hatButtonJPanel = new JPanel(); hatEastJPanel.add(hatButtonJPanel,_BorderLayout.NORTH); hatButtonJPanel.setLayout(new GridLayout(2,1)); // Zeilen, Spalten hatPauseJButton = new JButton("Pause"); hatPauseJButton.setFocusable(false); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatStellenJButton.setFocusable(false); hatButtonJPanel.add(hatStellenJButton); hatEastJPanel_=_new_JPanel(); hatJFrame.add(hatEastJPanel,_BorderLayout.EAST); hatEastJPanel.setLayout(new_BorderLayout()); hatButtonJPanel = new JPanel(); hatEastJPanel.add(hatButtonJPanel,_BorderLayout.NORTH); hatButtonJPanel.setLayout(new GridLayout(2,1)); // Zeilen, Spalten hatPauseJButton = new JButton("Pause"); hatPauseJButton.setFocusable(false); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatStellenJButton.setFocusable(false); hatButtonJPanel.add(hatStellenJButton); schon besser....aber ein wenig freien Rand rund um die Buttons würde man sich schon noch wünschen!

9 Ränder einrichten Michael Weiss hatEastJPanel = new JPanel(); hatJFrame.add(hatEastJPanel, BorderLayout.EAST); hatEastJPanel.setLayout(new BorderLayout()); hatButtonJPanel = new JPanel(); // unsichtbaren 10 Pixel breiten Rand um das hatButtonJPanel hatButtonJPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); hatEastJPanel.add(hatButtonJPanel, BorderLayout.NORTH); // Das GridLayout_auch_noch_mit_Abständen_zwischen_den_Zellen_versehen hatButtonJPanel.setLayout(new GridLayout(2,1,10,10)); // Zeilen, Spalten, horiz. & vert. Abstand hatPauseJButton = new JButton("Pause"); hatPauseJButton.setFocusable(false); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatStellenJButton.setFocusable(false); hatButtonJPanel.add(hatStellenJButton); hatEastJPanel = new JPanel(); hatJFrame.add(hatEastJPanel, BorderLayout.EAST); hatEastJPanel.setLayout(new BorderLayout()); hatButtonJPanel = new JPanel(); // unsichtbaren 10 Pixel breiten Rand um das hatButtonJPanel hatButtonJPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); hatEastJPanel.add(hatButtonJPanel, BorderLayout.NORTH); // Das GridLayout_auch_noch_mit_Abständen_zwischen_den_Zellen_versehen hatButtonJPanel.setLayout(new GridLayout(2,1,10,10)); // Zeilen, Spalten, horiz. & vert. Abstand hatPauseJButton = new JButton("Pause"); hatPauseJButton.setFocusable(false); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatStellenJButton.setFocusable(false); hatButtonJPanel.add(hatStellenJButton); nicht schlecht!

10 Slider Michael Weiss hatJSlider = new JSlider(JSlider.HORIZONTAL, -10, 10, 1); hatJSlider.setMajorTickSpacing(1); hatJSlider.setPaintTicks(true); hatJSlider.setPaintLabels(true); hatSliderJPanel.add(hatJSlider); hatJSlider = new JSlider(JSlider.HORIZONTAL, -10, 10, 1); hatJSlider.setMajorTickSpacing(1); hatJSlider.setPaintTicks(true); hatJSlider.setPaintLabels(true); hatSliderJPanel.add(hatJSlider); Leider hat Java seine eigenen Vorstellungen davon, was eine optimale Slider-Breite ist. Nun noch ein Schiebebalken zur Einstellung der Geschwindigkeit der Uhr.

11 Slider, verschönert Michael Weiss hatJSlider = new JSlider(JSlider.HORIZONTAL, -10, 10, 1); hatJSlider.setMajorTickSpacing(1); hatJSlider.setPaintTicks(true); hatJSlider.setPaintLabels(true); hatJSlider.setMinimumSize(new_Dimension(hatJFrame.getWidth()-20,50)); hatJSlider.setPreferredSize(new_Dimension(hatJFrame.getWidth()-20,50)); hatSliderJPanel.add(hatJSlider); hatJSlider = new JSlider(JSlider.HORIZONTAL, -10, 10, 1); hatJSlider.setMajorTickSpacing(1); hatJSlider.setPaintTicks(true); hatJSlider.setPaintLabels(true); hatJSlider.setMinimumSize(new_Dimension(hatJFrame.getWidth()-20,50)); hatJSlider.setPreferredSize(new_Dimension(hatJFrame.getWidth()-20,50)); hatSliderJPanel.add(hatJSlider); Einige Versuche führen schliesslich auf die folgende Lösung: Das kommt dem erwünschten Aussehen schon recht nahe. Nur die Uhr fehlt noch!

12 import javax.swing.*; import java.awt.*; /** * Ein JPanel um drin zu zeichnen. * Michael Weiss */ public class ZeichenJPanel extends JPanel { // überschreibe die entsprechende Methode der Überklasse protected void paintComponent(Graphics pGraphics) { // Damit die Buttons, Slider, Labels etc. weiterhin gezeichnet werden, // rufen wir als erstes paintComponent() der Überklasse auf. super.paintComponent(pGraphics); // Ab hier zeichnen wir selbst. } import javax.swing.*; import java.awt.*; /** * Ein JPanel um drin zu zeichnen. * Michael Weiss */ public class ZeichenJPanel extends JPanel { // überschreibe die entsprechende Methode der Überklasse protected void paintComponent(Graphics pGraphics) { // Damit die Buttons, Slider, Labels etc. weiterhin gezeichnet werden, // rufen wir als erstes paintComponent() der Überklasse auf. super.paintComponent(pGraphics); // Ab hier zeichnen wir selbst. } In ein JPanel hineinzeichnen Michael Weiss Im Gegensatz zur SuM-Bibliothek stellen uns die Java-Standardbibliotheken kein Fenster zur Verfügung, in das wir einfach jederzeit zeichnen können. Dafür weiss Java, wann ein JPanel neu gezeichnet werden muss und ruft dann die Methode paintComponent(Graphics pGraphics) auf. Standardmässig zeichnet diese Methode aber nur die in ihr enthaltenen GUI- Komponenten (Buttons, Slider, Labels etc.) neu. Formen wie Kreise, Linien usw. müssen wir selbst zeichnen. Zu diesem Zweck entwickeln wir eine Unterklasse von JPanel, welche paintComponent(Graphics pGraphics) überschreibt:

13 hatUhrJPanel = new JPanel(); hatJFrame.add(hatUhrJPanel, BorderLayout.CENTER); hatUhrZeichenJPanel_=_new_ZeichenJPanel(); hatJFrame.add(hatUhrZeichenJPanel,_BorderLayout.CENTER); hatUhrJPanel = new JPanel(); hatJFrame.add(hatUhrJPanel, BorderLayout.CENTER); hatUhrZeichenJPanel_=_new_ZeichenJPanel(); hatJFrame.add(hatUhrZeichenJPanel,_BorderLayout.CENTER); In ein JPanel hineinzeichnen Michael Weiss Das erfordert auch kleine Änderungen an der Klasse Uhr: Bis jetzt haben wir aber noch gar nichts gezeichnet!

14 // ab hier zeichnen wir selbst. pGraphics.setColor(Color.BLACK); int xmin = 0, width = 0, ymin = 0, height = 0; if(this.getWidth() > this.getHeight()) { height = this.getHeight() - 10; ymin = 5; xmin = (this.getWidth() - height) / 2; width = height; } else { width = this.getWidth() - 10; xmin = 5; ymin = (this.getHeight() - width) / 2; height = width; } pGraphics.drawOval(xmin, ymin, width, height); // ab hier zeichnen wir selbst. pGraphics.setColor(Color.BLACK); int xmin = 0, width = 0, ymin = 0, height = 0; if(this.getWidth() > this.getHeight()) { height = this.getHeight() - 10; ymin = 5; xmin = (this.getWidth() - height) / 2; width = height; } else { width = this.getWidth() - 10; xmin = 5; ymin = (this.getHeight() - width) / 2; height = width; } pGraphics.drawOval(xmin, ymin, width, height); Wie zeichnet man eine Uhr? Michael Weiss Die Uhr sollte ein möglichst grosses Quadrat ausfüllen. Wir bestimmen die Koordinaten dieses Quadrats und beginnen dann mit einem Kreis. Das Graphics-Objekt wird uns von Java mitgegeben, damit wir seine Methoden zum zeichnen benutzen können. Manchmal braucht man mehr Methoden, als sie das Graphics-Objekt zur Verfügung stellt. pGraphics zeigt aber in Wirklichkeit gar nicht auf ein reines Graphics-Objekt, sondern auf ein Graphics2D-Objekt, welches weitere Zeichnungsmehtoden zur Verfügung stellt. Um pGraphics als Zeiger auf ein Graphics2D-Objekt zu verwenden, müssen wir casten: Graphics2D kenntGraphics = (Graphics2D)pGraphics; // danach mit kenntGraphics arbeiten. Graphics2D kenntGraphics = (Graphics2D)pGraphics; // danach mit kenntGraphics arbeiten.

15 Die Uhrzeiger Michael Weiss Es macht Sinn, eine Klassenhierarchie einzuführen: Die Standard-Bibliothek von Java erlaubt es, Formen als Kombinationen von Linienzügen, Ellipsen, Kreisbogenstücken und anderen Grundformen auszudrücken und diese Formen später als Ganzes zu transformieren. Wir beschreiben daher die Zeiger in einer bequemen Lage (12-Uhr-Stellung) und in einem handlichen Koordinatensystem (Ursprung im Mittelpunkt der Uhr, Radius der Uhr gleich 50 Einheiten). Die anschliessende Transformationsarbeit (Drehen der Zeiger entsprechend der gewünschten Zeit, Einpassen der Zeiger in ein Fenster, dessen Grösse sich verändern kann) ist für alle Uhrzeiger gleich und wird daher in der abstrakten Überklasse erledigt.

16 import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public class Minutenzeiger extends Uhrzeiger { public Minutenzeiger() { super(Color.BLACK); super.hatForm.moveTo(0,-15); super.hatForm.lineTo(2,0); super.hatForm.lineTo(0,45); super.hatForm.lineTo(-2,0); super.hatForm.closePath(); } import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public class Minutenzeiger extends Uhrzeiger { public Minutenzeiger() { super(Color.BLACK); super.hatForm.moveTo(0,-15); super.hatForm.lineTo(2,0); super.hatForm.lineTo(0,45); super.hatForm.lineTo(-2,0); super.hatForm.closePath(); } Der Minutenzeiger Michael Weiss x y hatForm ist vom Typ Path2D.float und kann mehrere Grafikobjekte aufnehmen. Es wird in der Überklasse erzeugt. Der Stundenzeiger sieht praktisch gleich aus.

17 import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public class Sekundenzeiger extends Uhrzeiger { public Sekundenzeiger() { super(Color.RED); super.hatForm.moveTo(-0.5,-16); super.hatForm.lineTo(0.5,-16); super.hatForm.lineTo(0.5,48); super.hatForm.lineTo(-0.5,48); super.hatForm.closePath(); super.hatForm.append(new Ellipse2D.Float(-3,-3,6,6), false); } import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public class Sekundenzeiger extends Uhrzeiger { public Sekundenzeiger() { super(Color.RED); super.hatForm.moveTo(-0.5,-16); super.hatForm.lineTo(0.5,-16); super.hatForm.lineTo(0.5,48); super.hatForm.lineTo(-0.5,48); super.hatForm.closePath(); super.hatForm.append(new Ellipse2D.Float(-3,-3,6,6), false); } Der Sekundenzeiger Michael Weiss x y

18 Affine Transformation Michael Weiss x y affine Transformation x y

19 Erster Schritt: Drehung Michael Weiss x y Drehung x y Da die Drehung im Uhrzeigersinn erfolgt, ist der Drehwinkel negativ. Java stellt die benötigte Koordinatenumrechnung (ein Spezialfall einer affinen Transformation) direkt zur Verfügung.

20 Drehung in Java Michael Weiss import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public abstract class Uhrzeiger { protected Path2D.Float hatForm; private Color zColor; // Jeder Uhrzeiger wird durch einen Pfad repräsentiert, der in ein Quadrat von 100 Einheiten Seitenlänge // passt, und dessen Koordinatenursprung sich in der Quadratmitte befindet. public Uhrzeiger(Color pColor) { zColor = pColor; hatForm = new Path2D.Float(); } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe, double pWinkel) { AffineTransform_lRotation_=_AffineTransform.getRotateInstance(-pWinkel_/_180.0_*_Math.PI); AffineTransform_lAffineTransform_=_new_AffineTransform(0.01*pBreite,0,0,-0.01*pHoehe,pH+0.5*pBreite,pV+_0.5*pHoehe); lAffineTransform.concatenate(lRotation); Path2D.Float lForm_=_ (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); } import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public abstract class Uhrzeiger { protected Path2D.Float hatForm; private Color zColor; // Jeder Uhrzeiger wird durch einen Pfad repräsentiert, der in ein Quadrat von 100 Einheiten Seitenlänge // passt, und dessen Koordinatenursprung sich in der Quadratmitte befindet. public Uhrzeiger(Color pColor) { zColor = pColor; hatForm = new Path2D.Float(); } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe, double pWinkel) { AffineTransform_lRotation_=_AffineTransform.getRotateInstance(-pWinkel_/_180.0_*_Math.PI); AffineTransform_lAffineTransform_=_new_AffineTransform(0.01*pBreite,0,0,-0.01*pHoehe,pH+0.5*pBreite,pV+_0.5*pHoehe); lAffineTransform.concatenate(lRotation); Path2D.Float lForm_=_ (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); } Der Drehwinkel muss im Bogenmass angegeben werden, daher / 180 *.

21 Zweiter Schritt: Transformation auf JPanelkoordinaten Michael Weiss Transfor- mation x' y' x y A(0|0) B(50|0) C(0|50) A'(x 0 +w/2|y 0 +h/2) B'(x 0 +w|y 0 +h/2) C'(x 0 +w/2|y 0 ) x0x0 x 0 +w y0y0 y 0 +h

22 Berechnung der Transformation Michael Weiss Wenn man berechnen will, welche Koordinaten (x'|y') ein Punkt im neuen Koordinatensystem haben wird, wenn er im alten Koordinatensystem die Koordinaten (x|y) hat, kann man von folgenden Gleichungen ausgehen: x' = ax + cy + e y' = bx + dy + f Anhand dreier vorgegebener Punkte A(x A, y A ), B(x B, y B ) und C(x C, y C ) sowie ihrer Bildpunkte A'(x A ', y A '), B'(x B ', y B ') und C'(x C ', y C ') lassen sich die Parameter a, b, c, d, e und f berechnen. In unserem Fall sind die Punkte A(0|0), B(50|0) und C(0|50) sowie deren Bildpunkte A'(x 0 +w/2|y 0 +h/2), B'(x 0 +w|y 0 +h/2) und C'(x 0 +w/2|y 0 ) gegeben. Setzen wir A und A' ein, erhalten wir x 0 +w/2 = e y 0 +h/2 = f Setzen wir B und B' ein und verwenden die bereits ausgerechneten Werte für e und f, erhalten wir nach kurzer Rechnung a = w/100 und b = 0. Mit C und C' finden wir schliesslich c = 0 und d = -h / 100.

23 Die Transformation in Java Michael Weiss import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public abstract class Uhrzeiger { protected Path2D.Float hatForm; private Color zColor; // Jeder Uhrzeiger wird durch einen Pfad repräsentiert, der in ein Quadrat von 100 Einheiten Seitenlänge // passt, und dessen Koordinatenursprung sich in der Quadratmitte befindet. public Uhrzeiger(Color pColor) { zColor = pColor; hatForm = new Path2D.Float(); } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe, double pWinkel) { AffineTransform lRotation = AffineTransform.getRotateInstance(-pWinkel / * Math.PI); AffineTransform_lAffineTransform_=_new_AffineTransform(0.01*pBreite,0,0,-0.01*pHoehe,pH+0.5*pBreite,pV+_0.5*pHoehe); lAffineTransform.concatenate(lRotation); Path2D.Float lForm_=_ (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); } import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public abstract class Uhrzeiger { protected Path2D.Float hatForm; private Color zColor; // Jeder Uhrzeiger wird durch einen Pfad repräsentiert, der in ein Quadrat von 100 Einheiten Seitenlänge // passt, und dessen Koordinatenursprung sich in der Quadratmitte befindet. public Uhrzeiger(Color pColor) { zColor = pColor; hatForm = new Path2D.Float(); } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe, double pWinkel) { AffineTransform lRotation = AffineTransform.getRotateInstance(-pWinkel / * Math.PI); AffineTransform_lAffineTransform_=_new_AffineTransform(0.01*pBreite,0,0,-0.01*pHoehe,pH+0.5*pBreite,pV+_0.5*pHoehe); lAffineTransform.concatenate(lRotation); Path2D.Float lForm_=_ (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); } w h x 0 y 0 Die Parameter a bis f werden in dieser Reihenfolge dem Konstruktor eines Objekts der Klasse AffineTransform übergeben.

24 Hintereinanderausführung von Drehung und Koordinatentransformation Michael Weiss import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public abstract class Uhrzeiger { protected Path2D.Float hatForm; private Color zColor; // Jeder Uhrzeiger wird durch einen Pfad repräsentiert, der in ein Quadrat von 100 Einheiten Seitenlänge // passt, und dessen Koordinatenursprung sich in der Quadratmitte befindet. public Uhrzeiger(Color pColor) { zColor = pColor; hatForm = new Path2D.Float(); } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe, double pWinkel) { AffineTransform lRotation = AffineTransform.getRotateInstance(-pWinkel / * Math.PI); AffineTransform lAffineTransform = new AffineTransform(0.01*pBreite,0,0,-0.01*pHoehe,pH+0.5*pBreite,pV+ 0.5*pHoehe); lAffineTransform.concatenate(lRotation); Path2D.Float lForm_=_ (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); } import java.awt.*; import java.awt.geom.*; /** Michael Weiss */ public abstract class Uhrzeiger { protected Path2D.Float hatForm; private Color zColor; // Jeder Uhrzeiger wird durch einen Pfad repräsentiert, der in ein Quadrat von 100 Einheiten Seitenlänge // passt, und dessen Koordinatenursprung sich in der Quadratmitte befindet. public Uhrzeiger(Color pColor) { zColor = pColor; hatForm = new Path2D.Float(); } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe, double pWinkel) { AffineTransform lRotation = AffineTransform.getRotateInstance(-pWinkel / * Math.PI); AffineTransform lAffineTransform = new AffineTransform(0.01*pBreite,0,0,-0.01*pHoehe,pH+0.5*pBreite,pV+ 0.5*pHoehe); lAffineTransform.concatenate(lRotation); Path2D.Float lForm_=_ (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); }

25 Ausführung der gesamten Transformation Michael Weiss lAffineTransform.concatenate(lRotation); Path2D.Float lForm = (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); lAffineTransform.concatenate(lRotation); Path2D.Float lForm = (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(zColor); pGraphics2D.fill(lForm); Klonen des Zeigers (erzeugt eine echte Kopie) Transformieren der Kopie Farbe setzen transformierte Kopie zeichnen (fill: ausmalen)

26 Zifferblatt Michael Weiss import java.awt.*; import java.awt.geom.*; /** * Klasse Ziffernblatt: Zeichnet 12 grosse und 48 kleine Uhrstriche. * Gezeichnet wird ein Ziffernblatt, das in ein Quadrat der Seitenlänge * 100 und dem Koordinatenursprung in der Mitte passt. * Michael Weiss */ public class Ziffernblatt { private Path2D.Float hatForm, hatStundenstrich, hatMinutenstrich; public Ziffernblatt() { hatStundenstrich = new Path2D.Float(); hatStundenstrich.moveTo(-0.5,40); hatStundenstrich.lineTo(0.5,40); hatStundenstrich.lineTo(0.5,48); hatStundenstrich.lineTo(-0.5,48); hatStundenstrich.closePath(); hatMinutenstrich = new Path2D.Float(); hatMinutenstrich.moveTo(-0.25,45); hatMinutenstrich.lineTo(0.25,45); hatMinutenstrich.lineTo(0.25,48); hatMinutenstrich.lineTo(-0.25,48); hatMinutenstrich.closePath(); hatForm = new Path2D.Float(); import java.awt.*; import java.awt.geom.*; /** * Klasse Ziffernblatt: Zeichnet 12 grosse und 48 kleine Uhrstriche. * Gezeichnet wird ein Ziffernblatt, das in ein Quadrat der Seitenlänge * 100 und dem Koordinatenursprung in der Mitte passt. * Michael Weiss */ public class Ziffernblatt { private Path2D.Float hatForm, hatStundenstrich, hatMinutenstrich; public Ziffernblatt() { hatStundenstrich = new Path2D.Float(); hatStundenstrich.moveTo(-0.5,40); hatStundenstrich.lineTo(0.5,40); hatStundenstrich.lineTo(0.5,48); hatStundenstrich.lineTo(-0.5,48); hatStundenstrich.closePath(); hatMinutenstrich = new Path2D.Float(); hatMinutenstrich.moveTo(-0.25,45); hatMinutenstrich.lineTo(0.25,45); hatMinutenstrich.lineTo(0.25,48); hatMinutenstrich.lineTo(-0.25,48); hatMinutenstrich.closePath(); hatForm = new Path2D.Float(); Mit der selben Technik lässt sich auch ein Zifferblatt zeichnen. Dazu wird das ursprüngliche Bild eines senkrechten Ziffernstrichs 11- resp. 48-mal gedreht und jeweils in ein- und dasselbe Path2D.float-Objekt aufgenommen.

27 Zifferblatt (Forts.) Michael Weiss int h = 0; while(h < 12) { Path2D.Float lStundenstrich = (Path2D.Float)(hatStundenstrich.clone()); AffineTransform lRotation = AffineTransform.getRotateInstance(-h * 30.0 / * Math.PI); lStundenstrich.transform(lRotation); hatForm.append(lStundenstrich, false); h++; } int m = 1; while(m < 60) { if(m % 5 != 0) { Path2D.Float lMinutenstrich = (Path2D.Float)(hatMinutenstrich.clone()); AffineTransform lRotation = AffineTransform.getRotateInstance(-m * 6.0 / 180.0* Math.PI); lMinutenstrich.transform(lRotation); hatForm.append(lMinutenstrich, false); } m++; } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe) { AffineTransform lAffineTransform = new AffineTransform(0.01 * pBreite, 0, 0, * pHoehe, pH + 0.5*pBreite, pV + 0.5*pHoehe); Path2D.Float lForm = (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(Color.BLACK); pGraphics2D.fill(lForm); } int h = 0; while(h < 12) { Path2D.Float lStundenstrich = (Path2D.Float)(hatStundenstrich.clone()); AffineTransform lRotation = AffineTransform.getRotateInstance(-h * 30.0 / * Math.PI); lStundenstrich.transform(lRotation); hatForm.append(lStundenstrich, false); h++; } int m = 1; while(m < 60) { if(m % 5 != 0) { Path2D.Float lMinutenstrich = (Path2D.Float)(hatMinutenstrich.clone()); AffineTransform lRotation = AffineTransform.getRotateInstance(-m * 6.0 / 180.0* Math.PI); lMinutenstrich.transform(lRotation); hatForm.append(lMinutenstrich, false); } m++; } public void zeichne(Graphics2D pGraphics2D, int pH, int pV, int pBreite, int pHoehe) { AffineTransform lAffineTransform = new AffineTransform(0.01 * pBreite, 0, 0, * pHoehe, pH + 0.5*pBreite, pV + 0.5*pHoehe); Path2D.Float lForm = (Path2D.Float)(hatForm.clone()); lForm.transform(lAffineTransform); pGraphics2D.setColor(Color.BLACK); pGraphics2D.fill(lForm); }

28 Dargestellte Zeit einstellen Michael Weiss /** * Speichere die Zeit in Stunden, Minuten * und Sekunden und * berechne die Winkel der drei Uhrzeiger. * Michael Weiss */ public class Zeit { private int zStd, zMin; private double zSek; public Zeit(int pStd, int pMin, double pSek) { zStd = pStd; zMin = pMin; zSek = pSek; } /** * Speichere die Zeit in Stunden, Minuten * und Sekunden und * berechne die Winkel der drei Uhrzeiger. * Michael Weiss */ public class Zeit { private int zStd, zMin; private double zSek; public Zeit(int pStd, int pMin, double pSek) { zStd = pStd; zMin = pMin; zSek = pSek; } Wir benutzen eine Klasse, welche sich eine Zeit merken kann und diese in die Winkeleinstellungen der drei Uhrzeiger umrechnen kann. public double winkelStundenzeiger() { return zStd * 30 + zMin * zSek * 0.5 / 60.0; } public double winkelMinutenzeiger() { return zMin * 6 + zSek * 0.1; } public double winkelSekundenzeiger() { return zSek * 6; } public double winkelStundenzeiger() { return zStd * 30 + zMin * zSek * 0.5 / 60.0; } public double winkelMinutenzeiger() { return zMin * 6 + zSek * 0.1; } public double winkelSekundenzeiger() { return zSek * 6; }

29 Dargestellte Zeit einstellen Michael Weiss /** * Speichere die Zeit in Stunden, Minuten * und Sekunden und * berechne die Winkel der drei Uhrzeiger. * Michael Weiss */ public class Zeit { private int zStd, zMin; private double zSek; public Zeit(int pStd, int pMin, double pSek) { zStd = pStd; zMin = pMin; zSek = pSek; } /** * Speichere die Zeit in Stunden, Minuten * und Sekunden und * berechne die Winkel der drei Uhrzeiger. * Michael Weiss */ public class Zeit { private int zStd, zMin; private double zSek; public Zeit(int pStd, int pMin, double pSek) { zStd = pStd; zMin = pMin; zSek = pSek; } Wir benutzen eine Klasse, welche sich eine Zeit merken kann und diese in die Winkeleinstellungen der drei Uhrzeiger umrechnen kann. public double winkelStundenzeiger() { return zStd * 30 + zMin * zSek * 0.5 / 60.0; } public double winkelMinutenzeiger() { return zMin * 6 + zSek * 0.1; } public double winkelSekundenzeiger() { return zSek * 6; } public double winkelStundenzeiger() { return zStd * 30 + zMin * zSek * 0.5 / 60.0; } public double winkelMinutenzeiger() { return zMin * 6 + zSek * 0.1; } public double winkelSekundenzeiger() { return zSek * 6; } Erzeugt wird sie innerhalb der Klasse Uhr: hatZeit = new Zeit(13,50,22);

30 Dargestellte Zeit einstellen (2) Michael Weiss Damit das ZeichenJPanel die Uhrzeit nutzen kann, erzeugen wir eine Getter-Methode: public Zeit zeit() { return hatZeit; } public Zeit zeit() { return hatZeit; } Zudem übergeben wir dem ZeichenJPanel im Konstruktor einen Verweis auf die Klasse Uhr, so dass das ZeichenJPanel später die Methode zeit() der Klasse Uhr aufrufen kann: hatUhrZeichenJPanel = new ZeichenJPanel(this); Entsprechend bekommt die Klasse ZeichenJPanel einen geänderten Konstruktor: public class ZeichenJPanel extends JPanel { private Uhrzeiger hatSekundenzeiger, hatMinutenzeiger, hatStundenzeiger; private Ziffernblatt hatZiffernblatt; private Uhr kenntUhr; public ZeichenJPanel(Uhr pUhr) { hatZiffernblatt = new Ziffernblatt(); hatSekundenzeiger = new Sekundenzeiger(); hatMinutenzeiger = new Minutenzeiger(); hatStundenzeiger = new Stundenzeiger(); kenntUhr = pUhr; } public class ZeichenJPanel extends JPanel { private Uhrzeiger hatSekundenzeiger, hatMinutenzeiger, hatStundenzeiger; private Ziffernblatt hatZiffernblatt; private Uhr kenntUhr; public ZeichenJPanel(Uhr pUhr) { hatZiffernblatt = new Ziffernblatt(); hatSekundenzeiger = new Sekundenzeiger(); hatMinutenzeiger = new Minutenzeiger(); hatStundenzeiger = new Stundenzeiger(); kenntUhr = pUhr; }

31 protected void paintComponent(Graphics pGraphics) { // damit die Buttons, Slider, Labels etc. weiterhin gezeichnet werden, // rufen wir als erstes paintComponent() der Überklasse auf. super.paintComponent(pGraphics); Graphics2D kenntGraphics2D = (Graphics2D)pGraphics; // ab hier zeichnen wir selbst. int xmin = 0, width = 0, ymin = 0, height = 0; if(this.getWidth() > this.getHeight()) { height = this.getHeight() - 10; ymin = 5; xmin = (this.getWidth() - height) / 2; width = height; } else { width = this.getWidth() - 10; xmin = 5; ymin = (this.getHeight() - width) / 2; height = width; } kenntGraphics2D.setColor(Color.BLACK); kenntGraphics2D.setStroke(new BasicStroke(width / 100)); kenntGraphics2D.drawOval(xmin, ymin, width, height); hatZiffernblatt.zeichne(kenntGraphics2D, xmin, ymin, width, height); Zeit lZeit = kenntUhr.zeit(); hatStundenzeiger.zeichne(kenntGraphics2D, xmin, ymin, width, height, lZeit.winkelStundenzeiger()); hatMinutenzeiger.zeichne(kenntGraphics2D, xmin, ymin, width, height, lZeit.winkelMinutenzeiger()); hatSekundenzeiger.zeichne(kenntGraphics2D, xmin, ymin, width, height, lZeit.winkelSekundenzeiger()); } protected void paintComponent(Graphics pGraphics) { // damit die Buttons, Slider, Labels etc. weiterhin gezeichnet werden, // rufen wir als erstes paintComponent() der Überklasse auf. super.paintComponent(pGraphics); Graphics2D kenntGraphics2D = (Graphics2D)pGraphics; // ab hier zeichnen wir selbst. int xmin = 0, width = 0, ymin = 0, height = 0; if(this.getWidth() > this.getHeight()) { height = this.getHeight() - 10; ymin = 5; xmin = (this.getWidth() - height) / 2; width = height; } else { width = this.getWidth() - 10; xmin = 5; ymin = (this.getHeight() - width) / 2; height = width; } kenntGraphics2D.setColor(Color.BLACK); kenntGraphics2D.setStroke(new BasicStroke(width / 100)); kenntGraphics2D.drawOval(xmin, ymin, width, height); hatZiffernblatt.zeichne(kenntGraphics2D, xmin, ymin, width, height); Zeit lZeit = kenntUhr.zeit(); hatStundenzeiger.zeichne(kenntGraphics2D, xmin, ymin, width, height, lZeit.winkelStundenzeiger()); hatMinutenzeiger.zeichne(kenntGraphics2D, xmin, ymin, width, height, lZeit.winkelMinutenzeiger()); hatSekundenzeiger.zeichne(kenntGraphics2D, xmin, ymin, width, height, lZeit.winkelSekundenzeiger()); } Dargestellte Zeit einstellen (3) Michael Weiss Und auch paintComponent() ändert sich noch ein wenig:

32 Fertig? Michael Weiss Die Benutzeroberfläche ist nun fertig. Das Programm reagiert jedoch noch auf keine Benutzereingaben! Diese so genannte Ereignisverarbeitung behandeln wir später.


Herunterladen ppt "Benutzeroberflächen mit Java 4.1.20111Michael Weiss."

Ähnliche Präsentationen


Google-Anzeigen