2013-04-19 33 views
2

作爲我的編程任務的一部分,我必須在小程序中顯示旋轉風扇。在小應用程序中顯示旋轉風扇

這裏是我的代碼(類顯示風扇):

import javax.swing.*; 
import java.awt.*; 

public class Fan extends JPanel 
{ 
    private int angle1 = -15; 
    private int angle2 = 75; 
    private int angle3 = 165; 
    private int angle4 = 255; 

    public Fan() 
    { 
     this.setSize(600, 400); 
     Runnable spinner = new SpinFan(); 

     Thread thread1 = new Thread(spinner); 
     thread1.start(); 
    } 


    @Override 
    protected void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 

     g.drawOval(200, 150, 150, 150); 
     g.fillArc(210, 160, 130, 130, angle1, 30); 
     g.fillArc(210, 160, 130, 130, angle2, 30); 
     g.fillArc(210, 160, 130, 130, angle3, 30); 
     g.fillArc(210, 160, 130, 130, angle4, 30); 
    } 
} 

class SpinFan implements Runnable 
{ 
    @Override 
    public void run() 
    { 
     try 
     { 
      while(true) 
      { 
       angle1 = (angle1 + 1) % 360; 
       angle2 = (angle2 + 1) % 360; 
       angle3 = (angle3 + 1) % 360; 
       angle4 = (angle4 + 1) % 360; 

       System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4); 

       repaint(); 

       Thread.sleep(10); 
      } 
     } 
     catch(InterruptedException ex) 
     { 
      System.out.println("Problem while putting thread to sleep."); 
     } 
    } 
} 

類作進一步處理(現在只是有風扇的實例):

import java.awt.*; 
import javax.swing.*; 

public class FanControl extends JPanel 
{ 
    public FanControl() 
    { 
     add(new Fan()); 
    } 
} 

最後,這裏是小程序類:

import java.awt.*; 
import javax.swing.*; 

public class FanApplet extends JApplet 
{ 
    public FanApplet() 
    { 
     add(new FanControl()); 
    } 
} 

現在我一直在嘗試各種各樣的東西很長一段時間所以請不要介意th額外註釋掉代碼。 Fan.jav一個類可以正常工作(如果我將它作爲應用程序放在一個框架中運行,我可以看到風扇旋轉)。但我無法讓愛好者在Applet中旋轉。但是,如果我將類似於JButton的東西添加到Fan.java類的Applet中,它將起作用。

我錯過了什麼?使用線程和小應用程序時是否有一些複雜性,或者我似乎不知道的小應用程序和paintComponent()

當我作爲應用程序運行代碼時,它工作正常。我可以看到旋轉的風扇。下面是該代碼:

import javax.swing.*; 
import java.awt.*; 

public class Fan extends JPanel 
{ 
private int angle1 = -15; 
private int angle2 = 75; 
private int angle3 = 165; 
private int angle4 = 255; 

public Fan() 
{ 
    Runnable spinner = new SpinFan(); 

    Thread thread1 = new Thread(spinner); 
    thread1.start(); 
} 


public static void main(String[] args) 
{ 
    JFrame frame = new JFrame(); 
    frame.add(new Fan()); 
    frame.setSize(600, 400); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setVisible(true); 
} 


@Override 
protected void paintComponent(Graphics g) 
{ 
    super.paintComponent(g); 

    g.drawOval(200, 150, 150, 150); 
    g.fillArc(210, 160, 130, 130, angle1, 30); 
    g.fillArc(210, 160, 130, 130, angle2, 30); 
    g.fillArc(210, 160, 130, 130, angle3, 30); 
    g.fillArc(210, 160, 130, 130, angle4, 30); 

} 

class SpinFan implements Runnable 
{ 
    @Override 
    public void run() 
    { 
     try 
     { 
      while(true) 
      { 
       angle1 = (angle1 - 1) % 360; 
       angle2 = (angle2 - 1) % 360; 
       angle3 = (angle3 - 1) % 360; 
       angle4 = (angle4 - 1) % 360; 

       System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4); 

       repaint(); 

       Thread.sleep(10); 
      } 
     } 

