Java 2D
什么是 Java 2D
Java 2D API 是 Java 标准类库中的一个强大的绘图工具包,它为开发人员提供了用于创建高质量二维图形、文本和图像处理的一系列类和接口。Java 2D API 在 JDK 1.2 中首次引入,是对 Java 原始绘图功能的显著增强,让程序员能够创建出更加复杂和美观的图形界面。
Java 2D API 主要位于 java.awt
和 java.awt.geom
包中,代表了对原始 AWT 图形库的一次重大扩展。
Java 2D 的核心概念
在开始使用 Java 2D 之前,我们需要理解几个核心概念:
1. Graphics2D 类
Graphics2D
是 Java 2D 的核心类,它扩展了基本的 Graphics
类,提供了更多的二维图形渲染功能。我们可以通过 paint()
或 paintComponent()
方法获取 Graphics
对象,然后将其强制转换为 Graphics2D
。
2. 形状(Shape)
Java 2D 提供了各种预定义的形状类,如矩形(Rectangle2D
)、椭圆(Ellipse2D
)、线(Line2D
)等,都实现了 Shape
接口。这使得绘制各种几何图形变得简单。
3. 笔画(Stroke)
Stroke
接口定义了如何绘制线条的属性,例如线宽、连接方式和线帽样式。最常用的实现是 BasicStroke
类。
4. 绘制属性(Paint)
Paint
接口定义了如何填充形状的属性。常见的实现有 Color
(单色填充)、GradientPaint
(渐变填充)和 TexturePaint
(纹理填充)。
5. 仿射变换(AffineTransform)
AffineTransform
类允许对图形执行各种变换操作,如平移、旋转、缩放和切变。
基础图形绘制
让我们通过一个简单的例子来了解如何使用 Java 2D 绘制基本图形:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class SimpleDrawing extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// 将Graphics对象转换为Graphics2D
Graphics2D g2d = (Graphics2D) g;
// 设置抗锯齿以使绘图更平滑
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制一个矩形
Rectangle2D rect = new Rectangle2D.Double(50, 50, 200, 100);
g2d.setColor(Color.BLUE);
g2d.fill(rect);
// 绘制一个椭圆
Ellipse2D ellipse = new Ellipse2D.Double(300, 50, 150, 100);
g2d.setColor(Color.RED);
g2d.fill(ellipse);
// 绘制一条线
Line2D line = new Line2D.Double(50, 200, 450, 200);
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(5)); // 设置线宽为5像素
g2d.draw(line);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Java 2D 基础绘图");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SimpleDrawing());
frame.setSize(500, 300);
frame.setVisible(true);
}
}
运行这段代码,会显示一个窗口,其中包含一个蓝色矩形、一个红色椭圆和一条粗黑线。
高级绘图技术
渐变填充
Java 2D 允许使用渐变色填充形状,以创建更有吸引力的视觉效果:
// 创建线性渐变填充(从蓝色到绿色)
GradientPaint gradient = new GradientPaint(
50, 50, Color.BLUE,
250, 150, Color.GREEN,
true); // true表示循环渐变
g2d.setPaint(gradient);
g2d.fill(rect);
// 创建径向渐变
RadialGradientPaint radialGradient = new RadialGradientPaint(
new Point2D.Double(375, 100), // 中心点
75, // 半径
new float[] {0.0f, 0.8f, 1.0f}, // 分布点
new Color[] {Color.RED, Color.YELLOW, Color.WHITE} // 颜色
);
g2d.setPaint(radialGradient);
g2d.fill(ellipse);
透明度控制
通过设置 AlphaComposite
,可以控制绘制元素的透明度:
// 设置50%透明度
AlphaComposite ac = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.5f);
g2d.setComposite(ac);
g2d.fill(shape);
图形变换
使用 AffineTransform
可以对图形进行各种变换:
// 保存当前变换状态
AffineTransform oldTransform = g2d.getTransform();
// 平移、旋转和缩放
g2d.translate(100, 100); // 平移到(100,100)
g2d.rotate(Math.PI / 4); // 旋转45度
g2d.scale(1.5, 0.5); // x方向放大1.5倍,y方向缩小一半
// 绘制变换后的形状
g2d.draw(shape);
// 恢复原始变换
g2d.setTransform(oldTransform);
文本渲染
Java 2D 提供了强大的文本渲染功能,包括字体选择、文本布局和样式控制:
// 设置字体
Font font = new Font("Arial", Font.BOLD, 24);
g2d.setFont(font);
// 启用文本抗锯齿
g2d.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 绘制文本
g2d.setColor(Color.BLACK);
g2d.drawString("Hello, Java 2D!", 50, 250);
// 获取文本边界
FontMetrics metrics = g2d.getFontMetrics(font);
String text = "Centered Text";
int x = (getWidth() - metrics.stringWidth(text)) / 2;
int y = 300;
g2d.drawString(text, x, y);
图像处理
Java 2D API 还提供了丰富的图像处理功能:
try {
// 加载图片
BufferedImage image = ImageIO.read(new File("image.jpg"));
// 绘制图片
g2d.drawImage(image, 50, 300, this);
// 应用缩放
int w = image.getWidth();
int h = image.getHeight();
g2d.drawImage(image, 200, 300, w/2, h/2, this); // 缩小到一半大小
// 应用图像滤镜
BufferedImageOp op = new GaussianBlurFilter(5);
BufferedImage filteredImage = op.filter(image, null);
g2d.drawImage(filteredImage, 350, 300, this);
} catch (IOException e) {
e.printStackTrace();
}
上面的 GaussianBlurFilter
类不是 Java 标准库的一部分,需要额外的图像处理库,如 JAI(Java Advanced Imaging)或其他第三方库。
实际应用案例:简单绘图程序
下面是一个简单的绘图程序,允许用户通过鼠标绘制线条和形状:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
public class SimpleDrawingApp extends JPanel {
private ArrayList<Shape> shapes = new ArrayList<>();
private Point startPoint, endPoint;
private int shapeType = 0; // 0=线条, 1=矩形, 2=椭圆
public SimpleDrawingApp() {
setPreferredSize(new Dimension(800, 600));
setBackground(Color.WHITE);
MouseAdapter mouseHandler = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
endPoint = startPoint;
repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
endPoint = e.getPoint();
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
Shape shape = null;
if (shapeType == 0) { // 线条
shape = new Line2D.Double(
startPoint.x, startPoint.y,
endPoint.x, endPoint.y);
} else if (shapeType == 1) { // 矩形
shape = makeRectangle(startPoint, endPoint);
} else if (shapeType == 2) { // 椭圆
shape = makeEllipse(startPoint, endPoint);
}
if (shape != null) {
shapes.add(shape);
}
startPoint = null;
endPoint = null;
repaint();
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
private Rectangle2D.Double makeRectangle(Point p1, Point p2) {
return new Rectangle2D.Double(
Math.min(p1.x, p2.x),
Math.min(p1.y, p2.y),
Math.abs(p1.x - p2.x),
Math.abs(p1.y - p2.y));
}
private Ellipse2D.Double makeEllipse(Point p1, Point p2) {
return new Ellipse2D.Double(
Math.min(p1.x, p2.x),
Math.min(p1.y, p2.y),
Math.abs(p1.x - p2.x),
Math.abs(p1.y - p2.y));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// 启用抗锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// 设置绘图属性
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(2));
// 绘制已保存的形状
for (Shape shape : shapes) {
g2d.draw(shape);
}
// 绘制当前正在创建的形状
if (startPoint != null && endPoint != null) {
if (shapeType == 0) { // 线条
g2d.draw(new Line2D.Double(
startPoint.x, startPoint.y,
endPoint.x, endPoint.y));
} else if (shapeType == 1) { // 矩形
g2d.draw(makeRectangle(startPoint, endPoint));
} else if (shapeType == 2) { // 椭圆
g2d.draw(makeEllipse(startPoint, endPoint));
}
}
}
public void setShapeType(int type) {
shapeType = type;
}
public static void main(String[] args) {
JFrame frame = new JFrame("简单绘图程序");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SimpleDrawingApp drawingPanel = new SimpleDrawingApp();
// 创建工具栏
JToolBar toolbar = new JToolBar();
JButton lineButton = new JButton("线条");
JButton rectButton = new JButton("矩形");
JButton ellipseButton = new JButton("椭圆");
JButton clearButton = new JButton("清除");
lineButton.addActionListener(e -> drawingPanel.setShapeType(0));
rectButton.addActionListener(e -> drawingPanel.setShapeType(1));
ellipseButton.addActionListener(e -> drawingPanel.setShapeType(2));
clearButton.addActionListener(e -> {
drawingPanel.shapes.clear();
drawingPanel.repaint();
});
toolbar.add(lineButton);
toolbar.add(rectButton);
toolbar.add(ellipseButton);
toolbar.add(clearButton);
frame.add(toolbar, BorderLayout.NORTH);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
这个应用程序允许用户:
- 选择绘制线条、矩形或椭圆
- 通过拖拽鼠标来创建所选形状
- 清除画布上的所有内容
总结
Java 2D API 是一个功能强大的库,它使 Java 开发人员能够创建高质量的二维图形应用程序。主要特点包括:
- 各种几何形状的绘制
- 颜色、笔画和填充的精细控制
- 图形变换(旋转、缩放等)
- 文本渲染和高级字体支持
- 丰富的图像处理功能
通过本教程,你已经了解了 Java 2D 的基础知识,并学习了如何创建简单的绘图应用程序。随着不断练习,你将能够创建更加复杂和精美的图形界面。
练习
- 修改简单绘图程序,添加颜色选择功能,允许用户为不同的形状选择不同的颜色。
- 实现一个简单的图表应用程序,使用 Java 2D 绘制饼图或条形图。
- 创建一个图像查看器,可以加载图像并应用各种效果,如灰度转换、调整亮度或应用模糊效果。
- 尝试使用 Java 2D 实现一个简单的 2D 游戏,如贪吃蛇或俄罗斯方块。
附加资源
- Oracle 的 Java 2D 官方教程: Java 2D Graphics
- Java 2D API 的 JavaDoc 文档: javax.swing 和 java.awt
- 《Filthy Rich Clients》一书,作者 Chet Haase 和 Romain Guy,深入探讨了 Java 2D 和 Swing 的高级技术
继续探索和实践,你将能够掌握 Java 2D API,并创建出令人印象深刻的图形应用程序!