跳到主要内容

Java 2D

什么是 Java 2D

Java 2D API 是 Java 标准类库中的一个强大的绘图工具包,它为开发人员提供了用于创建高质量二维图形、文本和图像处理的一系列类和接口。Java 2D API 在 JDK 1.2 中首次引入,是对 Java 原始绘图功能的显著增强,让程序员能够创建出更加复杂和美观的图形界面。

备注

Java 2D API 主要位于 java.awtjava.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 绘制基本图形:

java
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 允许使用渐变色填充形状,以创建更有吸引力的视觉效果:

java
// 创建线性渐变填充(从蓝色到绿色)
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,可以控制绘制元素的透明度:

java
// 设置50%透明度
AlphaComposite ac = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.5f);
g2d.setComposite(ac);
g2d.fill(shape);

图形变换

使用 AffineTransform 可以对图形进行各种变换:

java
// 保存当前变换状态
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 提供了强大的文本渲染功能,包括字体选择、文本布局和样式控制:

java
// 设置字体
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 还提供了丰富的图像处理功能:

java
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)或其他第三方库。

实际应用案例:简单绘图程序

下面是一个简单的绘图程序,允许用户通过鼠标绘制线条和形状:

java
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);
}
}

这个应用程序允许用户:

  1. 选择绘制线条、矩形或椭圆
  2. 通过拖拽鼠标来创建所选形状
  3. 清除画布上的所有内容

总结

Java 2D API 是一个功能强大的库,它使 Java 开发人员能够创建高质量的二维图形应用程序。主要特点包括:

  • 各种几何形状的绘制
  • 颜色、笔画和填充的精细控制
  • 图形变换(旋转、缩放等)
  • 文本渲染和高级字体支持
  • 丰富的图像处理功能

通过本教程,你已经了解了 Java 2D 的基础知识,并学习了如何创建简单的绘图应用程序。随着不断练习,你将能够创建更加复杂和精美的图形界面。

练习

  1. 修改简单绘图程序,添加颜色选择功能,允许用户为不同的形状选择不同的颜色。
  2. 实现一个简单的图表应用程序,使用 Java 2D 绘制饼图或条形图。
  3. 创建一个图像查看器,可以加载图像并应用各种效果,如灰度转换、调整亮度或应用模糊效果。
  4. 尝试使用 Java 2D 实现一个简单的 2D 游戏,如贪吃蛇或俄罗斯方块。

附加资源

  • Oracle 的 Java 2D 官方教程: Java 2D Graphics
  • Java 2D API 的 JavaDoc 文档: javax.swingjava.awt
  • 《Filthy Rich Clients》一书,作者 Chet Haase 和 Romain Guy,深入探讨了 Java 2D 和 Swing 的高级技术

继续探索和实践,你将能够掌握 Java 2D API,并创建出令人印象深刻的图形应用程序!