2013-02-13 68 views
3

我試圖用直徑顯示兩個旋轉輪512untis以不同的速度,但我不能刪除以前繪製圖像的圖形,並在正確的位置設置旋轉圖形。 現在我正在做一個任意角度的旋轉。 我試過的AffineTransform,得到了輪換,但是這件事很奇怪像流傳了所有像素。 Im使用while循環與thread.sleep()。以下是代碼:// 的drawSmallCircle和drawBigCircle返回兩個圖像。圖像不正確的位置旋轉(圖形)後

class MyFramePart2 extends JFrame 

{ 

    String name; 
    JPanel big_obj_panel,small_obj_panel;  
    JLabel bigLabel,smallLabel;BufferedImage imgRet,imgRetSmall; 
    static double radians,angle,rev,fps,smallAngle,smallRadians;    
    int numLines,i=0;  

    MyFramePart2(String frameName,int numStrokes,double revolutions,double frameps) 
    {  
     numLines=numStrokes; 
     smallAngle=smallRadians=angle=radians=Math.toRadians(360/numLines);   
     rev=revolutions; 
     fps=frameps; 

     setSize(1240,720);  
     setLocation(0,0); 
     setLayout(null); 
     getContentPane().setBackground(Color.WHITE); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     big_obj_panel=new JPanel(); 
     big_obj_panel.setLayout(null); 
     big_obj_panel.setSize(512,512); 
     big_obj_panel.setLocation(100,100); 
     big_obj_panel.setBackground(Color.white); 
     add(big_obj_panel); 


     imgRet=drawBigCircle(); 
     bigLabel = new JLabel(new ImageIcon(imgRet)); 
     bigLabel.setLayout(null);   
     bigLabel.setLocation(0,0); 
     bigLabel.setSize(512,512); 
     bigLabel.setOpaque(true); 
     bigLabel.setBackground(Color.white); 
     big_obj_panel.add(bigLabel); 

     small_obj_panel=new JPanel(); 
     small_obj_panel.setLayout(null); 
     small_obj_panel.setSize(512,512); 
     small_obj_panel.setLocation(700,100); 
     small_obj_panel.setBackground(Color.white); 
     add(small_obj_panel); 

     imgRetSmall=drawSmallCircle(); 

     smallLabel = new JLabel(new ImageIcon(imgRetSmall)); 
     smallLabel.setLayout(null);   
     smallLabel.setLocation(0,0); 
     smallLabel.setSize(512,512); 
     smallLabel.setOpaque(true); 
     smallLabel.setBackground(Color.white); 
     small_obj_panel.add(smallLabel); 

     setVisible(true);    

     while(i!=5) // suppose to be while true, just checking 
     {     
     setVisible(true);   
     bigLabel.setIcon(new ImageIcon(imgRet));   
     smallLabel.setIcon(new ImageIcon(imgRetSmall)); 
     try{ 
     Thread.sleep(10);   
     } 
     catch(Exception e) 
     {} 
     i++;    
    }       
} 

    @Override 
    public void paint(Graphics g) 
    {   
     super.paint(g); 
     Graphics2D g2d=(Graphics2D)g;   
     g2d.translate(256,256); 
     g2d.rotate(Math.toRadians(20));      
     g2d.translate(-256,-256); 
     g2d.drawImage(imgRet,0,0,null); 
     g2d.dispose();   

     super.paint(g); 
     g2d=(Graphics2D)g; 
     g2d.translate(256,256); 
     g2d.rotate(Math.toRadians(30)); 
     g2d.translate(-256,-256);   
     g2d.drawImage(imgRetSmall,0,0,null);   
     g2d.dispose(); 
    } 

