2011-09-21 59 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()來清除面板,然後在新的時間繪製時鐘。