AWT允许在组件上绘制位图,Graphics提供了drawImage方法用于绘制位图,该方法需要一个Image参数——代表位图,通过该方法就可以绘制出指定的位图。
(一)Image抽象类和BufferedImage实现类
Image类代表位图,但它是一个抽象类,无法直接创建Image对象,为此Java为它提供了一个BufferedImage子类,这个子类是一个可访问图像数据缓冲区的Image实现类。
BufferedImage类提供了一个简单的构造器,用于创建一个BufferedImage对象:
(1)BufferedImage(int width, int height, int imageType):创建指定大小、指定图像类型的BufferedImage对象、其中ImageType可以是BufferedImage.TYPE_INT_RGB、BufferedImage.TYPE_BYTE_GRAY等值
除此之外,BufferedImage还提供了一个getGraphics()方法返回该对象的Graphics对象,从而允许通过该Graphics对象向Image中添加图形
借助于BufferedImage的帮助,我们可以在AWT中实现缓冲技术——当需要向GUI组件上绘制图形时,不要直接绘制到该GUI组件上,而是先将图形绘制到BufferedImage对象中,然后再调用组件的drawImage方法一次性地将BufferedImage对象绘制到特定组件上
/**
* 程序通过BufferedImage类实现了图形缓冲,并实现了一个简单的手绘程序
*/
package codes11;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
public class HandDraw {
// 画图区的宽度
private final int AREA_WIDTH = 500;
// 画图区的高度
private final int AREA_HEIGHT = 400;
// 下面preX、preY保存了上一次鼠标拖动事件的鼠标坐标
private int preX = -1;
private int preY = -1;
// 定义一个右键菜单用于设置画笔颜色
PopupMenu pop = new PopupMenu();
MenuItem redItem = new MenuItem("红色");
MenuItem greenItem = new MenuItem("绿色");
MenuItem blueItem = new MenuItem("蓝色");
// 定义一个BufferedImage对象
BufferedImage image = new BufferedImage(AREA_WIDTH, AREA_HEIGHT,
BufferedImage.TYPE_INT_RGB);
// 获取image对象的Graphics
Graphics g = image.getGraphics();
private Frame f = new Frame("简单手绘程序");
private DrawCanvas drawArea = new DrawCanvas();
// 用于保存画笔颜色
private Color foreColor = new Color(255, 0, 0);
public void init() {
// 定义右键菜单的事件监听器
ActionListener menuListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("红色")) {
foreColor = new Color(255, 0, 0);
}
if (e.getActionCommand().equals("绿色")) {
foreColor = new Color(0, 255, 0);
}
if (e.getActionCommand().equals("蓝色")) {
foreColor = new Color(0, 0, 255);
}
}
};
// 为三个菜单添加事件监听器
redItem.addActionListener(menuListener);
greenItem.addActionListener(menuListener);
blueItem.addActionListener(menuListener);
// 将菜单项组合成右键菜单
pop.add(redItem);
pop.add(greenItem);
pop.add(blueItem);
// 将右键菜单添加到drawArea对象中
drawArea.add(pop);
// 将image对象的背景色填充成白色
g.fillRect(0, 0, AREA_WIDTH, AREA_HEIGHT);
drawArea.setPreferredSize(new Dimension(AREA_WIDTH, AREA_HEIGHT));
// 监听鼠标移动动作
drawArea.addMouseMotionListener(new MouseMotionAdapter() {
// 实现按下鼠标键并拖动的事件处理器
@Override
public void mouseDragged(MouseEvent e) {
// 如果preX和preY大于0
if (preX > 0 && preY > 0) {
// 设置当前颜色
g.setColor(foreColor);
// 绘制从上一次鼠标拖动事件点到本次鼠标拖动事件点的线段
g.drawLine(preX, preY, e.getX(), e.getY());
}
// 将当前鼠标事件点的X、Y坐标保存起来
preX = e.getX();
preY = e.getY();
// 重绘drawArea对象
drawArea.repaint();
}
});
// 监听鼠标事件
drawArea.addMouseListener(new MouseAdapter() {
// 实现鼠标键松开的事件处理器
public void mouseReleased(MouseEvent e) {
// 弹出右键菜单
if (e.isPopupTrigger()) {
pop.show(drawArea, e.getX(), e.getY());
}
// 松开鼠标时,把上一次鼠标拖动时间的X、Y坐标设为-1
preX = -1;
preY = -1;
}
});
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.add(drawArea);
f.pack();
f.setVisible(true);
}
class DrawCanvas extends Canvas {
// 重写Canvas的paint方法,实现绘图
public void paint(Graphics g) {
// 将image绘制到该组件上
g.drawImage(image, 0, 0, null);
}
}
public static void main(String[] args) {
new HandDraw().init();
}
}
(二)使用ImageIO输入/输出位图
如果希望可以访问磁盘上的位图文件,例如GIF、JPG等格式的位图,则需要利用ImageIO工具类。ImageIO利用ImageReader和Imagewriter读写图形文件,通常程序无须关心该类底层的细节,只需要利用该工具类来读写图形文件即可。
ImageIO类并不支持读写全部格式的图形文件,程序可以通过ImageIO类的如下几个静态方法来访问该类所支持读写的图形文件格式:
(1)static String[] getReaderFileSuffixes():返回一个String数组,该数组列出ImageIO所有能读的图形文件的后缀
(2)static String[] getReaderFormatNames():返回一个String数组,该数组列出ImageIO所有能读的图形文件的非正式格式名称
(3)static String[] getWriterFileSuffixes():返回一个String数组,该数组列出ImageIO所有能写的图形文件的后缀
(4)static String[] getWriterFormatNames():返回一个String数组,该数组列出ImageIO所有能写的图形文件的非正式格式名称
/**
* 程序测试了ImageIO所支持读写的全部文件格式
*/
package codes11;
import javax.imageio.ImageIO;
public class ImageIOTest {
public static void main(String[] args) {
String[] readFormat = ImageIO.getReaderFormatNames();
System.out.println("-----Image 能读的所有图形文件格式-----");
for (String tmp : readFormat) {
System.out.println(tmp);
}
String[] writeFormat = ImageIO.getWriterFormatNames();
System.out.println("-----Image 能写的所有图形文件格式-----");
for (String tmp : writeFormat) {
System.out.println(tmp);
}
}
}
运行程序,输入结果如下:
-----Image 能读的所有图形文件格式-----
JPG
jpg
bmp
BMP
gif
GIF
WBMP
png
PNG
jpeg
wbmp
JPEG
-----Image 能写的所有图形文件格式-----
JPG
jpg
bmp
BMP
gif
GIF
WBMP
png
PNG
wbmp
jpeg
JPEG
ImageIO类包含两个静态方法:read()和writer(),通过这两个方法即可完成对位图文件的读写,调用write()方法输出图形文件时需要指定输出的图形格式,例如GIF、JPEG等