2013-08-06 390 views
0

我正在使用Java Graphics2D在JPanel中繪製一些行和標籤。繪圖代碼運行非常緩慢(drawString()似乎是最差的,但我不再認爲它是罪魁禍首,只是最忙碌的通話)。Graphics2D.drawString非常慢

執行環境是OSX 10.8.4和VM細節:

JVM: Java HotSpot(TM) 64-Bit Server VM (20.51-b01-457, mixed mode) 
Java: version 1.6.0_51, vendor Apple Inc. 
Java Home: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home 
JVM Flags: <none> 

完全自包含的示例代碼如下:

package com.controlj.test; 

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 
import java.awt.geom.*; 
import java.util.ArrayList; 
import java.util.List; 

public class TestDrawString { 

List<Line2D> lines = new ArrayList<Line2D>(); 
private Rectangle2D bounds; 

public TestDrawString(Rectangle2D rectBounds) { 
    bounds = rectBounds; 
    int x0 = (int)Math.floor(bounds.getX()); 
    int y0 = (int)Math.floor(bounds.getY()); 
    int x1 = (int)Math.ceil(bounds.getMaxX()); 
    int y1 = (int)Math.ceil(bounds.getMaxY()); 
    for(int i = x0; i != x1 + 1; i++) 
     lines.add(new Line2D.Float(i, y0, i, y1)); 
    for(int i = y0; i != y1 + 1; i++) 
     lines.add(new Line2D.Float(x0, i, x1, i)); 
} 

public void draw(Graphics2D g) { 
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); 
    g.setColor(Color.white); 
    g.setStroke(new BasicStroke(0)); 
    for(Line2D l : lines) 
     g.draw(l); 
    AffineTransform current = g.getTransform(); 
    Point2D origin = new Point2D.Double(bounds.getX(), bounds.getY()); 
    origin = current.transform(origin, origin); 
    g.setTransform(new AffineTransform()); 
    g.setFont(new Font("Monospaced", Font.PLAIN, 12)); 
    for(Line2D l : lines) { 
     Point2D p = new Point2D.Double(l.getX1(), l.getY1()); 
     p = current.transform(p, p); 
     if(l.getX1() == l.getX2()) 
      g.drawString(Integer.toString((int)l.getX1()), (int)p.getX() + 1, (int)origin.getY() - 4); 
     else 
      g.drawString(Integer.toString((int)l.getY1()), (int)origin.getX() + 1, (int)p.getY() - 4); 
    } 
    g.setTransform(current); 
} 

static class ImageLayers extends JPanel { 

    private TestDrawString grids; 
    private Rectangle2D.Double rectBounds; 
    private AffineTransform at; 
    private AffineTransform rat = null; 
    private double ratio; 

    public ImageLayers() { 
     MouseAdapter ma = new MouseAdapter() { 
      private final Point clicked = new Point(); 

      @Override 
      public void mousePressed(MouseEvent mouseEvent) { 
       super.mousePressed(mouseEvent); 
       clicked.setLocation(mouseEvent.getPoint()); 
      } 

      @Override 
      public void mouseDragged(MouseEvent mouseEvent) { 
       super.mouseDragged(mouseEvent); 
       clicked.setLocation(mouseEvent.getX() - clicked.getX(), mouseEvent.getY() - clicked.getY()); 
       setCoords(rectBounds.getX() - clicked.getX() * ratio, rectBounds.getY() + clicked.getY() * ratio, rectBounds.getWidth()); 
       clicked.setLocation(mouseEvent.getPoint()); 
      } 

      @Override 
      public void mouseWheelMoved(MouseWheelEvent mouseWheelEvent) { 
       super.mouseWheelMoved(mouseWheelEvent); 
       System.out.println(mouseWheelEvent.toString()); 
       zoom(1.0 + mouseWheelEvent.getWheelRotation()/20.0, mouseWheelEvent.getPoint()); 
      } 
     }; 
     addMouseListener(ma); 
     addMouseMotionListener(ma); 
     addMouseWheelListener(ma); 
     addComponentListener(new ComponentAdapter() { 
      @Override 
      public void componentResized(ComponentEvent componentEvent) { 
       setTransform(); 
       repaint(); 
      } 
     }); 
     setCoords(118.0, -40.0, 35.0); 
    } 

