Java 模拟时钟

Java analogue clock

我正在尝试在 java 中实现一个简单的模拟时钟。我的时钟成功显示了我第一次 运行 程序的时间,但是在打开时时间保持不变并且 none 绘图更新并冻结。我不明白为什么它不起作用,我浏览了论坛,试图找到有类似问题但找不到的人。如果有人能找到我哪里出错了,我将不胜感激,谢谢

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing. JPanel;

public class ClockFace extends JPanel {

Date date = new Date();

private BufferedImage clockFace;

public ClockFace() {

    this.init();
    this.startClock();

}

private void init() {

    JFrame window = new JFrame("Clock");
    window.setContentPane(this);

    this.setPreferredSize(new Dimension(600,600));

    window.pack();
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setVisible(true);
    window.setLocationRelativeTo(null);

}

//Draws the image to the ClockFace panel
public void paintComponent(Graphics g) {

    Graphics2D twoD = (Graphics2D) g;
    twoD.drawImage(clockFace, 0, 0, null);

}

public void startClock() {

    while(true) {

        int seconds = date.getSeconds();
        int minutes = date.getMinutes();
        int hours = date.getHours();

        clockFace = new BufferedImage(600,600,BufferedImage.TYPE_INT_ARGB);
        Graphics2D twoD = clockFace.createGraphics();
        twoD.setColor(Color.BLACK);
        twoD.fillRect(0, 0, 600, 600);
        twoD.setColor(Color.WHITE);
        twoD.translate(300,300);

        //Drawing the hour markers
        for(int i=0; i<12; i++) {

            twoD.drawLine(0, -260, 0, -300);
            twoD.rotate(Math.PI/6);

        }

        twoD.rotate(seconds*Math.PI/30);
        twoD.drawLine(0, 0, 0, -290);

        twoD.rotate(2*Math.PI-seconds*Math.PI/30);
        twoD.rotate(minutes*Math.PI/30);
        twoD.setStroke(new BasicStroke(3));
        twoD.drawLine(0, 0, 0, -250);

        twoD.rotate(2*Math.PI-minutes*Math.PI/30);
        twoD.rotate(hours*Math.PI/6);
        twoD.setStroke(new BasicStroke(6));
        twoD.drawLine(0, 0, 0, -200);

        repaint();

        //Pausing until the next "tick"
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

}

在 while(true) 之后插入 date 的计算。

这不是编写执行按时间增量安排的任务的程序的方法。它只会解决您眼前的问题。查看其他答案。

您正在阻塞事件调度线程,阻止它处理任何新的输入事件或处理任何新的绘制事件

有关详细信息,请参阅 Concurrency in Swing

所以不是...

public void startClock() {
    while(true) {
       //...
    }
}

你应该使用更像...

public void startClock() {
    Timer timer = new Timer(500, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent evt) {
            //... Update time and schedule repaint
        }
    }
}

有关详细信息,请参阅 How to Use Swing Timers

你也会发现这个...

//Draws the image to the ClockFace panel
public void paintComponent(Graphics g) {

    Graphics2D twoD = (Graphics2D) g;
    twoD.drawImage(clockFace, 0, 0, null);

}

给你问题(油漆人工制品)。应该是..

//Draws the image to the ClockFace panel
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D twoD = (Graphics2D) g;
    twoD.drawImage(clockFace, 0, 0, null);

}

已更新...

关于核心问题的讨论(太多)与事件调度线程的潜在阻塞或 Date class 的 non-mutable 性质有关。

事实是,很可能两者都是。

java.util.Date是一个时间点的快照(创建时),它不会改变也不会更新。因此,根据您的示例,您必须在循环的每次迭代中更新 date 实例。

更好的解决方案可能是使用 java.time.LocalTime,除了更多 up-to-date,它通常更易于使用(恕我直言)

例如...

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.time.LocalTime;
import java.time.temporal.TemporalField;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new ClockFace());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ClockFace extends JPanel {

        public ClockFace() {
            this.startClock();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(600, 600);
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g.create();

            LocalTime now = LocalTime.now();
            int seconds = now.getSecond();
            int minutes = now.getMinute();
            int hours = now.getHour();

            g2d.setColor(Color.BLACK);
            g2d.fillRect(0, 0, 600, 600);
            g2d.setColor(Color.WHITE);
            g2d.translate(300, 300);

            //Drawing the hour markers
            for (int i = 0; i < 12; i++) {

                g2d.drawLine(0, -260, 0, -300);
                g2d.rotate(Math.PI / 6);

            }

            g2d.rotate(seconds * Math.PI / 30);
            g2d.drawLine(0, 0, 0, -290);

            g2d.rotate(2 * Math.PI - seconds * Math.PI / 30);
            g2d.rotate(minutes * Math.PI / 30);
            g2d.setStroke(new BasicStroke(3));
            g2d.drawLine(0, 0, 0, -250);

            g2d.rotate(2 * Math.PI - minutes * Math.PI / 30);
            g2d.rotate(hours * Math.PI / 6);
            g2d.setStroke(new BasicStroke(6));
            g2d.drawLine(0, 0, 0, -200);

            g2d.dispose();
        }

        public void startClock() {
            Timer timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    repaint();
                }
            });
            timer.start();
        }

    }

}