2012-05-07 70 views
0

對於我所瞭解的內容,Swing將決定什麼時候需要重新繪製,這可以解釋爲什麼paintComponent()執行兩次。但是我做了睡16ms的,重新繪製的應用程序,睡16毫秒,重新繪製,睡16毫秒,等等:paintComponent paint兩次

while(true) 
{ 
    frame.repaint(); 
    try{Thread.sleep(16)}catch(Exception e){} 
} 

應該在60fps工作。但是,FPS測量程序(如FRAPS)顯示應用程序運行速度爲120fps。所以基本上,應用程序正在做的是:並條機,並條機,睡眠,並條機,並條機,睡眠......我怎樣才能告訴擺動畫每個repaint()電話一幀? (哦,我試過用Timer而不是sleep(),結果是一樣的)。

下面是例如在Oracle教程中找到的SwingPaintDemo。我添加了一個while循環,每16ms重新繪製一次。我還將undecorated設置爲true(這是FRAPS每秒向我顯示實際幀數的唯一方式)。

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

/* 
*************************************************************** 
* Silly Sample program which demonstrates the basic paint 
* mechanism for Swing components. 
*************************************************************** 
*/ 
public class SwingPaintDemo { 

    public static void main(String[] args) { 
     JFrame f = new JFrame("Aim For the Center"); 
     f.addWindowListener(new WindowAdapter() { 
      public void windowClosing(WindowEvent e) { 
       System.exit(0); 
      } 
     }); 
     Container panel = new BullsEyePanel(); 
     panel.add(new JLabel("BullsEye!", SwingConstants.CENTER), BorderLayout.CENTER); 
     f.setUndecorated(true); 
     f.setSize(200, 200); 
     f.getContentPane().add(panel, BorderLayout.CENTER); 
     f.show(); 

     while(true) 
     { 
      f.repaint(); 
      try{Thread.sleep(16);}catch(Exception e){} 
     } 
    } 
} 

/** 
* A Swing container that renders a bullseye background 
* where the area around the bullseye is transparent. 
*/ 
class BullsEyePanel extends JPanel { 

    public BullsEyePanel() { 
     super(); 
     setOpaque(false); // we don't paint all our bits 
     setLayout(new BorderLayout()); 
     setBorder(BorderFactory.createLineBorder(Color.black)); 
    } 

    public Dimension getPreferredSize() { 
     // Figure out what the layout manager needs and 
     // then add 100 to the largest of the dimensions 
     // in order to enforce a 'round' bullseye 
     Dimension layoutSize = super.getPreferredSize(); 
     int max = Math.max(layoutSize.width,layoutSize.height); 
     return new Dimension(max+100,max+100); 
    } 

    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Dimension size = getSize(); 
     int x = 0; 
     int y = 0; 
     int i = 0; 
     while(x < size.width && y < size.height) { 
      g.setColor(i%2==0? Color.red : Color.white); 
      g.fillOval(x,y,size.width-(2*x),size.height-(2*y)); 
      x+=10; y+=10; i++; 
     } 
    } 
} 
+0

爲了更好地幫助越早,請包括[SSCCE(http://www.sscce.org)證實說問題。 – user1329572

+2

[將程序設置爲60FPS,但以120FPS運行?]的完全重複(http://stackoverflow.com/questions/10473637/set-program-to-60fps-but-runs-at-120fps)。 ***不要問同樣的問題兩次!*** –

+0

哈哈我知道它是有點相同,但在這個問題中,我使用計時器,因爲你說設置FPS在60,但它看起來好像它是30 ,因爲它繪製每個幀兩次。所以問題仍然存在,定時器不是解決方案。現在我想知道如何設置paintComponent來繪製一次而不是兩次。 – user1319734

回答

3

1)基本上內部paintComponent()方法不重繪

3)爲今天擺動GUI與Graphics(2D)需要呼籲repaint()

2)搖擺GUI本身調用paintComponent()是必要的時默認使用Swing Timer

4)代碼爲frame.repaint();調用重複的repaint,刪除那個

5)frame.repaint();是有用的方法,如果您add/remove/modify已經可見的JFrame

6)你的意思

enter image description hereenter image description here

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

public class SwingPaintDemo { 

    public static void main(String[] args) { 
     JFrame f = new JFrame("Aim For the Center"); 
     f.addWindowListener(new WindowAdapter() { 

      @Override 
      public void windowClosing(WindowEvent e) { 
       System.exit(0); 
      } 
     }); 
     Container panel = new BullsEyePanel(); 
     panel.add(new JLabel("BullsEye!", SwingConstants.CENTER), BorderLayout.CENTER); 
     f.getContentPane().add(panel, BorderLayout.CENTER); 
     f.pack(); 
     f.setVisible(true); 
    } 
} 

/** 
* A Swing container that renders a bullseye background 
* where the area around the bullseye is transparent. 
*/ 
class BullsEyePanel extends JPanel { 

