AWT编程 · 语雀
仓库:Java图形化界面: Java图形化界面学习demo与资料 (gitee.com)
如果仅仅绘制一些简单的几何图形,程序的图形效果依然比较单调 。 AWT 也允许在组件上绘制位图, Graphics 提供了 drawlmage() 方法用于绘制位图,该方法需要一个Image参数一一代表位图,通过该方法就可 以绘制出指定的位图 。
位图使用步骤:
1.创建Image的子类对象BufferedImage(int width,int height,int ImageType),创建时需要指定位图的宽高及类型属性;此时相当于在内存中生成了一张图片;
2.调用BufferedImage对象的getGraphics()方法获取画笔,此时就可以往内存中的这张图片上绘图了,绘图的方法和之前学习的一模一样;
3.调用组件的drawImage()方法,一次性的内存中的图片BufferedImage绘制到特定的组件上。
使用位图绘制组件的好处:
使用位图来绘制组件,相当于实现了图的缓冲区,此时绘图时没有直接把图形绘制到组件上,而是先绘制到内存中的BufferedImage上,等全部绘制完毕,再一次性的图像显示到组件上即可,这样用户的体验会好一些。
案例:
通过BufferedImage实现一个简单的手绘程序:通过鼠标可以在窗口中画图。
演示代码:
package awt_swimg.day04;
import awt_swimg.day01.Utils;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class HandDraw {
//定义画图区的宽高
private final int AREA_WIDTH = 500;
private final int AREA_HEIGHT = 400;
//定义变量,保存上一次鼠标拖动时,鼠标的坐标
private int preX = -1;
private int preY = -1;
//定义一个右键菜单,用于设置画笔的颜色
private PopupMenu popupMenu=new PopupMenu();
private MenuItem redItem = new MenuItem("红色");
private MenuItem greenItem = new MenuItem("绿色");
private MenuItem buleItem = new MenuItem("蓝色");
//定义一个BufferedImage对象
private BufferedImage image = new BufferedImage(AREA_WIDTH, AREA_HEIGHT, BufferedImage.TYPE_INT_RGB);
//获取BufferedImage对象关联的画笔
private Graphics g=image.getGraphics();
//定义窗口对象
private JFrame frame = new JFrame("简单手绘程序");
//定义画布对象
private Canvas canvas=new Canvas(){
@Override
public void paint(Graphics g) {
g.drawImage(image,0,0,null);
}
};
//定义一个Color对象,用来保存用户设置的画笔颜色,默认为黑色
private Color color = Color.BLACK;
public void init(){
redItem.addActionListener(e -> color = Color.red);
greenItem.addActionListener(e -> color = Color.GREEN);
buleItem.addActionListener(e -> color = Color.BLUE);
canvas.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
popupMenu.show(canvas, e.getX(), e.getY());
}
preX = -1;
preY = -1;
}
});
canvas.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if (preX > 0 && preY > 0) {
g.setColor(color);
g.drawLine(preX, preY, e.getX(), e.getY());
}
preX = e.getX();
preY = e.getY();
canvas.repaint();
}
});
g.fillRect(0,0,AREA_WIDTH,AREA_HEIGHT);
canvas.setPreferredSize(new Dimension(AREA_WIDTH,AREA_HEIGHT));
canvas.add(popupMenu);
popupMenu.add(redItem);
popupMenu.add(greenItem);
popupMenu.add(buleItem);
frame.add(canvas);
Utils.setJFrame(frame);
}
public static void main(String[] args) {
new HandDraw().init();
}
}
在实际生活中,很多软件都支持打开本地磁盘已经存在的图片,然后进行编辑,编辑完毕后,再重新保存到本地磁盘。如果使用AWT要完成这样的功能,那么需要使用到ImageIO这个类,可以操作本地磁盘的图片文件。
方法名称 |
方法功能 |
static BufferedImage read(File input) |
读取本地磁盘图片文件 |
static BufferedImage read(InputStream input) |
读取本地磁盘图片文件 |
static boolean write(RenderedImage im, String formatName, File output) |
往本地磁盘中输出图片文件 |
案例:
编写图片查看程序,支持另存操作
演示代码:
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public class ReadAndSaveImage {
private Frame frame = new Frame("图片查看器");
private BufferedImage image;
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
if (image!=null){
g.drawImage(image,0,0,image.getWidth(),image.getHeight(),null);
}
}
}
private MyCanvas imageComponent = new MyCanvas();
public void init() throws Exception{
//设置菜单项
MenuBar mb = new MenuBar();
Menu menu = new Menu("文件");
MenuItem openItem = new MenuItem("打开");
MenuItem saveItem = new MenuItem("另存为");
openItem.addActionListener(e -> {
//弹出对话框,选择本地图片
FileDialog oDialog = new FileDialog(frame);
oDialog.setVisible(true);
//读取用户选择的图片
String dir = oDialog.getDirectory();
String file = oDialog.getFile();
try {
image = ImageIO.read(new File(dir,file));
imageComponent.repaint();
} catch (IOException e1) {
e1.printStackTrace();
}
});
saveItem.addActionListener(e -> {
//弹出对话框,另存为
FileDialog sDialog = new FileDialog(frame,"保存图片",FileDialog.SAVE);
sDialog.setVisible(true);
String dir = sDialog.getDirectory();
String file = sDialog.getFile();
try {
ImageIO.write(image,"JPEG",new File(dir,file));
} catch (IOException e1) {
e1.printStackTrace();
}
});
mb.add(menu);
menu.add(openItem);
menu.add(saveItem);
frame.setMenuBar(mb);
frame.add(imageComponent);
frame.setBounds(200,200,800,600);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) throws Exception {
new ReadAndSaveImage().init();
}
}
接下来,我们使用之前学习的绘图技术,做一个五子棋的游戏。
演示代码:
package awt_swimg.day04;
import awt_swimg.day01.Utils;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Gobang {
//定义三个BufferedImage,分别代表棋盘图、黑子图、白子图
private BufferedImage table;
private BufferedImage black;
private BufferedImage white;
//定义一个BufferedImage,代表当鼠标移动时将要下子的选择框
private BufferedImage selected;
//定义棋盘的宽高,这里的定义尺寸和给定的board.jpg图片的尺寸一致因为棋盘背景是通过图片加载的
private final int TABLE_WIDTH = 535;
private final int TABLE_HEIGHT = 536;
//定义棋盘中,每行和每列可下子的数目,这个数目跟给定的board.jpg中的数目是一致的,都为15
private final int BOARD_SIZE = 15;
//定义每个棋子所占棋盘总宽度的大小比率;每个棋子所占宽度 535/15=35
private final int RATE = TABLE_WIDTH / BOARD_SIZE;
//定义棋盘有效区域与背景图坐标之间的偏移值,x坐标右移5个像素,y坐标下移6个像素
private final int X_OFFSET = 5;
private final int Y_OFFSET = 6;
/*
定义一个二维数组充当棋盘上每个位置处的棋子;
该数组的索引与该棋子在棋盘上的坐标需要有一个对应关系:
例如: 索引[2][3]处的棋子,对一个的真实绘制坐标应该是:
xpos = 2*RATE+X_OFFSET=75;
ypos = 3*RATE+Y_OFFSET=111;
*/
private int[][] board = new int[BOARD_SIZE][BOARD_SIZE];//如果存储0,代表没有棋子,如果存储1,代表黑棋,如果存储2,代表白棋
//定义五子棋游戏窗口
private JFrame frame = new JFrame("五子棋游戏");
//定义变量,记录当前选中的坐标点对应的boad数组中对应的棋子索引;
private int selectX = -1;
private int selectY = -1;
//定义一个变量,记录当前用户选择下的是白棋还是黑棋还是清除,清除:0,黑棋:1,白棋:2;
private int chessCategory = 1;
private JPanel canvas = new JPanel() {
@Override
public void paint(Graphics g) {
g.drawImage(table, 0, 0, null);
if (selectX > 0 && selectY > 0) {
g.drawImage(selected, selectX * RATE + X_OFFSET, selectY * RATE + Y_OFFSET, null);
}
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] == 2) {
g.drawImage(white, i * RATE + X_OFFSET, j * RATE + Y_OFFSET, null);
}
if (board[i][j] == 1) {
g.drawImage(black, i * RATE + X_OFFSET, j * RATE + Y_OFFSET, null);
}
}
}
}
};
private Panel panel = new Panel();
private Button whiteChess = new Button("白棋");
private Button blackChess = new Button("黑棋");
private Button delete = new Button("删除");
public void init() throws IOException {
//初始化数组,默认
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
board[i][j] = 0;
}
}
canvas.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
selectX = (e.getX() - X_OFFSET) / RATE;
selectY = (e.getY() - Y_OFFSET) / RATE;
canvas.repaint();
}
});
canvas.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int xChess = (e.getX() - X_OFFSET) / RATE;
int yChess = (e.getY() - Y_OFFSET) / RATE;
board[xChess][yChess] = chessCategory;
canvas.repaint();
}
@Override
public void mouseExited(MouseEvent e) {
selectX = -1;
selectY = -1;
canvas.repaint();
}
});
whiteChess.addActionListener(e -> {
chessCategory = 2;
this.setButtonColor(Color.green,Color.white,Color.white);
});
blackChess.addActionListener(e -> {
chessCategory = 1;
this.setButtonColor(Color.white,Color.green,Color.white);
});
delete.addActionListener(e -> {
chessCategory = 0;
this.setButtonColor(Color.white,Color.white,Color.green);
});
table = ImageIO.read(new File("src/awt_swimg/img/board.jpg"));
white = ImageIO.read(new File("src/awt_swimg/img/white.gif"));
black = ImageIO.read(new File("src/awt_swimg/img/black.gif"));
selected = ImageIO.read(new File("src/awt_swimg/img/selected.gif"));
canvas.setPreferredSize(new Dimension(table.getWidth(), table.getHeight()));
panel.add(whiteChess);
panel.add(blackChess);
panel.add(delete);
frame.add(canvas);
frame.add(panel, BorderLayout.SOUTH);
Utils.setJFrame(frame);
}
public void setButtonColor(Color w,Color b ,Color d){
whiteChess.setBackground(w);
blackChess.setBackground(b);
delete.setBackground(d);
}
public static void main(String[] args) throws IOException {
new Gobang().init();
}
}