开发者

Repainting in Swing JComponent after an interval

开发者 https://www.devze.com 2023-04-06 07:04 出处:网络
I have been assigned a project where I have to make an analog clock using the GregorianCalendar object in java.First, we were told to get the clock working, so that it shows the proper time on each ru

I have been assigned a project where I have to make an analog clock using the GregorianCalendar object in java. First, we were told to get the clock working, so that it shows the proper time on each run. Then we were told to make the clock redraw for every second that it is running. I made a timer object and thought I could add an ActionListener and have it repaint every time actionPerformed was invoked, but repaint obviously can't be used in this way. Here's my code:

    import javax.swing.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    import java.awt.*;
    import java.util.Calendar;
    import java.util.GregorianCalendar;
    import java.util.Date;
    import javax.swing.Timer;
    import java.lang.Math;    

    public class SwingClock {

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                MyFrame frame = new MyFrame();
                frame.setDef开发者_运维技巧aultCloseOperation(JFrame.EXIT_ON_CLOSE);
                ActionListener listener = new TimePrinter();
                Timer t = new Timer(1000, listener);
                GregorianCalendar calendar = new GregorianCalendar();
                t.start();
                frame.setVisible(true);
            }
        });
    }
}

    class TimePrinter implements ActionListener
    {
        public void actionPerformed(ActionEvent event)
        {
            //I'd like to repaint here every second, but I can't
        }
    }

    class MyFrame extends JFrame
    {
        public MyFrame()
        {
            setTitle("Swing Clock");
            setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

            MyComponent component = new MyComponent();
            add(component);
        }

        public static final int DEFAULT_WIDTH = 500;
        public static final int DEFAULT_HEIGHT = 500;
    }

    class MyComponent extends JComponent
    {
        public void paint(Graphics g)
        {
            Graphics2D g2 = (Graphics2D)g;
            int leftX = 50, topY = 50, width = 300, height = 300;
            Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height);

            Ellipse2D clockFace = new Ellipse2D.Double();
            clockFace.setFrame(rect);
            g2.draw(clockFace);

            double centerX = clockFace.getCenterX();
            double centerY = clockFace.getCenterY();
            GregorianCalendar calendar = new GregorianCalendar();
            int hour = calendar.get(Calendar.HOUR_OF_DAY);

            int minute = calendar.get(Calendar.MINUTE);
            int second = calendar.get(Calendar.SECOND);

            double minusMinute = (90 - (minute*6))*(Math.PI/180);           
            double minuteCosine = Math.cos(minusMinute);
            double minuteSine = Math.sin(minusMinute);

            double minusSecond = (90 - (second*6))*(Math.PI/180);
            double secondCosine = Math.cos(minusSecond);
            double secondSine = Math.sin(minusSecond);

            double hourTheta = (90-(hour+(minute/60)*30))*(Math.PI/180);
            g2.draw(new Line2D.Double(centerX,centerY,centerX+50*(Math.cos(hourTheta)),
                    centerY - 50*(Math.sin(hourTheta))));   
            g2.draw(new Line2D.Double(centerX,centerY,centerX+150*(minuteCosine),centerY-150*(minuteSine)));
        g2.draw(new Line2D.Double(centerX, centerY, centerX+100*secondCosine, 
                    centerY-100*(secondSine)));
        }
    }

Any ideas on how to get around this? Maybe I'm going about it wrong?


"Swing programs should override paintComponent() instead of overriding paint()," although as you will see, this is not necessary at all. Second of all, you're right in using javax.swing.Timer. Third of all, why don't you make it easy on yourself and use a JLabel instance to display the time instead?


  1. MyComponent should be defined as a class variable in your MyFrame class

  2. The Timer should be created and started in your MyFrame class.

  3. The ActionListener for the Timer should invoke repaint on your MyComponent variable.

  4. Your MyComponent class should extend JPanel, then you can just invoke super.paintComponent() as the first statement to clear the panel before drawing the clock at its new time.


You just override constructor of Listener:

class TimePrinter implements ActionListener

{
    private MyFrame frame;
    TimePrinter(MyFrame frame){
        this.frame=frame;
    }
    public void actionPerformed(ActionEvent event)
    {
        frame.repaint();
    }
}


MyFrame frame = new MyFrame();
ActionListener listener = new TimePrinter(frame);
0

精彩评论

暂无评论...
验证码 换一张
取 消