Table of Contents
Wątki - zegar
Wątek to program sekwencyjny, który może być wykonywany współbieżnie z innymi wątkami.
- Wykonywany kod umieszczamy w metodzie
run()
- Wątki uruchamiamy wywołując metodę
start()
- Wątki kończą działanie po wyjściu z metody
run()
Uwaga - wywołanie
run()
wykona funkcję, ale nie jako osobny wątek.
Zegar na konsoli - wątek Clock
Zadeklaruj klasę Clock
public class Clock extends Thread{ @Override public void run() { } public static void main(String[] args) { new Clock().start(); } }
Kod wykonywany przez wątek
Następnie w metodzie run()
- dodaj pętlę nieskończoną
- w pętli odczytuj i drukuj bieżący czas
LocalTime time = LocalTime.now(); System.out.printf("%02d:%02d:%02d\n", time.getHour(), time.getMinute(), time.getSecond());
Usypianie wątku
Prawdopodobnie ten sam czas drukuje się wielokrotnie.
Uśpij wątek na jedną sekundę (1000 milisekund) wprowadzając wywołanie metody sleep()
Zegar z GUI
Zaimplementujemy zegar analogowy wyświetlający (i przesuwający wskazówki).
- Zegar będzie rysowany wewnątrz klasy
ClockWithGui
dziedziczącej poJPanel
. - W funkcji
main()
utworzona zostanie ramka, dodany do niej panel, itd
public class ClockWithGui extends JPanel { LocalTime time = LocalTime.now(); public static void main(String[] args) { JFrame frame = new JFrame("Clock"); frame.setContentPane(new ClockWithGui()); frame.setSize(700, 700); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(true); frame.setVisible(true); } }
Rysujemy tarczę
Kod umieszczamy w paintComponent()
Poniżej przykład rysowania cyfr na tarczy.
- tworzymy macierz przekształcenia afinicznego (powinowactwa)
- definiujemy obrót o wielokrotność
360/12
stopni - wyznaczamy obraz punktu w przekształceniu.
- Ten punkt ma współrzędne (0,-120). Wartość 120 to promień, znak minus bo współrzędne
y
rosną w dół. Lokalizacja cyfr nie jest idealna, warto odjąć od x (przed przekształceniem) szerokość tekstu. Jeszcze lepiej zrealizowana metoda powinna odczytać wymiary tekstu dla danej czcionki.
public void paintComponent(Graphics g){ Graphics2D g2d=(Graphics2D)g; g2d.translate(getWidth()/2,getHeight()/2); for(int i=1;i<13;i++){ AffineTransform at = new AffineTransform(); at.rotate(2*Math.PI/12*i); Point2D src = new Point2D.Float(0,-120); Point2D trg = new Point2D.Float(); at.transform(src,trg); g2d.drawString(Integer.toString(i),(int)trg.getX(),(int)trg.getY()); } }
Gdyby ktoś potrzebował inspiracji - można zajrzeć na kod rysujący tarczę zegara w JavaScript.
Kontekst graficzny
ctx
w JavaScript jest analogiem Grapics2D w bibliotece Swing. Transformacje afiniczne mają podobną postać…
Rysujemy wskazówki
Tak możemy narysować jedną ze wskazówek (godzinową)…
Ale popraw poniższy kod, ponieważ położenie wskazówek na ogół nie zmienia się skokowo np. przy zmianie z 11:59:59 na 12:00:00.
AffineTransform saveAT = g2d.getTransform(); g2d.rotate(time.getHour()%12*2*Math.PI/12); g2d.drawLine(0,0,0,-100); g2d.setTransform(saveAT);
Możesz zmienić kształt (np. narysować wielobok) lub użyć pogrubienia g2d.setStroke(new BasicStroke(???, CAP_ROUND,JOIN_MITER))
Kreski na tarczy
Dorysuj samodzielnie…
Animacja wskazówek
W klasie ClockWithGui
zadeklaruj klasę wewnętrzną będącą wątkiem.
class ClockThread extends Thread{ @Override public void run() { for(;;){ time = LocalTime.now(); System.out.printf("%02d:%02d:%02d\n",time.getHour(),time.getMinute(),time.getSecond()); //sleep(1000); repaint(); } } }
- Dlaczego w
ClockThread
możliwy jest dostęp do atrybututime
? - Za co odpowiada metoda
repaint()
? Jest to metoda wątku czy JPanel?