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 rysujemy jedną ze wskazówek (godzinową)…
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?