    public static BufferedImage drawBigCircle() 
    { 
     BufferedImage img=new BufferedImage(512,512,BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2d=img.createGraphics();     
     g2d.setColor(Color.black); 
     g2d.drawOval(0,0,511,511); 

     Line2D l2d; 
     while(angle <= 2*Math.PI) 
     { 
      l2d=new Line2D.Double(256,256,256+256*Math.cos(angle),256+256*Math.sin(angle)); 
      g2d.draw(l2d); 
      angle=angle+radians; 
     }    
     return img; 
    }   
} 
+2

'的Thread.sleep(10);'不要擋住EDT(事件指派線程) - 這種情況發生時,圖形用戶界面將 '凍結'。而不是調用'Thread.sleep(n)'實現一個Swing'Timer'來重複執行任務,或者一個'SwingWorker'執行長時間運行的任務。有關更多詳細信息,請參見[Swing中的併發](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。 – 2013-02-13 06:58:01

+0

請勿重寫JFrame的paint()方法! – camickr 2013-02-13 16:06:35

回答

2

Swing的第一條規則。不要阻塞事件調度線程。這樣做會使您的應用程序看起來像掛起,並阻止EDT處理任何重新繪製請求。

這意味着,你需要一些方法來安排不阻止EDT

搖擺的

第二條規則的更新。不要從EDT以外的任何線程創建或修改任何UI組件。

一般來說,你應該避免一切覆蓋頂層容器的paint方法類似JFrame,分開,他們不是雙緩衝,這意味着你的畫,因爲它的更新會閃爍。相反,你應該使用Swing容器之一,如JPanel

有很多不同的方法來實現這一點。基本上,在這裏我使用了三個列表,但如果我認真的話,我會創建一個可以保留所有必需信息的對象(圖像,角度和三角洲)

爲了實現實際的動畫,使用了一個javax.swing.Timer。這將觸發一個事件,至少每ñ時期,但更重要的是,它是事件調度線程的上下文中。這確保了角度所做的所有修改的方式,將防止畫,而我們要更新值出現的可能性完成...

這個例子在不同(隨機)旋轉的三幅圖像的速度.. 。

enter image description here

public class TestRotation { 

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

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

       JFrame frame = new JFrame("Test"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new AnimationPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 

     }); 
    } 

    public class AnimationPane extends JPanel { 

     private List<BufferedImage> images; 
     private List<Double> angles; 
     private List<Double> speed; 

     public AnimationPane() { 
      images = new ArrayList<>(5); 
      images.add(createWheel(50, 4)); 
      images.add(createWheel(50, 3)); 
      images.add(createWheel(50, 6)); 
      angles = new ArrayList<>(); 
      speed = new ArrayList<>(); 
      for (int index = 0; index < images.size(); index++) { 
       angles.add(0d); 
       speed.add(Math.random() * 5d); 
      } 

      Timer timer = new Timer(40, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        for (int index = 0; index < angles.size(); index++) { 
         double angle = angles.get(index); 
         double delta = speed.get(index); 
         angle += delta; 
         angles.set(index, angle); 
        } 
        repaint(); 
       } 
      }); 
      timer.setRepeats(true); 
      timer.setCoalesce(true); 
      timer.start(); 

     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      int x = 0; 
      int y = 0; 
      for (int index = 0; index < images.size(); index++) { 
       BufferedImage image = images.get(index); 
       double angle = angles.get(index); 

       // This is important. Basically we going to grab a isolated snap shot 
       // of the current graphics context. This means any changes we make 
       // will not affect the original graphics context (other then painting) 
       Graphics2D g2d = (Graphics2D) g.create(); 
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
       AffineTransform at = new AffineTransform(); 
       at.translate(x, y); 
       at.rotate(Math.toRadians(angle), image.getWidth()/2, image.getHeight()/2); 
       g2d.setTransform(at); 
       g2d.drawImage(image, 0, 0, this); 
       g2d.dispose(); 

       x += image.getWidth(); 

      } 
     } 

    } 

    protected Point2D calculateOutterPoint(int radius, double angel) { 

     int x = Math.round(radius/2); 
     int y = Math.round(radius/2); 

     double rads = Math.toRadians((angel + 90)); 

     // This determins the length of tick as calculate from the center of 
     // the circle. The original code from which this derived allowed 
     // for a varible length line from the center of the cirlce, we 
     // actually want the opposite, so we calculate the outter limit first 
     double fullLength = (radius/2d); 

     // Calculate the outter point of the line 
     double xPosy = (x + Math.cos(rads) * fullLength); 
     double yPosy = (y - Math.sin(rads) * fullLength); 

     return new Point2D.Double(xPosy, yPosy); 

    } 

    public BufferedImage createWheel(int radius, int spokes) { 
     BufferedImage img = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2d = img.createGraphics(); 
     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2d.setColor(Color.black); 
     g2d.drawOval(0, 0, radius - 1, radius - 1); 

     Point2D center = new Point2D.Double(radius/2d, radius/2d); 
     double angle = 360d/spokes; 
     for (int index = 0; index < spokes; index++) { 
      Point2D p = calculateOutterPoint(radius, index * angle); 
      g2d.draw(new Line2D.Double(center, p)); 
     } 

     g2d.dispose(); 
     return img; 

    } 

} 
+0

非常感謝...我會提高自己的揮杆技巧......這是有很大的幫助... – Vizzard 2013-02-13 11:26:54

+1

參見['RotateApp'(http://stackoverflow.com/a/3420651/230513)。 – trashgod 2013-02-13 15:37:16

+0

嗨,現在我試圖通過理解上述程序實際上在兩個矩形內旋轉輻條。我想讓矩形內的輻條旋轉(而不是整個矩形),並將兩個圖像中的每一個像圓形部分一樣並排顯示。我沒有得到這個計算部分,你能幫我解決。 – Vizzard 2013-02-15 03:18:41