Java 2D 图形绘制入门指南
1. Java 2D 图形绘制简介
在 Java 编程中,Java 2D 为我们提供了强大的图形绘制功能。通过 Java 2D,我们可以绘制各种基本形状,如线条、矩形、椭圆等,还能设置形状的填充颜色、轮廓粗细,甚至创建透明形状和渐变填充。
1.1 获取图形上下文
在使用 Java 2D 进行绘图之前,我们需要获取一个图形上下文对象。通常的做法是将绘图代码放在组件的
paint
方法中,该方法会接收一个图形上下文作为参数。
paint
方法会在组件需要重绘时被 Swing 调用,例如组件首次显示、窗口最小化后恢复或被其他窗口遮挡再移开等情况。我们也可以通过调用组件的
repaint
方法来手动触发
paint
方法。
图形上下文对象是
Graphics2D
类的实例,但
paint
方法传递的是
Graphics
类的对象,因此我们需要将其转换为
Graphics2D
对象:
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
// 后续代码...
}
为了获得更好的图形效果,我们可以使用抗锯齿提示:
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
1.2 绘制形状
要绘制形状,首先需要创建一个
Shape
对象来表示要绘制的形状。Java 2D 提供了多个实现
Shape
接口的类,例如创建一个基本矩形:
Shape rect = new Rectangle2D.Float(10, 20, 120, 150);
这个矩形的左上角坐标为 (10, 20),宽度为 120,高度为 150。创建好形状后,我们可以调用图形上下文的
draw
方法来绘制形状的轮廓:
g2.draw(rect);
我们还可以对形状进行一些调整:
-
改变颜色
:调用
setColor
方法,如
g2.setColor(Color.RED);
-
改变线条粗细
:调用
setStroke
方法并传入
BasicStroke
类的实例,如
g2.setStroke(new BasicStroke(4));
-
填充形状
:调用
fill
方法,如
g2.fill(rect);
-
同时绘制轮廓和填充颜色
:先调用
draw
方法,再调用
fill
方法,并在中间改变颜色,例如:
g2.setColor(Color.BLACK);
g2.draw(rect);
g2.setColor(Color.MAGENTA);
g2.fill(rect);
1.3 简单图形程序示例
以下是一个简单的程序,用于显示一个椭圆:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class SimpleShape extends JFrame {
public static void main(String [] args) {
new SimpleShape();
}
public SimpleShape() {
this.setSize(300, 300);
this.setTitle("A Simple Shape Program");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new PaintSurface(), BorderLayout.CENTER);
this.setVisible(true);
}
private class PaintSurface extends JComponent {
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Shape s = new Ellipse2D.Float(20, 50, 250, 150);
g2.setPaint(Color.BLACK);
g2.draw(s);
}
}
}
这个程序的重要点如下:
1. 导入了
javax.swing
、
java.awt
和
java.awt.geom
三个包,大多数图形绘制程序至少需要这三个包。
2.
SimpleShape
类继承自
JFrame
,也可以继承
JApplet
作为小程序使用,但需要移除
JApplet
未定义的方法调用。
3.
main
方法创建了
SimpleShape
类的一个新实例。
4.
SimpleShape
构造函数进行了窗口的基本设置,并添加了
PaintSurface
组件。
5.
PaintSurface
类继承自
JComponent
,重写了
paint
方法,在方法中进行了图形上下文转换、设置抗锯齿提示、创建椭圆形状并绘制。
2. 创建形状
Java 2D 中所有可绘制的形状都是通过实现
Shape
接口的类创建的。以下是一些常见的基本形状类及其构造函数:
| 类 | 构造函数 | 描述 |
| — | — | — |
|
Arc2D.Float
|
(float x, float y, float w, float h, float start, float extent, int type)
| 创建一个圆弧,由前四个参数定义椭圆,
start
是圆弧的起始角度(度),
extent
是圆弧的角度范围,
type
可以是
OPEN
、
CHORD
或
PIE
|
|
Ellipse2D.Float
|
(float x, float y, float w, float h)
| 创建一个椭圆,其外接矩形的左上角坐标为 (x, y),宽度为 w,高度为 h。如果 w 和 h 相等,则为圆形 |
|
Line2D.Float
|
(float x1, float y1, float x2, float y2)
或
(Point2D p1, Point2D p2)
| 创建一条从 (x1, y1) 到 (x2, y2) 的直线,或从点 p1 到点 p2 的直线 |
|
Rectangle2D.Float
|
(float x, float y, float w, float h)
| 创建一个矩形,左上角坐标为 (x, y),宽度为 w,高度为 h |
|
RoundRectangle2D.Float
|
(float x, float y, float w, float h, float arcw, float arch)
| 创建一个圆角矩形,左上角坐标为 (x, y),宽度为 w,高度为 h,
arcw
和
arch
分别指定圆角的宽度和高度 |
这些类的名称可能看起来有些奇怪,例如
Rectangle2D.Float
,实际上
Float
是
Rectangle2D
类的内部类,每个类还有一个
Double
内部类,用于更精确地表示形状。对于大多数情况,
float
精度已经足够,但在需要高精度的应用中,可能需要使用
Double
类。
2.1 创建线条
线条是最基本的形状,可以使用
Line2D.Float
类创建。例如:
Shape line1 = new Line2D.Float(0, 0, 100, 200);
也可以使用
Point2D
对象来创建线条:
Point2D start = new Point2D.Float(0, 0);
Point2D end = new Point2D.Float (100, 200);
Shape line1 = new Line2D.Float(start, end);
以下是绘制网格线的代码示例:
for (int i = 0; i < getSize().width; i += 10)
g2.draw(new Line2D.Float(i, 0, i, getSize().height));
for (int i = 0; i < getSize().height; i += 10)
g2.draw(new Line2D.Float(0, i, getSize().width, i));
第一个
for
循环绘制垂直线,第二个绘制水平线。
2.2 创建矩形
矩形的创建需要指定起始点 (x, y) 以及宽度和高度。例如:
Shape rect1 = new Rectangle2D.Float(10, 10, 60, 80);
Java 2D 还提供了
RoundRectangle2D
类来创建圆角矩形,例如:
Shape round1 = new RoundRectangle2D.Float(110, 10, 80, 80, 10, 10);
通过设置不同的圆角宽度和高度,可以创建出各种有趣的形状:
Shape round2 = new RoundRectangle2D.Float(210, 10, 60, 80, 50, 75);
2.3 创建椭圆
椭圆是一种圆形形状,其构造函数与矩形类似。例如:
Shape ellipse1 = new Ellipse2D.Float(10, 110, 80, 80);
如果外接矩形是正方形,则椭圆为圆形。以下是不同形状的椭圆示例:
Shape ellipse2 = new Ellipse2D.Float(110, 110, 80, 40);
Shape ellipse3 = new Ellipse2D.Float(210, 110, 40, 80);
2.4 创建圆弧
圆弧是椭圆的一部分,创建圆弧需要指定包含椭圆的外接矩形以及起始角度、角度范围和圆弧类型。例如:
Shape arc1 = new Arc2D.Float(10, 210, 80, 80, 90, 90, Arc2D.OPEN);
Shape arc2 = new Arc2D.Float(110, 210, 80, 80, 0, 180, Arc2D.CHORD);
Shape arc3 = new Arc2D.Float(210, 210, 45, 180, 45, 90, Arc2D.PIE);
2.5 ShapeMaker 程序示例
以下是一个
ShapeMaker
程序,用于绘制多种形状:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
public class ShapeMaker extends JFrame {
public static void main(String [] args) {
new ShapeMaker();
}
public ShapeMaker() {
this.setSize(300, 300);
this.setTitle("Shape Maker");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new PaintSurface(), BorderLayout.CENTER);
this.setVisible(true);
}
private class PaintSurface extends JComponent {
ArrayList<Shape> shapes = new ArrayList<Shape>();
Point startDrag, endDrag;
Shape found = null;
public PaintSurface() {
Shape s;
// 矩形
s = new Rectangle2D.Float(10, 10, 60, 80);
shapes.add(s);
// 圆角矩形
s = new RoundRectangle2D.Float(110, 10, 80, 80, 10, 10);
shapes.add(s);
// 圆角矩形
s = new RoundRectangle2D.Float(210, 10, 60, 80, 50, 75);
shapes.add(s);
// 圆形
s = new Ellipse2D.Float(10, 110, 80, 80);
shapes.add(s);
// 椭圆
s = new Ellipse2D.Float(110, 110, 80, 40);
shapes.add(s);
// 椭圆
s = new Ellipse2D.Float(210, 110, 40, 80);
shapes.add(s);
// 圆弧
s = new Arc2D.Float(10, 210, 80, 80, 90, 90, Arc2D.OPEN);
shapes.add(s);
// 圆弧
s = new Arc2D.Float(110, 210, 80, 80, 0, 180, Arc2D.CHORD);
shapes.add(s);
// 圆弧
s = new Arc2D.Float(210, 210, 80, 80, 45, 90, Arc2D.PIE);
shapes.add(s);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
// 开启抗锯齿
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制背景网格
g2.setPaint(Color.LIGHT_GRAY);
for (int i = 0; i < getSize().width; i += 10)
g2.draw(new Line2D.Float(i, 0, i, getSize().height));
for (int i = 0; i < getSize().height; i += 10)
g2.draw(new Line2D.Float(0, i, getSize().width, i));
// 绘制所有形状
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(2));
for (Shape s : shapes)
g2.draw(s);
}
}
}
这个程序将所有形状存储在一个
ArrayList
中,在
PaintSurface
构造函数中创建形状,在
paint
方法中绘制所有形状。这种方法对于处理多个形状的程序非常有用,当用户绘制新形状时,只需将其添加到
ArrayList
中,每次调用
paint
方法时,所有形状都会被重新绘制。
graph TD;
A[开始] --> B[创建 ShapeMaker 实例];
B --> C[设置窗口大小、标题和关闭操作];
C --> D[添加 PaintSurface 组件];
D --> E[显示窗口];
E --> F[PaintSurface 构造函数创建形状];
F --> G[调用 paint 方法];
G --> H[转换图形上下文];
H --> I[设置抗锯齿提示];
I --> J[绘制背景网格];
J --> K[绘制所有形状];
K --> L[结束];
3. 填充形状
前面提到可以使用纯色填充形状,只需先调用
setPaint
方法设置填充颜色,再调用
fill
方法填充形状。例如:
g2.setColor(Color.RED);
g2.fill(rect1);
这里将填充颜色设置为红色,然后填充名为
rect1
的形状。但填充不仅仅局限于纯色,下面将介绍如何创建部分透明的填充以及从一种颜色逐渐过渡到另一种颜色的渐变填充。
3.1 绘制透明形状
Java 2D 允许通过指定合成规则来创建透明形状。虽然合成规则的功能不止设置透明度,但由于篇幅限制,这里只介绍设置透明度的方法:
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50F));
关键在于浮点参数值,其范围必须在 0.0 到 1.0 之间。在这个例子中,透明度设置为 0.50F,意味着形状是 50% 透明的,绘制形状时,其下方的内容会部分显示出来。
3.2 使用渐变填充
除了使用纯色,还可以指定渐变填充,通过
GradientPaint
类将两种颜色混合。
GradientPaint
类的构造函数如下表所示:
| 构造函数 | 描述 |
| — | — |
|
GradientPaint(float x1, float y1, Color c1, float x2, float y2, Color c2)
| 创建一个渐变,点 (x1, y1) 的颜色为 c1,点 (x2, y2) 的颜色为 c2,两点之间的颜色平滑过渡。超出 (x1, y1) 的所有点颜色为 c1,超出 (x2, y2) 的所有点颜色为 c2 |
|
GradientPaint(Point2D p1, Color c1, Point2D p2, Color c2)
| 创建一个渐变,点 p1 的颜色为 c1,点 p2 的颜色为 c2,两点之间的颜色平滑过渡。超出 p1 的所有点颜色为 c1,超出 p2 的所有点颜色为 c2 |
|
GradientPaint(float x1, float y1, Color c1, float x2, float y2, Color c2, boolean cyclic)
| 与第一个构造函数相同,但如果
cyclic
参数为
true
,渐变模式将在两点之外无限重复 |
|
GradientPaint(Point2D p1, Color c1, Point2D p2, Color c2, boolean cyclic)
| 与第二个构造函数相同,但如果
cyclic
参数为
true
,渐变模式将在两点之外无限重复 |
以下是一个设置从洋红色到黄色渐变填充的示例:
GradientPaint gp = new GradientPaint(0, 0, Color.MAGENTA, 0, 100, Color.YELLOW);
选择两个颜色点位置的建议如下:
- 这些点是相对于组件的左上角,而不是要填充的形状。通常希望两个点都位于或靠近要绘制形状的边缘。
- 最简单的方法是创建名为
x
、
y
、
width
和
height
的变量,并使用这些变量创建形状和渐变填充。
- 如果希望第一种颜色在顶部,第二种颜色在底部,第一个点使用
(x, y)
,第二个点使用
(x, y + height)
。
- 如果希望第一种颜色在左侧,第二种颜色在右侧,第一个点使用
(x, y)
,第二个点使用
(x + width, y)
。
- 每个点都会被绘制为指定的完整颜色。如果希望在渐变开始之前对象边缘有纯色带,可以选择在对象内部的点,例如
(10, 10)
和
(width - 10, height - 10)
。
- 如果使用第三个或第四个构造函数并将
cyclic
参数指定为
true
,渐变模式会重复。此时应选择更靠近的点,以便在对象内部看到重复效果。例如,如果对象宽度为 150,可以选择
(0, 0)
和
(0, 50)
这样的点,使渐变在对象内重复三次。
下表展示了使用
GradientPaint
类创建的四种不同渐变填充示例,每个矩形的大小为 100 x 100,同时列出了每个填充的点相对于
x
、
y
、
width
和
height
的位置,每个填充的点 1 颜色为黑色,点 2 颜色为白色:
| 渐变填充名称 | 点 1(黑色) | 点 2(白色) |
| — | — | — |
|
gp1
|
x, y
|
x, y + height
|
|
gp2
|
x, y
|
x + width, y
|
|
gp3
|
x, y + 35
|
x, y + height + 35
|
|
gp4
|
x + 35, y + 35
|
x + width - 35, y + height - 35
|
graph TD;
A[开始] --> B[选择填充方式];
B --> C{纯色填充};
C -- 是 --> D[setPaint 设置颜色];
D --> E[fill 填充形状];
C -- 否 --> F{透明填充};
F -- 是 --> G[setComposite 设置透明度];
G --> E;
F -- 否 --> H[创建 GradientPaint 对象];
H --> I[根据建议选择点位置];
I --> J[设置渐变填充];
J --> E;
E --> K[结束];
综上所述,Java 2D 提供了丰富的图形绘制和填充功能,通过掌握获取图形上下文、创建各种形状以及不同的填充方式,可以开发出具有吸引力的图形应用程序。无论是简单的线条和矩形,还是复杂的透明形状和渐变填充,都能在 Java 2D 中轻松实现。希望这些知识能帮助你在 Java 图形编程的道路上迈出坚实的一步。
Java 2D 图形绘制入门指南
超级会员免费看
1万+

被折叠的 条评论
为什么被折叠?



