Utwórz nowy projekt typu Desktop Application. Nazwij go DigitalClock.
Utwórz nową klasę dziedziczącą po JPanel. Nazwij ją ClockPanel.
Dodaj metodę public void paint(Graphics g){}.
Dodaj instrukcję import. Przekompiluj klasę. Umieść komponent w oknie widoku.
1. Za każdym razem podczas wyświetlania bieżącej godziny na ekranie będziemy wyświetlali napis z wykorzystaniem tego samego fontu. Dlatego, zamiast tworzyć go wielokrotnie w metodzie paint() dodamy atrybut klasy ClockPanel:
Font font = new Font(Font.SANS_SERIF,Font.BOLD,50);
2. W metodzie paint() wyświetlimy próbny napis, np. ”16:23:45”
public void paint(Graphics g){
g.setFont(font);
g.drawString("16:23:45",
20, 100);
}
W metodzie paint() wstawiamy kod, który pobiera aktualny czas i wyświetla go
Calendar
calendar=Calendar.getInstance();
int
hour=calendar.get(Calendar.HOUR);
if(
calendar.get(Calendar.AM_PM)==Calendar.PM)hour+=12;
int
minute=calendar.get(Calendar.MINUTE);
int
second=calendar.get(Calendar.SECOND);
String
t=hour+":"+minute+":"+second;
g.setFont(font);
g.drawString(t, 20, 100);
Niestety, zegar wyświetla czas tylko raz. Zmieniając rozmiary okna można wymusić przerysowanie ekranu i uaktualnić czas, ale chcielibyśmy to zrobić automatycznie.
Aby przerysować ekran, należy wywołać metodę repaint() komponentu. Jeżeli będziemy wołali ją co około 0.5 sekundy zegar będzie wyświetlał w miarę dokładny czas (z jaką dokładnością?).
W tym celu użyjemy wątku, który periodycznie
co około 0.5 sekundy będzie się budził i wywoływał metodę
repaint().
Każdy program zawiera co najmniej jeden wątek (wątek funkcji main). Jeżeli ma ich więcej, wówczas wątki wykonują się
równolegle dzieląc czas procesora. Wszystkie wątki korzystają ze wspólnej
pamięci, ale mają własny stos.
Tworząc własny wątek
deklarujemy klasę, która dziedziczy po klasie Thread,
a następnie przedefiniowujemy metodę run(). Tam umieszczamy całą aktywność
wątku.
Następnie uruchamiamy
wątek, jako podproces naszego programu wołając metodę start().
Metoda run() jest
uruchamiana jednorazowo, watek kończy działanie wraz z końcem metody run().
Dlatego, jeżeli chcemy, aby wątek działał w sposób ciągły w metodzie run()
umieszczamy pętlę nieskończoną:
public void run(){
for(;;){
//
aktywność wątku
}
}
Nasz wątek będzie klasą wewnętrzną.
Klasa wewnętrzna to
klasa zdefiniowana wewnątrz innej klasy (zewnętrznej). Jej obiekt(y) są ściśle powiązane z obiektem
klasy zewnętrznej. Z obiektów klas
wewnętrznej można realizować pełny dostęp do pól i metod obiektu klasy
zewnętrznej. W naszym przypadku dostęp będzie polegał na wywołaniu metody repaint().
Przeczytaj fragment
wykładu o wątkach oraz klasach wewnętrznych.
1. Po tym przydługim objaśnieniu zadanie jest niewielkie. Wewnątrz klasy ClockPanel dodaj klasę wątku:
class ClockThread extends Thread{
public
void run(){
for(;;){
try{
sleep(500);
repaint();
}
catch(Exception e){}
}
}
}
2. Uruchom wątek w konstruktorze ClockPanel dodając instrukcję:
new
ClockThread().start();
1. Podczas działania obserwujesz, że cyfry drukują się na sobie? Zmień panel na nieprzezroczysty, czyli odznacz pole opaque we właściwościach obiektu.
2. Chciałbyś wyświetlać godziny, minuty i sekundy w dwucyfrowych polach. Zamiast automatycznej konwersji liczb na teksty należy skorzystać z opcji formatowania. W metodzie paint() klasy ClockPanel wprowadź fragment kodu:
NumberFormat formatter = new
DecimalFormat("00");
String h
= formatter.format(hour);
String m
= formatter.format(minute);
String s
= formatter.format(second);
String
t=h+":"+m+":"+s;
//String
t=hour+":"+minute+":"+second;
g.setFont(font);
//g.drawString("16:23:45", 20, 100);
g.drawString(t, 20, 100);