Zegar cyfrowy

Wstęp

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.

Etap I – wyświetlamy próbny tekst

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);

}

Etap II – pobieramy bieżący czas i wyświetlamy go

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.

Etap III – wątek uaktualniający czas

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();

Etap IV – zabiegi kosmetyczne

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);