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 po JPanel.
  • 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.

  • 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 atrybutu time?
  • Za co odpowiada metoda repaint()? Jest to metoda wątku czy JPanel?
pz1/watki-zegar.txt · Last modified: 2022/11/25 23:43 by pszwed
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0