Benutzeroberflächen mit Java

Slides:



Advertisements
Ähnliche Präsentationen
der Universität Oldenburg
Advertisements

der Universität Oldenburg
DVG Einfache Klassen Einfache Klassen. DVG Einfache Klassen 2 Strukturen Beispiel: Personendaten bestehen aus –String name –String vorname.
Ein Beispiel in Java.
Java: Objektorientierte Programmierung
Java2D Richard Göbel.
Indirekte Adressierung
FH-Hof Java 2D - Kontext für Zeichenoperationen Richard Göbel.
Java: Grundlagen der Objektorientierung
Abstrakte Klassen.
Grafische Benutzeroberfläche
Wie überwacht man Objekte im "Alltag" ?. Indem man "Wanzen" an diese anbringt.
Ein Beispiel in Java.
Konstruktoren.
Objekte werden als Adressen (Referenzen) übergeben. Dies führt manchmal zu unerwarteten Ergebnissen...
Polymorphie (Vielgestaltigkeit)
Polymorphie (Vielgestaltigkeit)
Objekte und Arbeitsspeicher
Benötigte Applets Startseite: in HTML-Format Applet auf der Startseite Das Applet, das auf der Startseite geladen wird, wird die vier Buttons und die eine.
Sommersemester 2003 Lars Bernard
Sommersemester 2004 Jan Drewnak Entwicklung und Einsatz von Geosoftware I Praktikum Sitzung 8 Sitzung 8: Zeichnen in Java.
AWT – Detailbetrachtung Java 3D – Seminar im Wintersemester 2002/2003 Christian Schneider.
Einführung in die Programmierung mit Java
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer, Dr. Gerhard Gröger, Dipl.-Ing. D. Dörschlag Einführung in die Programmierung mit Java.
Java-Kurs Grafik Julian Drerup.
Java-Kurs - 7. Übung Besprechung der Hausaufgabe Referenzvariablen
Programmieren mit JAVA
Programmieren mit JAVA
Programmieren mit JAVA Teil V. Grafikausgabe mit JAVA, das AWT Java wurde von Anfang an mit dem Anspruch entwickelt, ein vielseitiges, aber einfach zu.
Vererbung Spezialisierung von Klassen in JAVA möglich durch
1DVG3 - Paint Paint ein Zeichenprogramm. DVG3 - Paint 2 Paint – ein Zeichenprogramm.
1 Animation (Doublepuffering) Vorlesung: Datenverarbeitung Grundlagen 3 Fachbereich II - Mathematik Rolf Heitzenröder.
1DVG3 - anonyme Klassen Anonyme Klassen. DVG3 - anonyme Klassen 2 Syntax new BasisKlasse(Parameterliste) { Modifikationen und Erweiterungen der Basisklasse.
07-GraphischeObjekte Graphische Objekte in EMMA301Paint.
Transformationen 09-Transformationen.
DVG Klassen und Objekte
DVG Einfache Klassen 1 Einfache Klassen. 2DVG Einfache KlassenStrukturen Beispiel: Personendaten bestehen aus String name String name.
© 2002 Dr. Cavelius - Ley - Pohlig - Taulien Step by step zum JFrame 1 Zum JFrame Step by step by step by step by step by step by step by step by.
© 2005 Pohlig GK Informatik K Zum JFrame Step by step by step by step by step by step by step by step by.
© 2006 MPohlig Grundkurs Informatik mit Java 1 JFrame-Vorlage Step by step by step by step by step by step by step by step by.
Verzweigung.
© 2004 Pohlig - Taulien Dokumentation mit JavaDoc.
FH-Hof Java2D - Grundlagen Richard Göbel. FH-Hof Java2D - Funktionen Java2D unterstützt: das Zeichnen von Grafiken die Darstellung von Texten die Darstellung.
Java ohne Kara. Java ohne Kara Ab jetzt: Java ohne Kara Ziel: Erfahrungen sammeln mit ersten Java Programmen.
Programme dokumentieren mit JavaDoc
CuP - Java Elfte Vorlesung Montag, 11. November 2002.
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
Vom Umgang mit Daten. public void myProgram() { int[] saeulenWerte = new int[world.getSizeX()]; for (int i = 0; i < saeulenWerte.length; i++) { saeulenWerte[i]
Variablenkonzept Klassisch, in Java Basistyp
Parameterübergabemechanismen für den Methodenaufruf
CuP - Java Achzehnte (und LETZTE. ) Vorlesung : 1
Learning By Doing Konstruktoren Gleicher Name wie die Klasse Zur Initialisierung des Objekts, insbesondere mit Parametern Wir immer bei der Objekterzeugung.
Programmiervorkurs WS 2014/15 Instanzmethoden
Java-Kurs - 8. Übung Besprechung der Hausaufgabe.
Uhr mit PPT Link Step 1 Step 2 Step 3 Step 4 Step 5
Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.
Java-Kurs - 6. Übung Besprechung der Hausaufgabe
Java-Kurs Übung Benutzeroberflächen und Graphik
© 2005 Pohlig Informatik Jg. 11 mfH Michael Pohlig 1 Zum JFrame Step by step by step by step by step by step by step by step by.
OOP-Begriffe Abstraktion Modellieren Klasse Objekt Attribute Methoden
Java-Kurs Übung Benutzeroberflächen und Graphik Frames (Fenster)
Java-Kurs - 6. Übung Besprechung der Hausaufgabe
Programmierkurs JavaUE 4 Anweisungen und ProgrammeDietrich BolesSeite 1 Programmierkurs Java Dr. Dietrich Boles Teil Imperative Programmierung Unterrichtseinheit.
Java Programme nur ein bisschen objektorientiert.
Vererbung in Java. public abstract class Form { protected int breite; protected int hoehe; protected String farbe; /** * Erzeuge eine Form der Breite.
Venusspiegel und Marsschild
Java-Kurs Übung Grafik in Java - das Abstract Windowing Toolkit
Java-Kurs Übung Klassen und Objekte: Vererbung (Fortsetzung)
Ein schematischer Kirschbaum in Java
Implementieren von Klassen
 Präsentation transkript:

Benutzeroberflächen mit Java Michael Weiss 4.1.2011

Ausgangspunkt JFrame import javax.swing.*; /** * @author Michael Weiss * @version 4.1.2011 */ 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(); Michael Weiss 4.1.2011

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

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

JPanel 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); } Der sichtbare Effekt ist gleich null, daher fügen wir 2 Buttons ein. Michael Weiss 4.1.2011

GridLayout und JButton 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. hatButtonJPanel.setLayout(new GridLayout(2,1)); // Zeilen, Spalten hatPauseJButton = new JButton("Pause"); hatButtonJPanel.add(hatPauseJButton); hatStellenJButton = new JButton("stellen"); hatButtonJPanel.add(hatStellenJButton); 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. Michael Weiss 4.1.2011

Keine Buttons mit Focus... 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. Michael Weiss 4.1.2011

Geschachtelte Layouts 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! Michael Weiss 4.1.2011

Ränder einrichten nicht schlecht! 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! Michael Weiss 4.1.2011

Slider Nun noch ein Schiebebalken zur Einstellung der Geschwindigkeit der Uhr. 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. Michael Weiss 4.1.2011

Slider, verschönert Einige Versuche führen schliesslich auf die folgende Lösung: 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); Das kommt dem erwünschten Aussehen schon recht nahe. Nur die Uhr fehlt noch! Michael Weiss 4.1.2011

In ein JPanel hineinzeichnen 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: import javax.swing.*; import java.awt.*; /** * Ein JPanel um drin zu zeichnen. * * @author Michael Weiss * @version 4.1.2011 */ 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. } Michael Weiss 4.1.2011

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

