Einführung Inhaltsverzeichnis 2. Darstellung von Variablen und Werten

2. Alternative Anzeige

Eine Uhr kann auch eine kreisförmige Anzeige haben. Die folgende Uhr zeigt die Zeit analog an:

Kreisuhr

Weil hier die Uhrzeit auf zwei verschiedene Weise (analog und digital) angezeigt wird, ist es zweckdienlich, sie nur einmal zu berechnen und in einem (immutablen) Objekt Uhrzeit zu speichern. Darüber hinaus programmieren wir jetzt die Steuerung der Uhr nicht mit Knöpfen sondern mit der Tastatur: A hält die Uhr an, E schaltet sie wieder ein und U schaltet die Taktfrequenz zwischen 1 und 3 Sekunden um:

public class KreisUhr extends JFrame { // KreisUhr.java

   private static final String TITEL = "Kreisuhr", INFO = "Tasten: A(usschalten), E(inschalten), U(mschalten); Takt = ";

   private static final long FREQUENZ = 1000, FREQUENZ_UM = 3000; // 1 bzw. 3 sec

   private static final int BREITE = 400, HÖHE = 300, // Größe des Frames

     ZENTRUM_X = BREITE / 2, ZENTRUM_Y = HÖHE / 2, // des Kreises

     RADIUS = 100, DURCHMESSER = 2 * RADIUS, // des Kreises

     POS_INFO_X = 20, POS_INFO_Y = 40, POS_UHRZEIT = 60; // Position der Texte

   private static final int[] ZEIGERLÄNGE = new int[] { 5*RADIUS/10, 6*RADIUS/10, 7*RADIUS/10 }; // Längen der 3 Zeiger

   private static final Color[] ZEIGERFARBE = new Color[] { Color.red, Color.green, Color.blue }; // Farben der 3 Zeiger

   private static final Color HINTERGRUND_FARBE = Color.white, KREIS_FARBE = Color.black;

   private static class Uhrzeit {

     private int stunde, minute, sekunde;     

     public Uhrzeit(int stunde, int minute, int sekunde) {

        this.stunde = stunde;

        this.minute = minute;

        this.sekunde = sekunde; }

     public int getStunde() { return stunde; }

     public int getMinute() { return minute; }

     public int getSekunde() { return sekunde; } }  

   private Uhrzeit uhrzeit;

   private boolean uhrAn;

   private long frequenz;

   public KreisUhr() {

     uhrAn = true;

     frequenz = FREQUENZ;

     tick(); // uhrzeit wird initialisiert

     setTitle(TITEL);

     setSize(BREITE, HÖHE); setVisible(true);

     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

     this.addKeyListener(new KeyAdapter() {

        @Override

        public void keyPressed(KeyEvent e) {

           switch (Character.toUpperCase(e.getKeyChar())) {

              case 'E': uhrAn = true; break; // "Ein"

              case 'A': uhrAn = false; break; // "Aus"

              case 'U': frequenz = frequenz == FREQUENZ ? FREQUENZ_UM : FREQUENZ; }

           repaint(); } });

     new Thread() {

        @Override

        public void run() {

           try {

              while (true) {

                Thread.sleep(frequenz);

                tick(); } }

           catch (InterruptedException e) { } } }.start(); }

   private void tick() {

     if (!uhrAn)

        return;

     Calendar kalender = Calendar.getInstance();

     uhrzeit = new Uhrzeit(kalender.get(Calendar.HOUR),

        kalender.get(Calendar.MINUTE),

        kalender.get(Calendar.SECOND));

     repaint(); }

   // Anfangspunkt für jeden Zeiger ist Mittelpunkt des Kreises

   private static final int[][] endX = new int[3][60], endY = new int[3][60];

   // Endpunkte der 3 Zeiger pro Minute - Jeder Endpunkt wird nur einmal berechnet

   private static final double zweiPi = 2 * Math.PI;

   private static final double[] KONST = // für die Berechnung der 3 Endpunkte

     new double[] { zweiPi/12, zweiPi/60, zweiPi/60 };

   @Override // Frame

   public void paint(Graphics g) {

     g.clearRect(0, 0, BREITE, HÖHE);

     g.setColor(HINTERGRUND_FARBE);

     g.fillRect(0, 0, BREITE, HÖHE);

     g.setColor(KREIS_FARBE);

     g.drawOval((BREITE - DURCHMESSER) / 2, (HÖHE - DURCHMESSER) / 2, DURCHMESSER, DURCHMESSER); // Kreis

     final int[] zeit = new int[] { uhrzeit.getStunde(), uhrzeit.getMinute(), uhrzeit.getSekunde() } ;

     g.drawString(INFO + (uhrAn ? frequenz/1000 : 0), POS_INFO_X, POS_INFO_Y);

     g.drawString(String.format("%02d:%02d:%02d", zeit[0], zeit[1], zeit[2]), POS_INFO_X, POS_UHRZEIT); // Uhrzeit digital

     for (int i = 0; i < endX.length; i++) { // für jeden Zeiger

        final int z = zeit[i]; // Stunde, Minute oder Sekunde

        if (endX[i][z] == 0) { // wurde noch nicht berechnet

           final double grad = z * KONST[i];                             

           endX[i][z] = (int)(ZENTRUM_X + ZEIGERLÄNGE[i] * Math.sin(grad));

           endY[i][z] = (int)(ZENTRUM_Y - ZEIGERLÄNGE[i] * Math.cos(grad)); }

        g.setColor(ZEIGERFARBE[i]);

        g.drawLine(ZENTRUM_X, ZENTRUM_Y, endX[i][zeit[i]], endY[i][zeit[i]]); } }

   public static void main(String[] args) {

     new KreisUhr(); } }

Einige Programmteile (wie die Thread-Initialisierung) haben wir hier unverändert vom DigitalUhr übernommen; andere (insbesondere die Anzeige) haben wir neu programmiert. Hierbei zeichnen wir mit drawOval() das Kreisblatt, anschließend schreiben wir mit drawString() die Uhrzeit digital auf die Fläche. Anschließend zeichnen wir mit drawLine() die drei Zeiger. Ihre Anfangspunkte liegen im Zentrum des Kreises, aber die Endpunkte zu berechnen ist aufwändig (sin() und cos(), abhängig von der aktuellen Uhrzeit). Um die wiederholte Berechnung zu ersparen, speichern wir die berechneten Endpunkte in den Reihungen (arrays) endX und endY. Um diese in einer Schleife für alle drei Zeiger programmieren zu können, definieren wir ihre Eigenschaft-Konstanten wie ZEIGERLÄNGE und ZEIGERFARBE in Reihungen; so auch die Konstanten KONST, die für die Berechnung der Endpunkte aus der Uhrzeit (gespeichert in der Reihung zeit) notwendig sind.

Das Entwurfsmuster MVC

Einführung Inhaltsverzeichnis 2. Darstellung von Variablen und Werten


Version: 19. April 2012

© Prof. Solymosi, 20102 Beuth-Hochschule für Technik Berlin, Fachbereich VI (Informatik und Medien)

solymosibht-berlin.de