     catch(InterruptedException ex) 
     { 
      System.out.println("Problem while putting thread to sleep."); 
     } 
    } 

} 
} 

回答

2
while(true) .. repaint(); .. Thread.sleep(10); 

這是完全錯誤的方式去動畫。

不要阻塞EDT(Event Dispatch Thread) - 當發生這種情況時GUI將「凍結」。而不是調用Thread.sleep(n)執行重複任務的Swing Timer或長時間運行的任務執行SwingWorker。有關更多詳細信息,請參閱Concurrency in Swing

以下來源使用代碼中定義的Thread,但將GUI更新放回EDT。

但是真正的問題在於,動畫組件被添加到大小爲0x0的小程序中。通過將父容器的佈局更改爲BorderLayout,我們可以將其拉伸以適應可用空間。

E.G.

import java.awt.*; 
import javax.swing.*; 

public class FanApplet extends JApplet 
{ 
    private int angle1 = -15; 
    private int angle2 = 75; 
    private int angle3 = 165; 
    private int angle4 = 255; 

    public FanApplet() 
    { 
     add(new FanControl()); 
    } 

    class FanControl extends JPanel 
    { 
     public FanControl() 
     { 
      // by setting a BorderLayout and adding a component to the CENTER 
      // (default if no constraint specified) the child component will 
      // be stretched to fill the available space. 
      setLayout(new BorderLayout()); 
      add(new Fan()); 
     } 
    } 

    class Fan extends JPanel 
    { 
     public Fan() 
     { 
      //this.setSize(600, 400); 
      Runnable spinner = new SpinFan(); 

      Thread thread1 = new Thread(spinner); 
      thread1.start(); 
     } 


     @Override 
     protected void paintComponent(Graphics g) 
     { 
      super.paintComponent(g); 

      g.drawOval(200, 150, 150, 150); 
      g.fillArc(210, 160, 130, 130, angle1, 30); 
      g.fillArc(210, 160, 130, 130, angle2, 30); 
      g.fillArc(210, 160, 130, 130, angle3, 30); 
      g.fillArc(210, 160, 130, 130, angle4, 30); 
     } 
    } 

    class SpinFan implements Runnable 
    { 
     @Override 
     public void run() 
     { 
      try 
      { 
       while(true) 
       { 
        angle1 = (angle1 + 1) % 360; 
        angle2 = (angle2 + 1) % 360; 
        angle3 = (angle3 + 1) % 360; 
        angle4 = (angle4 + 1) % 360; 

        System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4); 

        // This ensures that repaint() is called on the EDT. 
        Runnable r = new Runnable() { 
         public void run() { 
          repaint(); 
         } 
        }; 
        SwingUtilities.invokeLater(r); 

        Thread.sleep(10); 
       } 
      } 
      catch(InterruptedException ex) 
      { 
       System.out.println("Problem while putting thread to sleep."); 
      } 
     } 
    } 
} 
+0

安德魯,謝謝你的回答。我所做的編程練習要求我使用線程而不是定時器來完成動畫。 我的問題是,如果我將它作爲應用程序而不是applet運行,相同的代碼可以正常工作。現在,如果它作爲一個應用程序運行良好,那麼它爲什麼要作爲一個小程序工作呢? Swing和線程(以及所有這些東西)之間的複雜性在兩種情況下應該是相同的嗎? 查看我編輯的代碼,將其作爲應用程序運行。 謝謝。 – sarora

+0

發佈的applet代碼不在這裏編譯。一旦這是'固定',父母的佈局改變了,我看到了applet中的旋轉扇。還修復了GUI更新以使它們位於EDT上。一定要閱讀鏈接的文章,以便當教師詢問代碼爲什麼執行它時,可以解釋! –

+0

非常感謝你安德魯!我知道了。有用。 :) – sarora

相關問題