2013-07-01 24 views
0

背景用Java繪圖 - 爲什麼我的代碼太慢?

我試着去創造一些撥號慣量模擬等,我想避免的OpenGL如果這是可能看中,順利和快速的模擬儀表。

問題

我在Java代碼中是比我預期的要慢得多。我想讓我的錶盤在從最小值(0)到最大值(1024,我可以改變這個,但我需要平滑度)短於0.5秒的時間內移動。

我試着測量花在重繪和paintComponent方法上的時間來查找問題。

重繪需要大約40us,paintComponent需要300us,在我的機器上(Core Duo 2GHz,Windows 7)。

它似乎足夠快(1/0.000340s =〜3000「運行」每秒)。

我認爲視頻卡是瓶頸,它會減慢我的代碼,但我不知道該如何處理它。

問題

如何使我的速度更快,並保持流暢的動畫儘可能?

import java.awt.BasicStroke; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.Stroke; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.Point2D; 
import java.awt.image.BufferedImage; 

import javax.swing.*; 

public class Main extends JPanel { 
    private static final Point2D CENTER = new Point2D.Double(PREF_W/2.0, 
     PREF_W/2.0); 
    private static final double RADIUS = PREF_W/2.0; 
    private static final Color LARGE_TICK_COLOR = Color.DARK_GRAY; 
    private static final Color CENTER_HUB_COLOR = Color.DARK_GRAY; 
    private static final Stroke LARGE_TICK_STROKE = new BasicStroke(4f); 
    private static final Stroke LINE_TICK_STROKE = new BasicStroke(8f); 
    private static final int LRG_TICK_COUNT = 18; 
    private static final double TOTAL_LRG_TICKS = 24; 
    private static final double LRG_TICK_OUTER_RAD = 0.9; 
    private static final double LRG_TICK_INNER_RAD = 0.8; 
    private static final int START_TICK = 10; 
    private static final double CENTER_HUB_RADIUS = 10; 
    private static final double DIAL_INNER_RAD = 0.00; 
    private static final double DIAL_OUTER_RAD = 0.75; 
    private static final Color DIAL_COLOR = Color.DARK_GRAY; 
    private BufferedImage backgroundImg; 


    private static final int PREF_W = 400; // 
    private static final int PREF_H = 400; 

    private static final double INIT_VALUE = 0; 
    public static final int MAX_VALUE = 1024; // resolution 

    public static int delay = 1; // delay (ms) between value changes 

    private double theta; 
    private double cosTheta; 
    private double sinTheta; 
    private static long microtime; 

    public Main() { 
     setBackground(Color.white); 

     backgroundImg = createBackgroundImg(); 
     setSpeed(INIT_VALUE); 
    } 

    public void setSpeed(double speed) { 


    if (speed < 0) { 
     speed = 0; 
     } else if (speed > MAX_VALUE) { 
     speed = MAX_VALUE; 
     } 
     this.theta = ((speed/MAX_VALUE) * LRG_TICK_COUNT * 2.0 + START_TICK) 
      * Math.PI/TOTAL_LRG_TICKS; 

     cosTheta = Math.cos(theta); 
     sinTheta = Math.sin(theta); 

     microtime = System.nanoTime()/1000; 

     repaint(); 

     System.out.println("Repaint (us) = " + (System.nanoTime()/1000 - microtime)); 



    } 

    private BufferedImage createBackgroundImg() { 
     BufferedImage img = new BufferedImage(PREF_W, PREF_H, 
      BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2 = img.createGraphics(); 

     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON); 
     g2.setColor(LARGE_TICK_COLOR); 
     g2.setStroke(LARGE_TICK_STROKE); 

     for (double i = 0; i < LRG_TICK_COUNT; i++) { 
     double theta = (i * 2.0 + START_TICK) * Math.PI/TOTAL_LRG_TICKS; 
     double cosTheta = Math.cos(theta); 
     double sinTheta = Math.sin(theta); 

     int x1 = (int) (LRG_TICK_INNER_RAD * RADIUS * cosTheta + CENTER.getX()); 
     int y1 = (int) (LRG_TICK_INNER_RAD * RADIUS * sinTheta + CENTER.getY()); 
     int x2 = (int) (LRG_TICK_OUTER_RAD * RADIUS * cosTheta + CENTER.getX()); 
     int y2 = (int) (LRG_TICK_OUTER_RAD * RADIUS * sinTheta + CENTER.getY()); 

     g2.drawLine(x1, y1, x2, y2); 
     } 

     g2.setColor(CENTER_HUB_COLOR); 

     int x = (int) (CENTER.getX() - CENTER_HUB_RADIUS); 
     int y = (int) (CENTER.getY() - CENTER_HUB_RADIUS); 
     int width = (int) (2 * CENTER_HUB_RADIUS); 
     int height = width; 
     g2.fillOval(x, y, width, height); 


     g2.dispose(); 
     return img; 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 

      System.out.println("Paint component (us) = " + (System.nanoTime()/1000 - microtime)); 

     super.paintComponent(g); 
     if (backgroundImg != null) { 
     g.drawImage(backgroundImg, 0, 0, this); 
     } 

     Graphics2D g2 = (Graphics2D) g; 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2.setStroke(LINE_TICK_STROKE); 


     g.setColor(DIAL_COLOR); 

     int x1 = (int) (DIAL_INNER_RAD * RADIUS * cosTheta + CENTER.getX()); 
     int y1 = (int) (DIAL_INNER_RAD * RADIUS * sinTheta + CENTER.getY()); 
     int x2 = (int) (DIAL_OUTER_RAD * RADIUS * cosTheta + CENTER.getX()); 
     int y2 = (int) (DIAL_OUTER_RAD * RADIUS * sinTheta + CENTER.getY()); 

     g.drawLine(x1, y1, x2, y2); 

     microtime = System.nanoTime()/1000; 


    } 

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

    private static void createAndShowGui() { 
     final Main mainPanel = new Main(); 

     JFrame frame = new JFrame("DailAnimation"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 

     new Timer(delay, new ActionListener() { 
     double speed = 0; 

     @Override 
     public void actionPerformed(ActionEvent evt) { 

      speed ++; 
      if (speed > Main.MAX_VALUE) { 
       speed = 0; 
      } 
      mainPanel.setSpeed(speed); 

     } 
     }).start(); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

小代碼描述:

有一個計時器,改變計數值。定時器間隔在開始時由變量delay定義。

這是完整的,一個文件代碼,您可以將它粘貼到您的IDE並編譯。

回答

0

你可以嘗試以下方法:從BufferedImage的

  • 切換到的VolatileImage
  • 預先計算的正弦和餘弦函數的結果和他們
  • 切換到活動畫存儲陣列,而不是調用重繪