我正在使用 Java Graphics2D 将一些线条和标签绘制到 JPanel 中。绘图代码运行非常缓慢(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() 大约需要 400 毫秒!但是,如果我不将按钮添加到侧面板,它会显着加快速度 - 每个 draw() 调用花费不到 1 毫秒。诡异的。