2011-09-21 57 views
3

我已经分配了一个项目,我必须使用java中的GregorianCalendar对象制作模拟时钟。首先,我们被告知让时钟工作,以便它在每次运行中显示适当的时间。然后我们被告知让它每秒运行一次。我制作了一个计时器对象,并认为我可以添加一个ActionListener,并在每次调用actionPerformed时重新绘制它,但重绘显然不能以这种方式使用。这是我的代码:在间隔之后重新绘制Swing JComponent

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.setDefaultCloseOperation(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))); 
     } 
    } 

有关如何解决此问题的任何想法?也许我错了?

回答

5

“Swing programs should override paintComponent()”,而不是覆盖paint(),“尽管你会看到,这根本没有必要。其次,您正确使用javax.swing.Timer。第三,为什么不让自己容易一些,并使用JLabel实例来显示时间呢?

+2

恩,你没有那个倒退kemosabe - 他**应该**重写paintComponent,而不是绘画(如果他需要做自定义绘画)? –

+0

我可以使用actionListener以这种方式重绘组件吗? – Tom

+1

@Tom:Swing Timers使用ActionListeners,所以很好,使用ActionListener来更改程序状态,然后在必要时通过调用repaint()来触发重绘。然而,我第二次投票只是改变了JLabel的文本,而不是为了定制绘画而烦恼。 –

0

你只需重写监听器的构造:

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); 
2
  1. MyComponent的应该在MyFrame类

  2. 定时器应创建并在MyFrame类开始被定义为类变量。

  3. Timer的ActionListener应该调用你的MyComponent变量的重绘。

  4. 你的MyComponent类应该扩展JPanel,那么你可以在第一次声明之前调用super.paintComponent()来清除面板,然后在新的时间绘制时钟。