    public void zoom(double val, Point point) { 
     Point2D point2 = new Point2D.Double(point.getX(), point.getY()); 
     point2 = rat.transform(point2, point2); 
     double x = point2.getX() - (point2.getX() - rectBounds.getX())/val; 
     double y = point2.getY() - (point2.getY() - rectBounds.getY())/val; 
     setCoords(x, y, rectBounds.getWidth()/val); 
    } 

    private void setTransform() { 

     Rectangle pos = getBounds(); 
     System.out.println("Getbounds returned " + pos); 
     if(pos.getHeight() == 0 || pos.getWidth() == 0) 
      return; 
     ratio = rectBounds.width/(double)pos.getWidth(); 
     rectBounds.height = rectBounds.width * (double)pos.getHeight()/(double)pos.getWidth(); 
     at = new AffineTransform(); 
     //at.translate(pos.getX(), pos.getY() + pos.getHeight()); 
     at.translate(0, pos.getHeight()); 
     at.scale((pos.getWidth())/rectBounds.getWidth(), -(pos.getWidth())/rectBounds.getWidth()); 
     at.translate(-rectBounds.getMinX(), -rectBounds.getMinY()); 
     System.out.println("Translation is: " + at.toString()); 

     rat = null; 
     try { 
      rat = at.createInverse(); 
     } catch(NoninvertibleTransformException e) { 
      e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 
     } 
    } 


    @Override 
    protected void paintComponent(Graphics graphics) { 
     super.paintComponent(graphics); 
     Graphics2D g = (Graphics2D)graphics; 
     g.setTransform(at); 
     grids.draw(g); 
    } 

    public void setCoords(double x, double y, double width) { 
     if(width <= 0) 
      width = 35; 
     System.out.println(String.format("setCoords(x=%f, y=%f, width=%f", x, y, width)); 
     rectBounds = new Rectangle2D.Double(x, y, width, width); 
     setTransform(); 
     grids = new TestDrawString(rectBounds); 
     repaint(); 
    } 
} 

public static void main(String args[]) { 
    JFrame frame = new JFrame("DrawStringTest"); 
    frame.setBounds(400, 400, 1000, 1000); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    ImageLayers iml = new ImageLayers(); 
    iml.setBackground(Color.blue); 
    iml.setCoords(118.0, -40.0, 35.0); 
    JPanel jp = new JPanel(); 
    jp.setLayout(new BorderLayout()); 
    JPanel buttonPanel = new JPanel(); 
    buttonPanel.add(new Button("+")); // COMMENT out this line to speed things up! 
    jp.add(buttonPanel, BorderLayout.SOUTH); 
    JSplitPane contentPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jp, iml); 
    contentPane.setDividerLocation(200); 
    frame.add(contentPane); 
    frame.setVisible(true); 
} 

}

拖動或縮放(使用滾輪)非常慢。 VisualVM分析數據如下。每次調用TestDrawString.draw()需要大約400ms!但是,如果我不將該按鈕添加到側面板,它會顯着加速 - 每次draw()調用的時間不會超過1ms。奇怪的。

profile http://www.sr20.org/DrawString.png

+0

「緩慢」,如:它出現在面板上之前有一點滯後? – GGrec

+4

你正在做雙循環,這不會幫助。如果可以的話,將結果緩衝到像「BufferedImage」之類的東西並直接繪製它們。 – MadProgrammer

+1

請修改您的問題以包含展示您描述的問題的[sscce](http://sscce.org/),並確保[profile](http://stackoverflow.com/q/2064427/230513) ;或者,使用'JTextComponent'。 – trashgod

回答

0

多虧了trashgod了非常明智的建議,以創建一個小的自包含的例子我能找出問題。這涉及到混合AWT和Swing組件,特別是添加Button而不是JButton。