Wie zeichnet man eine Uhr? Die Uhr sollte ein möglichst grosses Quadrat ausfüllen. Wir bestimmen die Koordinaten dieses Quadrats und beginnen dann mit einem Kreis. // 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); 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. Michael Weiss 4.1.2011

Die Uhrzeiger 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. Michael Weiss 4.1.2011

Der Minutenzeiger y import java.awt.*; import java.awt.geom.*; /** * @author Michael Weiss * @version 5.1.2011 */ 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(); } x hatForm ist vom Typ Path2D.float und kann mehrere Grafikobjekte aufnehmen. Es wird in der Überklasse erzeugt. Der Stundenzeiger sieht praktisch gleich aus. Michael Weiss 4.1.2011

Der Sekundenzeiger y x Michael Weiss 4.1.2011 import java.awt.*; import java.awt.geom.*; /** * @author Michael Weiss * @version 5.1.2011 */ 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); } x Michael Weiss 4.1.2011

Affine Transformation x x y affine Transformation Michael Weiss y 4.1.2011

Erster Schritt: Drehung y y Drehung x x 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. Michael Weiss 4.1.2011

Drehung in Java import java.awt.*; import java.awt.geom.*; /** * @author Michael Weiss * @version 5.1.2011 */ 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 * . Michael Weiss 4.1.2011

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

