仓库 :Java图形化界面: Java图形化界面学习demo与资料 (gitee.com)
很多程序如各种小游戏都需要在窗口中绘制各种图形,除此之外,即使在开发JavaEE项目时, 有 时候也必须"动态"地向客户 端生成各种图形、图表,比如 图形验证码、统计图等,这都需要利用AWT的绘图功能。
组件绘图原理
之前我们已经学习过很多组件,例如Button、Frame、Checkbox等等,不同的组件,展示出来的图形都不一样,其实这些组件展示出来的图形,其本质就是用AWT的绘图来完成的。
在AWT中,真正提供绘图功能的是Graphics对象,那么Component组件和Graphics对象存在什么关系,才能让Component绘制自身图形呢?在Component类中,提供了下列三个方法来完成组件图形的绘制与刷新:
paint(Graphics g):绘制组件的外观;
update(Graphics g):内部调用paint方法,刷新组件外观;
repaint():调用update方法,刷新组件外观;
一般情况下,update和paint方法是由AWT系统负责调用,如果程序要希望系统重新绘制组件,可以调用repaint方法完成。
Graphics类的使用
实际生活中如果需要画图,首先我们得准备一张纸,然后在拿一支画笔,配和一些颜色,就可以在纸上画出来各种各样的图形,例如圆圈、矩形等等。
程序中绘图也一样,也需要画布,画笔,颜料等等。AWT中提供了Canvas类充当画布,提供了Graphics类来充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色。
画图的步骤:
1.自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图;
2.在paint方法内部,真正开始画图之前调用Graphics对象的setColor()、setFont()等方法设置画笔的颜色、字体等属性;
3.调用Graphics画笔的drawXxx()方法开始画图。
其实画图的核心就在于使用Graphics画笔在Canvas画布上画出什么颜色、什么样式的图形,所以核心在画笔上,下表中列出了Graphics类中常用的一些方法:
案例:
使用AWT绘图API,完成下图效果
演示代码:
java
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class SimpleDraw {
private final String RECT_SHAPE="rect";
private final String OVAL_SHAPE="oval";
private Frame frame = new Frame("这里测试绘图");
private Button drawRectBtn = new Button("绘制矩形");
private Button drawOvalBtn = new Button("绘制椭圆");
//用来保存当前用户需要绘制什么样的图形
private String shape="";
private MyCanvas drawArea = new MyCanvas();
public void init(){
//为按钮添加点击事件
drawRectBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
shape = RECT_SHAPE;
drawArea.repaint();
}
});
drawOvalBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
shape = OVAL_SHAPE;
drawArea.repaint();
}
});
//定义一个Panel,装载两个按钮
Panel p = new Panel();
p.add(drawRectBtn);
p.add(drawOvalBtn);
//把panel添加到frame底部
frame.add(p,BorderLayout.SOUTH);
//设置画布的大小
drawArea.setPreferredSize(new Dimension(300,200));
//把画布添加到frame中
frame.add(drawArea);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new SimpleDraw().init();
}
//1.自定义类,继承Canvas类,重写paint方法
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
Random r = new Random();
if (shape.equals(RECT_SHAPE)){
//绘制矩形
g.setColor(Color.BLACK);
g.drawRect(r.nextInt(200),r.nextInt(100),40,60);
}
if(shape.equals(OVAL_SHAPE)){
//绘制椭圆
g.setColor(Color.RED);
g.drawOval(r.nextInt(200),r.nextInt(100),60,40);
}
}
}
}
Java也可用于开发一些动画。所谓动画,就是间隔一定的时间(通常小于0 . 1秒 )重新绘制新的图像,两次绘制的图像之间差异较小,肉眼看起来就成了所谓的动画 。
为了实现间隔一定的时间就重新调用组件的 repaint()方法,可以借助于 Swing 提供的Timer类,Timer类是一个定时器, 它有如下一个构造器 :Timer(int delay, ActionListener listener): 每间隔 delay 毫秒,系统自动触发 ActionListener 监听器里的事件处理器方法,在方法内部我们就可以调用组件的repaint方法,完成组件重绘。
案例2:
使用AWT画图技术及Timer定时器,完成下图中弹球小游戏。
演示代码2:
java
package awt_swimg.day03;
import awt_swimg.day01.Utils;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PinBall {
//桌面宽度
private final int TABLE_WIDTH = 300;
//桌面高度
private final int TABLE_HEIGHT = 400;
//球拍的高度和宽度
private final int RACKET_WIDTH = 60;
private final int RACKET_HEIGHT = 20;
//小球的大小
private final int BALL_SIZE = 16;
//定义小球纵向运行速度
private int ySpeed = 10;
//小球横向运行速度
private int xSpeed = 5;
//定义小球的初始坐标
private int ballX = 120;
private int ballY = 20;
//定义球拍的初始坐标,x坐标会发生变化,y坐标不会发生变化
private int RACKET_X = 120;
private final int RACKET_Y = 340;
//声明定时器
private Timer timer;
private JFrame frame=new JFrame("弹球游戏");
private MyCanvas canvas=new MyCanvas();
//定义游戏结束的标记
private boolean isLose = false;
private KeyListener event = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT) {
if (RACKET_X > 0) {
RACKET_X -= 10;
}
}
if (keyCode == KeyEvent.VK_RIGHT) {
if (RACKET_X < TABLE_WIDTH - RACKET_WIDTH) {
RACKET_X += 10;
}
}
}
};
private ActionListener timerTask=new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (ballX<=0||ballX>=TABLE_WIDTH-BALL_SIZE) {
xSpeed=-xSpeed;
}
if (ballY<=0||ballY>=RACKET_Y-BALL_SIZE&&ballX>= RACKET_X &&ballX<= RACKET_X +RACKET_WIDTH) {
ySpeed = -ySpeed;
}
if (ballY>RACKET_Y&&(ballX<RACKET_X||ballX>RACKET_X+RACKET_WIDTH)) {
timer.stop();
isLose=true;
canvas.repaint();
}
ballX += xSpeed;
ballY += ySpeed;
canvas.repaint();
}
};
private MenuBar menuBar=new MenuBar();
private Menu option=new Menu("选项");
private MenuItem reStart=new MenuItem("重新开始");
private MenuItem exit=new MenuItem("退出");
public void init(){
frame.add(canvas);
frame.setMenuBar(menuBar);
menuBar.add(option);
option.add(reStart);
option.add(exit);
exit.addActionListener(e -> System.exit(0));
reStart.addActionListener(e -> {
isLose=false;
ballX = 120;
ballY = 20;
RACKET_X = 120;
canvas.repaint();
timer.start();
});
canvas.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));
canvas.addKeyListener(event);
frame.addKeyListener(event);
timer=new Timer(50,timerTask);
timer.start();
Utils.setJFrame(frame);
}
public static void main(String[] args) {
new PinBall().init();
}
public class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
if (isLose) {
g.setColor(Color.BLUE);
g.setFont(new Font("Times",Font.BOLD,30));
g.drawString("游戏结束!",80,200);
}else{
g.setColor(Color.red);
g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE);
g.setColor(Color.green);
g.fillRect(RACKET_X, RACKET_Y, RACKET_WIDTH, RACKET_HEIGHT);
}
}
}
}