Eine Uhr kann auch eine kreisförmige Anzeige haben. Die
folgende Uhr zeigt die Zeit analog an:
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 {
private
static final String
TITEL = "Kreisuhr",
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.
Version: 19. April 2012
© Prof. Solymosi, 20102 Beuth-Hochschule für Technik Berlin, Fachbereich VI (Informatik und Medien)
solymosibht-berlin.de