    public BullsEyePanel() { 
     super(); 
     setOpaque(false); // we don't paint all our bits 
     setLayout(new BorderLayout()); 
     setBorder(BorderFactory.createLineBorder(Color.black)); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     // Figure out what the layout manager needs and 
     // then add 100 to the largest of the dimensions 
     // in order to enforce a 'round' bullseye 
     Dimension layoutSize = super.getPreferredSize(); 
     int max = Math.max(layoutSize.width, layoutSize.height); 
     return new Dimension(max + 100, max + 100); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     Dimension size = getSize(); 
     int x = 0; 
     int y = 0; 
     int i = 0; 
     while (x < size.width && y < size.height) { 
      g.setColor(i % 2 == 0 ? Color.red : Color.white); 
      g.fillOval(x, y, size.width - (2 * x), size.height - (2 * y)); 
      x += 10; 
      y += 10; 
      i++; 
     } 
    } 
} 

編輯,有什麼錯@trashgod代碼鏈接在你之前的問題中,大約有JPanel's repaintthis.repaint()

enter image description here

import java.awt.*; 
import java.awt.event.*; 
import java.awt.image.BufferedImage; 
import java.util.Random; 
import javax.swing.*; 

/** @see http://stackoverflow.com/questions/3256941 */ 
public class AnimationTest extends JPanel implements ActionListener { 

    private static final int WIDE = 640; 
    private static final int HIGH = 480; 
    private static final int RADIUS = 25; 
    private static final int FRAMES = 24; 
    private static final long serialVersionUID = 1L; 
    private final Timer timer = new Timer(20, this); 
    private final Rectangle rect = new Rectangle(); 
    private BufferedImage background; 
    private int index; 
    private long totalTime; 
    private long averageTime; 
    private int frameCount; 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new AnimationTest().create(); 
      } 
     }); 
    } 

    private void create() { 
     JFrame f = new JFrame("AnimationTest"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(this); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
     timer.start(); 
    } 

    public AnimationTest() { 
     super(true); 
     this.setOpaque(false); 
     this.setPreferredSize(new Dimension(WIDE, HIGH)); 
     this.addMouseListener(new MouseHandler()); 
     this.addComponentListener(new ComponentHandler()); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     long start = System.nanoTime(); 
     super.paintComponent(g); 
     int w = this.getWidth(); 
     int h = this.getHeight(); 
     g.drawImage(background, 0, 0, this); 
     double theta = 2 * Math.PI * index++/64; 
     g.setColor(Color.blue); 
     rect.setRect((int) (Math.sin(theta) * w/3 + w/2 - RADIUS), 
       (int) (Math.cos(theta) * h/3 + h/2 - RADIUS), 2 * RADIUS, 2 * RADIUS); 
     g.fillOval(rect.x, rect.y, rect.width, rect.height); 
     g.setColor(Color.white); 
     if (frameCount == FRAMES) { 
      averageTime = totalTime/FRAMES; 
      totalTime = 0; 
      frameCount = 0; 
     } else { 
      totalTime += System.nanoTime() - start; 
      frameCount++; 
     } 
     String s = String.format("%1$5.3f", averageTime/1000000d); 
     g.drawString(s, 5, 16); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     this.repaint(); 
    } 

    private class MouseHandler extends MouseAdapter { 

     @Override 
     public void mousePressed(MouseEvent e) { 
      super.mousePressed(e); 
      JTextField field = new JTextField("test"); 
      Dimension d = field.getPreferredSize(); 
      field.setBounds(e.getX(), e.getY(), d.width, d.height); 
      add(field); 
     } 
    } 

    private class ComponentHandler extends ComponentAdapter { 

     private final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
     private final GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration(); 
     private final Random r = new Random(); 

     @Override 
     public void componentResized(ComponentEvent e) { 
      super.componentResized(e); 
      int w = getWidth(); 
      int h = getHeight(); 
      background = gc.createCompatibleImage(w, h, Transparency.OPAQUE); 
      Graphics2D g = background.createGraphics(); 
      g.clearRect(0, 0, w, h); 
      g.setColor(Color.green.darker()); 
      for (int i = 0; i < 128; i++) { 
       g.drawLine(w/2, h/2, r.nextInt(w), r.nextInt(h)); 
      } 
      g.dispose(); 
      System.out.println("Resized to " + w + " x " + h); 
     } 
    } 
} 
+0

這個程序繪製一個靜止圖像,所以實際上沒有必要重繪,但我只是把它作爲一個例子。我正在做的應用程序需要重新繪製,因爲對象移動。而在我發佈的應用程序中,它仍然繪製兩次相同的靜止圖像。 – user1319734

+0

@ControlAltDel我認爲這也是由tjacobs製作的,是不是 – mKorbel

+0

藍色球的應用程序工作在60fps。我要看看它。感謝您發佈它。 – user1319734