AWT绘图技术
一、概述
- Canvas:画布类(可以画各种图形)
- Graphics(抽象类):绘图类(提供很多画图形的方法,是所有图形上下文的抽象基类)
- Graphics2D(抽象类):新绘图类,继承了Graphics(拓展了很多复杂的绘制方法,它将图形对象化,即封装为类,并实现了Shape图形接口,可控制画笔粗细,实现颜色的渐变,实现坐标系移动、翻转功能等)
- Shape:图形接口(有一大堆实现类,都在java.awt.gemo下,为图形类)
- Color:颜色类
- Stroke:画笔接口
- BasicStroke:Stroke实现类(可以调整画笔粗细等属性)
- Font:字体类
注意:以上类或接口都在java.awt下。Graphics2D是推荐使用的绘图类,但是程序设计中提供的绘图对象大多是Graphics类的实例对象,应该使用强制类型转换将其转换为Graphics2D类型。
二、
1.绘制图形
构造方法 |
说明 |
public Canvas() |
一个新的 Canvas。 |
public Canvas(GraphicsConfiguration config) |
构造一个给定了 GraphicsConfiguration 对象的 Canvas。 |
注意:该类的实例通常通过其他类继承该类,并重写paint(Graphics g)方法实现,最后将该实例添加到窗体中。
核心方法 |
说明 |
public void paint(Graphics g) |
绘制这个 canvas。为 Canvas 创建子类的大多数应用程序应该重写此方法,以便执行某个有用的操作(通常是 canvas 的自定义绘制操作)。默认操作是清理 canvas。重写此方法的应用程序不需要调用 super.paint(g)。此方法自动调用,参数对象系统自动生成。 |
public void repaint() |
重新编辑该组件。 如果此组件是轻量级组件,则此方法将尽快调用此组件的paint方法。 否则,该方法会尽快调用此组件的update方法。 |
public void repaint(long tm) |
重绘组件。如果此组件是轻量组件,则在 tm 毫秒内调用 paint。 |
构造方法 |
说明 |
protected Graphics() |
构造一个新的 Graphics 对象。此构造方法是用于图形上下文的默认构造方法。 |
注意:因为 Graphics 是一个抽象类,所以应用程序不能直接调用此构造方法。图形上下文从其他图形上下文获取,或者通过在组件上调用 getGraphics 来创建。
常用方法 |
说明 |
public abstract void setColor(Color c) |
将此图形上下文的当前颜色设置为指定颜色。 |
public abstract void drawString(String str, int x,int y) |
使用此图形上下文的当前字体和颜色绘制由指定 string 给定的文本。最左侧字符的基线位于此图形上下文坐标系统的 (x, y) 位置处。 |
public abstract void setFont(Font font) |
将此图形上下文的字体设置为指定字体。使用此图形上下文的所有后续文本操作均使用此字体。 |
public abstract boolean drawImage(Image img,int x,int y,ImageObserver observer) |
在 (x, y)(图象左上角)绘制指定图像,图像中的透明像素不影响该处已存在的像素。此方法在任何情况下都立刻返回,甚至在整个图像尚未装入,并且它还没有为当前输出设备完成抖动和转换的情况下也是如此。如果图像已经完全装入,并且其像素不再发生改变,则 drawImage 返回 true。否则 drawImage 返回 false,并且随着更多的图像可用或者到了绘制动画另一帧的时候,装入图像的进程就会通知指定的图像观察者。返回:如果图像像素仍在改变,则返回 false;否则返回 true。 |
public abstract boolean drawImage(Image img,int x,int y,int width,int height,ImageObserver observer) |
绘制指定图像中已缩放到适合指定矩形内部的图像。 |
public abstract boolean drawImage(Image img,int dx1,int dy1,int dx2,int dy2,int sx1,int sy1,int sx2,int sy2,ImageObserver observer) |
绘制当前可用的指定图像的指定区域,动态地缩放图像使其符合目标绘制表面的指定区域。透明像素不影响该处已存在的像素。此方法总是用图像的非缩放版本来呈现缩放的矩形,并且动态地执行所需的缩放。此操作不使用图像的缓存的、缩放版本。执行图像从源到目标的缩放,这样源矩形的第一个坐标被映射到目标矩形的第一个坐标,第二个源坐标被映射到第二个目标坐标。按需要缩放和翻转子图像以保持这些映射关系。 |
因为画图方法参数描述内容过多,请读者自行查阅API
drawImage()方法参数 |
说明 |
img |
要绘制的指定图像。如果 img 为 null,则此方法不执行任何动作 |
x |
x 坐标。 |
y |
y 坐标。 |
observer |
当转换了更多图像时要通知的对象。(即要通知的图像观察者,当图像要重绘时,要通知的对象,通常为显示在哪个组件的对象) |
width |
图片的新宽度属性 |
height |
图片的新高度属性 |
dx1 |
目标矩形第一个角的 x 坐标。 |
dy1 |
目标矩形第一个角的 y 坐标。 |
dx2 |
目标矩形第二个角的 x 坐标。 |
dy2 |
目标矩形第二个角的 y 坐标。 |
sx1 |
源矩形第一个角的 x 坐标。 |
sy1 |
源矩形第一个角的 y 坐标。 |
sx2 |
源矩形第二个角的 x 坐标。 |
sy2 |
源矩形第二个角的 y 坐标。 |
注意:第一个角为源图片的左上角,第二个角为右下角。
- Graphics2D抽象类(新绘图类)
继承了Graphics抽象类,创建绘图类时推荐使用该类,它可以使用不同的类来表示不同的形状。
构造方法· |
说明 |
protected Graphics2D() |
构建一个新的 Graphics2D 对象。由于 Graphics2D 是一个抽象类,而且它必须由不同输出设备的子类来自定义,所以无法直接创建 Graphics2D 对象。相反,Graphics2D 对象必须从另一个 Graphics2D 对象获得、由某个 Component 创建,或者从图像(如 BufferedImage)对象获得。 |
常用重要方法 |
说明 |
public abstract void draw(Shape s) |
使用当前 Graphics2D 上下文的设置勾画 Shape 的轮廓。 |
public abstract void fill(Shape s) |
使用 Graphics2D 上下文的设置,填充 Shape 的内部区域。 |
public abstract void setStroke(Stroke s) |
为 Graphics2D 上下文设置 画笔 |
public abstract void drawString(String str,int x,int y) |
使用 Graphics2D 上下文中的当前文本属性状态呈现指定的 String 的文本。首字符的基线位于用户空间中的 (x, y) 位置处。 |
public abstract void drawString(String s,float x,float y) |
使用 Graphics2D 上下文中当前文本属性状态呈现由指定 String 指定的文本。首字符的基线位于用户空间中的 (x, y) 位置处。 |
public abstract void setFont(Font font) |
将此图形上下文的字体设置为指定字体。使用此图形上下文的所有后续文本操作均使用此字体。 |
public abstract boolean drawImage(Image img,int x,int y,ImageObserver observer) |
在 (x, y)(图象左上角)绘制指定图像,图像中的透明像素不影响该处已存在的像素。此方法在任何情况下都立刻返回,甚至在整个图像尚未装入,并且它还没有为当前输出设备完成抖动和转换的情况下也是如此。如果图像已经完全装入,并且其像素不再发生改变,则 drawImage 返回 true。否则 drawImage 返回 false,并且随着更多的图像可用或者到了绘制动画另一帧的时候,装入图像的进程就会通知指定的图像观察者。返回:如果图像像素仍在改变,则返回 false;否则返回 true。 |
public abstract boolean drawImage(Image img,int x,int y,int width,int height,ImageObserver observer) |
绘制指定图像中已缩放到适合指定矩形内部的图像。 |
public abstract boolean drawImage(Image img,int dx1,int dy1,int dx2,int dy2,int sx1,int sy1,int sx2,int sy2,ImageObserver observer) |
绘制当前可用的指定图像的指定区域,动态地缩放图像使其符合目标绘制表面的指定区域。透明像素不影响该处已存在的像素。此方法总是用图像的非缩放版本来呈现缩放的矩形,并且动态地执行所需的缩放。此操作不使用图像的缓存的、缩放版本。执行图像从源到目标的缩放,这样源矩形的第一个坐标被映射到目标矩形的第一个坐标,第二个源坐标被映射到第二个目标坐标。按需要缩放和翻转子图像以保持这些映射关系。 |
public abstract void rotate(double theta) |
图像旋转,theta :旋转的角度,以弧度表示 |
public abstract void shear(double shx,double shy) |
使图像倾斜,shx : 在正 X 轴方向移动坐标的乘数,它可以作为其 Y 坐标的函数;shy : 在正 Y 轴方向移动坐标的乘数,它可以作为其 X 坐标的函数 |
注意:使用以上两个方法绘制图形,需要先创建并初始化该图形类的对象,且这些图形类必须是Shape接口的实现类,然后在使用上述方法绘制图形。
示例:
1.第一种写法
public class DrawFrame extends JFrame {
private static final long serialVersionUID = 1L;
public DrawFrame() {
super();
initialize();// 调用初始化方法
}
// 初始化方法
private void initialize() {
this.setSize(300, 200); // 设置窗体大小
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置窗体关闭模式
add(new CanvasPanel()); // 设置窗体面板为绘图面板对象
this.setTitle("绘图实例2"); // 设置窗体标题
}
public static void main(String[] args) {
new DrawFrame().setVisible(true);
}
class CanvasPanel extends JPanel {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) { //paint()方法系统自动调用,参
数对象系统自动生成,直接使用就可以
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
Shape[] shapes = new Shape[4]; // 声明图形数组
shapes[0] = new Ellipse2D.Double(5, 5, 100, 100); // 创建圆形对象
// 创建矩形对象
shapes[1] = new Rectangle2D.Double(110, 5, 100, 100);
shapes[2] = new Rectangle2D.Double(15, 15, 80, 80); // 创建矩形对象
shapes[3] = new Ellipse2D.Double(120, 15, 80, 80); // 创建圆形对象
for (Shape shape : shapes) { // 遍历图形数组
Rectangle2D bounds = shape.getBounds2D();
if (bounds.getWidth() == 80)
g2.fill(shape); // 填充图形
else
g2.draw(shape); // 绘制图形
}
}
}
}
2.第二种写法
class CanvasPanel extends Canvas {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Shape[] shapes = new Shape[4]; // 声明图形数组
shapes[0] = new Ellipse2D.Double(5, 5, 100, 100); // 创建圆形对象
// 创建矩形对象
shapes[1] = new Rectangle2D.Double(110, 5, 100, 100);
shapes[2] = new Rectangle2D.Double(15, 15, 80, 80); // 创建矩形对象
shapes[3] = new Ellipse2D.Double(120, 15, 80, 80); // 创建圆形对象
for (Shape shape : shapes) { // 遍历图形数组
Rectangle2D bounds = shape.getBounds2D();
if (bounds.getWidth() == 80)
g2.fill(shape); // 填充图形
else
g2.draw(shape); // 绘制图形
}
}
}
2.绘图颜色
- Color类(颜色类)
Java以跨平台和与硬件无关的方式支持颜色管理。java.awt.Color类
常用构造方法 |
说明 |
public Color(int r,int g, int b) |
用指定的红色、绿色和蓝色值创建一种不透明的 sRGB 颜色,这三个颜色值都在 0-255 的范围内。绘制时实际使用的颜色,取决于从给出的可用于给定输出设备的颜色空间中找到的最匹配的颜色。alpha 值的默认值为 255。r : 红色分量;g :绿色分量;b :蓝色分量 |
public Color(int rgb) |
用指定的组合 RGB 值创建一种不透明的 sRGB 颜色,此 sRGB 值的 16-23 位表示红色分量,8-15 位表示绿色分量,0-7 位表示蓝色分量。绘制时实际使用的颜色取决于从给出的可用于特定输出设备的颜色空间中找到的最匹配的颜色。alpha 值的默认值为 255。rgb:颜色值,该值是红、绿、蓝三原色的总和。 |
Color类定义了常用的色彩常量值,这些常量都是静态的Color对象,可以直接使用这些常量值定义的颜色对象,如下
常量名 |
颜色值 |
black |
黑色。 |
BLACK |
黑色。 |
blue |
蓝色。 |
BLUE |
蓝色。 |
cyan |
青色。 |
CYAN |
青色。 |
DARK_GRAY |
深灰色。 |
darkGray |
深灰色。 |
gray |
灰色。 |
GRAY |
灰色。 |
green |
绿色。 |
GREEN |
绿色。 |
LIGHT_GRAY |
浅灰色。 |
lightGray |
浅灰色。 |
magenta |
洋红色。 |
MAGENTA |
洋红色。 |
orange |
桔黄色。 |
ORANGE |
桔黄色。 |
pink |
粉红色。 |
PINK |
粉红色。 |
red |
红色。 |
RED |
红色。 |
white |
白色。 |
WHITE |
白色。 |
yellow |
黄色。 |
YELLOW |
黄色。 |
通过Graphics的setColor(Color color)设置当前颜色。
注意:设置好绘图颜色后,再进行绘图或者绘制文本,系统会采用该颜色作为前景色。
示例:
public void paint(Graphics g){
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.RED);
}
3.画笔属性(本属性设置只在Graphics2D有)
默认情况下,Graphics绘图类使用的画笔属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置画笔的属性,如改变线条的粗细、虚实,定义线段端点的形状、风格等。
方法 |
说明 |
setStroke(Stroke s) |
为 Graphics2D 上下文设置 Stroke |
- Stroke接口(画笔接口)
- BasicStroke类
他实现了Stroke接口
构造方法 |
说明 |
public BasicStroke() |
构造一个具有所有属性的默认值的新 BasicStroke。默认属性是宽度为 1.0 的实线、CAP_SQUARE、JOIN_MITER 和 10.0 的斜接限制。 |
public BasicStroke(float width) |
构造一个具有指定线条宽度以及 cap 和 join 风格的默认值的实心 BasicStroke。 |
public BasicStroke(float width, int cap, int join) |
构造一个具有指定属性的实心的 BasicStroke。 |
public BasicStroke(float width,int cap,int join, float miterlimit) |
构造一个具有指定属性的实心的 BasicStroke。 |
public BasicStroke(float width,int cap,int join,float miterlimit,float[] dash,float dash_phase) |
构造一个具有指定属性的新 BasicStroke。 |
参数 |
说明 |
width |
画笔宽度。此宽度必须大于或等于 0.0f。如果将宽度设置为 0.0f,则将画笔设置为当前设备的默认宽度。 |
cap |
线端点的装饰 |
join |
应用在路径线段交汇处的装饰 |
miterlimit |
斜接处的剪裁限制。必须大于或等于 1.0f。 |
dash |
表示虚线模式的数组 |
dash_phase |
开始虚线模式的偏移量 |
cap参数取值 |
说明 |
CAP_BUTT |
无装饰地结束未封闭的子路径和虚线线段。 |
CAP_ROUND |
使用半径等于画笔宽度一半的圆形装饰结束未封闭的子路径和虚线线段。(即圆角末端) |
CAP_SQUARE |
使用正方形结束未封闭的子路径和虚线线段,正方形越过线段端点,并延长等于线条宽度一半的距离。(正方形末端) |
join参数取值 |
说明 |
JOIN_BEVEL |
交汇处为平角 |
JOIN_MITER |
交汇处为尖角 |
JOIN_ROUND |
交汇处为圆角 |
4.绘制文本
(1)设置字体
方法 |
说明 |
public abstract void setFont(Font font) |
将此图形上下文的字体设置为指定字体。使用此图形上下文的所有后续文本操作均使用此字体。 |
常用构造方法 |
说明 |
public Font(String name,int style, int size) |
根据指定名称、样式和大小,创建一个新 Font。 |
参数 |
说明 |
name |
字体的名称(如宋体) |
style |
字体的样式,PLAIN:普通样式;BOLD:粗体样式;ITALIC:斜体样式;ITALIC|BOLD:斜体组合粗体样式 |
size |
字体大小 |
(2)显示字体
方法 |
说明 |
public abstract void drawString(String str, int x, int y) |
使用此图形上下文的当前字体和颜色绘制由指定 string 给定的文本。最左侧字符的基线位于此图形上下文坐标系统的 (x, y) 位置处。(Graphics和Graphics2D都有) |
public abstract void drawString(String s, float x, float y) |
同上,只不过位置更精确(Graphics2D提供) |
示例:
public class DrawString extends JFrame {
private static final long serialVersionUID = 1L;
private Shape rect; // 矩形对象
private Font font; // 字体对象
private Date date; // 当前日期对象
public DrawString() {
rect = new Rectangle2D.Double(10, 10, 200, 80);
font = new Font("宋体", Font.BOLD, 16);
date = new Date();
this.setSize(230, 140); // 设置窗体大小
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置窗体关闭模式
add(new CanvasPanel()); // 设置窗体面板为绘图面板对象
this.setTitle("绘图文本"); // 设置窗体标题
}
public static void main(String[] args) {
new DrawString().setVisible(true);
}
class CanvasPanel extends Canvas {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.CYAN); // 设置当前绘图颜色
g2.fill(rect); // 填充矩形
g2.setColor(Color.BLUE); // 设置当前绘图颜色
g2.setFont(font); // 设置字体
g2.drawString("现在时间是", 20, 30); // 绘制文本
g2.drawString(String.format("%tr", date), 50, 60); // 绘制时间文本
}
}
}
5.绘制图片
绘图类不仅可以绘制图形和文本,还可以使用drawImage()方法将图片资源显示到绘图上下文中,而且可以实现各种特效处理,如图片的缩放、翻转等。
常用绘制图片方法 |
说明 |
public abstract boolean drawImage(Image img,int x,int y,ImageObserver observer) |
在 (x, y)(图象左上角)绘制指定图像,图像中的透明像素不影响该处已存在的像素。此方法在任何情况下都立刻返回,甚至在整个图像尚未装入,并且它还没有为当前输出设备完成抖动和转换的情况下也是如此。如果图像已经完全装入,并且其像素不再发生改变,则 drawImage 返回 true。否则 drawImage 返回 false,并且随着更多的图像可用或者到了绘制动画另一帧的时候,装入图像的进程就会通知指定的图像观察者。返回:如果图像像素仍在改变,则返回 false;否则返回 true。 |
示例:
public class DrawImage extends JFrame {
private static final long serialVersionUID = 1L;
Image img;
public DrawImage() {
URL imgUrl = DrawImage.class.getResource("img.jpg");// 获取图片资源的路径
img = Toolkit.getDefaultToolkit().getImage(imgUrl); // 获取图片资源
this.setSize(440, 300); // 设置窗体大小
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置窗体关闭模式
add(new CanvasPanel()); // 设置窗体面板为绘图面板对象
this.setTitle("绘制图片"); // 设置窗体标题
}
public static void main(String[] args) {
new DrawImage().setVisible(true);
}
class CanvasPanel extends Canvas {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(img, 0, 0, this); // 显示图片
}
}
}
6.图像处理
- 放大与缩小
该功能只能通过AWT的绘图功能来实现,使用JLabel标签的添加图片是无法实现的,他无法改变图片大小。修改大小后调用repaint()重绘图片,repaint()方法将调用paint()方法,实现组件或画板的重画功能,类似于界面刷新。
方法 |
说明 |
public abstract boolean drawImage(Image img,int x,int y,int width,int height,ImageObserver observer) |
绘制指定图像中已缩放到适合指定矩形内部的图像。 |
示例:
public class ImageZoom extends JFrame {
private static final long serialVersionUID = 1L;
Image img;
private JPanel contentPanel = null;
private JSlider jSlider = null;
private int imgWidth, imgHeight;
private Canvas canvas = null;
public ImageZoom() {
initialize(); // 调用初始化方法
}
// 界面初始化方法
private void initialize() {
URL imgUrl = ImageZoom.class.getResource("img.jpg");// 获取图片资源的路径
img = Toolkit.getDefaultToolkit().getImage(imgUrl);// 获取图片资源
canvas = new MyCanvas();
this.setBounds(100, 100, 800, 600); // 设置窗体大小和位置
this.setContentPane(getContentPanel()); // 设置内容面板
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置窗体关闭模式
this.setTitle("绘制图片"); // 设置窗体标题
}
// 内容面板的布局
private JPanel getContentPanel() {
if (contentPanel == null) {
contentPanel = new JPanel();
contentPanel.setLayout(new BorderLayout());
contentPanel.add(getJSlider(), BorderLayout.SOUTH);
contentPanel.add(canvas, BorderLayout.CENTER);
}
return contentPanel;
}
// 获取滑块组件
private JSlider getJSlider() {
if (jSlider == null) {
jSlider = new JSlider();
jSlider.setMaximum(1000);
jSlider.setValue(100);
jSlider.setMinimum(1);
jSlider.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent e) {
canvas.repaint();
}
});
}
return jSlider;
}
// 主方法
public static void main(String[] args) {
new ImageZoom().setVisible(true);
}
// 画板类
class MyCanvas extends Canvas {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
int newW = 0, newH = 0;
imgWidth = img.getWidth(this); // 获取图片宽度
imgHeight = img.getHeight(this); // 获取图片高度
float value = jSlider.getValue();// 滑块组件的取值
newW = (int) (imgWidth * value / 100);// 计算图片放大后的宽度
newH = (int) (imgHeight * value / 100);// 计算图片放大后的高度
g.drawImage(img, 0, 0, newW, newH, this);// 绘制指定大小的图片
}
}
}
方法 |
说明 |
public abstract boolean drawImage(Image img,int dx1,int dy1,int dx2,int dy2,int sx1,int sy1,int sx2,int sy2,ImageObserver observer) |
绘制当前可用的指定图像的指定区域,动态地缩放图像使其符合目标绘制表面的指定区域。透明像素不影响该处已存在的像素。此方法总是用图像的非缩放版本来呈现缩放的矩形,并且动态地执行所需的缩放。此操作不使用图像的缓存的、缩放版本。执行图像从源到目标的缩放,这样源矩形的第一个坐标被映射到目标矩形的第一个坐标,第二个源坐标被映射到第二个目标坐标。按需要缩放和翻转子图像以保持这些映射关系。 |
- 图像旋转
图像旋转需要调用Graphics2D类的rotate()方法,Graphics不能实现该效果。
方法 |
说明 |
public abstract void rotate(double theta) |
图像旋转,theta :旋转的角度,以弧度表示 |
注意:rotate()方法只接受旋转的弧度作为参数,可以使用Math类的toRadians()方法将角度转换为弧度,此方法接受角度值作为参数。
- 图像倾斜
使用Graphics2D类提供的shear()方法设置绘图的倾斜方向。
方法 |
说明 |
public abstract void shear(double shx,double shy) |
使图像倾斜,shx : 在正 X 轴方向移动坐标的乘数,它可以作为其 Y 坐标的函数;shy : 在正 Y 轴方向移动坐标的乘数,它可以作为其 X 坐标的函数 |