Berechnung der Transformation 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(xA, yA), B(xB, yB) und C(xC, yC) sowie ihrer Bildpunkte A'(xA', yA'), B'(xB', yB') und C'(xC', yC') 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'(x0+w/2|y0+h/2), B'(x0+w|y0+h/2) und C'(x0+w/2|y0) gegeben. Setzen wir A und A' ein, erhalten wir x0+w/2 = e y0+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. Michael Weiss 4.1.2011

Die Transformation in Java Die Parameter a bis f werden in dieser Reihenfolge dem Konstruktor eines Objekts der Klasse AffineTransform übergeben. import java.awt.*; import java.awt.geom.*; /** * @author Michael Weiss * @version 5.1.2011 */ 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); w h x0 y0 Michael Weiss 4.1.2011

Hintereinanderausführung von Drehung und Koordinatentransformation import java.awt.*; import java.awt.geom.*; /** * @author Michael Weiss * @version 5.1.2011 */ 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); Michael Weiss 4.1.2011

Ausführung der gesamten Transformation 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) Michael Weiss 4.1.2011

Zifferblatt 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. 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. * * @author Michael Weiss * @version 5.1.2011 */ 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(); Michael Weiss 4.1.2011

Zifferblatt (Forts.) int h = 0; while(h < 12) { Path2D.Float lStundenstrich = (Path2D.Float)(hatStundenstrich.clone()); AffineTransform lRotation = AffineTransform.getRotateInstance(-h * 30.0 / 180.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, -0.01 * 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); Michael Weiss 4.1.2011

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

Dargestellte Zeit einstellen Wir benutzen eine Klasse, welche sich eine Zeit merken kann und diese in die Winkeleinstellungen der drei Uhrzeiger umrechnen kann. /** * Speichere die Zeit in Stunden, Minuten * und Sekunden und * berechne die Winkel der drei Uhrzeiger. * * @author Michael Weiss * @version 6.1.2011 */ public class Zeit { private int zStd, zMin; private double zSek;   public Zeit(int pStd, int pMin, double pSek) zStd = pStd; zMin = pMin; zSek = pSek; } public double winkelStundenzeiger() { return zStd * 30 + zMin * 0.5 + 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); Michael Weiss 4.1.2011

Dargestellte Zeit einstellen (2) Damit das ZeichenJPanel die Uhrzeit nutzen kann, erzeugen wir eine Getter-Methode: 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; } Michael Weiss 4.1.2011

Dargestellte Zeit einstellen (3) Und auch paintComponent() ändert sich noch ein wenig: 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()); Michael Weiss 4.1.2011

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