画笔Graphics

Java中提供了Graphics类,他是一个抽象的画笔,可以在Canvas组件(画布)上绘制丰富多彩的几何图和位图。
Graphics常用的画图方法如下:
  • drawLine(): 绘制直线
  • drawString(): 绘制字符串
  • drawRect(): 绘制矩形
  • drawRoundRect(): 绘制带圆角的矩形
  • drawOval():绘制椭圆形
  • drawPolygon():绘制多边形边框
  • drawArc():绘制一段圆弧(可能是椭圆的圆弧)
  • drawPolyline():绘制折线
  • fillRect():填充一个矩形区域
  • fillRoundRect():填充一个圆角矩形区域
  • fillOval():填充椭圆形
  • fillPolygon():填充多边形边框
  • fillArc():填充一段圆弧(可能是椭圆的圆弧)
  • drawImage():绘制位图
AWT专门提供了一个Canvas类作为绘图的画布,程序可以通过创建Canvas的子类,并重写它的paint()方法来实现绘图。
测试代码:
  • Canvas()画布类 paint方法画图,方法中传入画笔形参
  • Canvas()画布类 setSize(250,250);方法设置画布大小
  • Canvas()画布类 repaint(); //清除后重新绘制
  • Graphics().setColor方法设置画笔颜色,画笔执行画图动作(红色值,绿色值,蓝色值) 红绿蓝三色取值范围0-255 组合起来可以组成人类可见的任何颜色
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.concurrent.atomic.AtomicReference; /**
* @ClassName DrawSimple
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/7.
*/
public class DrawSimple {
public static void main(String[] args) {
//窗口
Frame frame = new Frame("简单画图示例"); //窗口关闭按钮动作
WindowListener closeListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("窗口关闭");
System.exit(0);
}
};
frame.addWindowListener(closeListener);
//绘制图形形状变量
AtomicReference<String> shape = new AtomicReference<>();
//画布
Canvas canvas = new Canvas(){
Random random = new Random();
@Override
public void paint(Graphics g) { //g为画笔
System.out.println("画图中");
if (shape.get() != null){
switch (shape.get()){
case "rect":
//设置画笔颜色Color(红色值,绿色值,蓝色值) 红绿蓝三色取值范围0-255 组合起来可以组成人类可见的任何颜色
g.setColor(new Color(255,0,0));
//画矩形,x,y分别为起始位置,后面两个参数为宽,高 Random.nextInt(200) 为伪随机数
g.drawRect(20,20,random.nextInt(200),random.nextInt(200));
break;
case "oval":
//画椭圆
g.setColor(new Color(10,100,30));
g.drawOval(40,20,random.nextInt(200),random.nextInt(200));
}
}
}
};
canvas.setSize(250,250);
frame.add(canvas); //容器
Panel panel = new Panel();
//按钮
Button drawRectBtn = new Button("画矩形");
Button drawOvalBtn = new Button("画椭圆");
//按钮绑定事件
drawRectBtn.addActionListener(e ->{
shape.set("rect");
canvas.repaint(); //清除后重新绘制
});
drawOvalBtn.addActionListener(e ->{
shape.set("oval");
canvas.repaint(); //清除后重新绘制
});
panel.add(drawOvalBtn);
panel.add(drawRectBtn);
frame.add(panel,BorderLayout.SOUTH);
//窗口自动调整大小
frame.setLocation(400,300);
frame.pack();
frame.setVisible(true);
}
}

开发弹球小游戏

开发思路:动画,就是间隔一定的时间(通常小于1秒)重新绘制新的图像,两次绘制的图像之间差异较小,肉眼看起来就成了所谓的动画。这个程序我们要借助Swing包的一个Timer类。
Timer(int delay, ActionListener listener): 每间隔delay秒,系统自动出发ActionListener监听器里的事件处理器(actionPerformed方法)
知识点:
  • KeyListener 实现监听键盘按键 触发移动球拍
  • 画图逻辑:球到了画布的X轴左右端,向相反方向移动位置,到了Y轴顶端位置0,或者到了球拍接触区域向相反方向移动位置
  • Timer定时器,每隔毫秒级别重新画图
  • 用到的变量全部定义为类变量

 示例代码:

import com.sun.source.tree.NewClassTree;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random; /**
* @ClassName Pinball
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/7.
*/
public class Pinball {
//定义球拍初始位置用随机对象
private Random random = new Random();
/**
* 设置画布大小:宽高
*/
private int canvaWidth = 300;
private int canvaHeight = 400;
/**
* 球拍初始参数
*/
//拍子大小位置
private int rectX = random.nextInt(200); //拍子所在横坐标位置,要在画布范围之内,
private int rectY = 355; //拍子所在Y轴坐标位置小于400,和底部留一定空隙
private int rectWidth = 60; //宽度60
private int rectHeight = 15; //厚度
//拍子按下按键拍子移动的像素大小(步伐)
int pace =10; /**
* 小球的尺寸位置初始参数
*/
private int ballSize =15;
private int ballX = random.nextInt(200);
private int ballY = random.nextInt(100); /**
* 小球运动速度值
*/
private int ballYSpeed = 5; //Y 轴移动速度
private double xyRate = random.nextDouble() - 0.5; //X轴相对比Y轴运动速度的比率,返回一个-0.5 ~0.5之间的数,移动方向为向左或者向右
private int ballXSpeed = (int) (ballYSpeed * xyRate * 2); // X 轴运动的速度 /**
* 定时器Timer
*/
private Timer timer; /**
* 游戏是否结束
*/
private boolean gameOver = false; /**
* 方法
*/
public void play(){
/**
* 定义窗口,设置位置和关闭动作
*/
Frame frame = new Frame("弹球小游戏");
frame.setLocation(400,300);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("关闭游戏");
System.exit(0);
}
}); /**
* 定义画布
*/
Canvas canvas = new Canvas(){
@Override
public void paint(Graphics g) {
//如果没有结束
if (!gameOver){
//画球
g.setColor(new Color(30,200,150));
g.fillOval(ballX,ballY,ballSize, ballSize);
//画下面的矩形拍子
g.setColor(new Color(75, 79, 194));
g.fillRect(rectX, rectY, rectWidth, rectHeight);
}else { //gameOver了
g.setColor(Color.RED);
g.setFont(new Font("Times",Font.BOLD,30)); // 设置字体格式字体
g.drawString("Game Over",70, 200);
}
}
};
//设置画布大小
canvas.setPreferredSize(new Dimension(canvaWidth,canvaHeight));
frame.add(canvas);
/**
* 游戏核心逻辑:动画效果
*/
timer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
/**
* 如果到了X轴的两端,就向反方向画图
*/
if (ballX < 0 || ballX >= canvaWidth - ballSize)
ballXSpeed = -ballXSpeed;
/**
* 如果球接触到了球拍的X轴和Y轴区域内,或者跑到顶端(ballY 坐标小于0)就把Y轴反向移动
*/
if (ballY < 0 || (ballY >= rectY - ballSize && ballY < rectY - ballSize/2) && ballX + ballSize /2 >= rectX && ballX + ballSize /2 <= rectX + rectWidth) {
System.out.println("ballX:"+ ballX + "ballY:"+ ballY + "rectX:" + rectX + "rectY:" +rectY);
ballYSpeed = -ballYSpeed; //反向速度
}else if (ballY >= canvaHeight){ //如果球已经掉到画布之外或者 球拍下 就停止timer循环
timer.stop();
gameOver = true;
}
ballX += ballXSpeed;
ballY += ballYSpeed;
canvas.repaint();
}
});
timer.start();
/**
* 窗口监听键盘
*/
KeyListener keyListener = new KeyAdapter() { //添加键盘监听器
@Override
public void keyPressed(KeyEvent e) { //当键盘被按下时触发
// System.out.println("按下键盘");
int KeyCode = e.getKeyCode(); //获取按下的键盘代号
switch (KeyCode){
case KeyEvent.VK_LEFT://左键按下
if(rectX - pace > 0){
rectX -= pace;
}else {
rectX = 0;
}
break;
case KeyEvent.VK_RIGHT://右键按下
if (rectX + pace < canvaWidth - rectWidth){
rectX += pace;
}else {
rectX = canvaWidth -rectWidth;
}
break;
}
canvas.repaint();
}
};
frame.addKeyListener(keyListener);
/**
* 窗口大小自动调节到最优,显示窗口
*/
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Pinball().play();
}
}

最新文章

  1. runtime-对成员变量操作应用之归档和返归档
  2. Block知识点总结
  3. iOS开发 解决UITapGestureRecognizer手势与UITableView的点击事件的冲突
  4. Java实现文件压缩与解压
  5. iOS网络请求之multipart/form-data提交数据
  6. 深入解读A/B 测试的统计学原理
  7. Cache-control使用Cache-control:private学习笔记
  8. JavaScript系列:再巩固-原型链
  9. Java为什么使用连接池
  10. C++设计模式之建造模式
  11. mongodb副本集出现的错误 mongodb error: { MongoNetworkError: failed to connect to server [127.0.0.1:1010] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:1010]
  12. Blob CLOB区别
  13. Exp3
  14. js调试系列: 断点与动态调试[基础篇]
  15. 洛谷P4197 Peaks&amp;&amp;克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)
  16. 远程视频监控之应用篇(mjpg-streamer)
  17. Python class的属性访问控制和内建函数重写实现高级功能以及@property
  18. 非常不错的app和网站
  19. pid参数调节的几句话
  20. [leetcode-640-Solve the Equation]

热门文章

  1. 【JavaSE】集合
  2. docker详细
  3. (前端)面试300问之(3)this的指向判断
  4. CSS动画--让div动起来
  5. [USACO17FEB]Why Did the Cow Cross the Road III P
  6. Webpack 打包 Javascript 详细介绍
  7. 非寻常方式学习ApacheTomcat架构及10.0.12源码编译
  8. C# / VB.NET 在Word中嵌入多媒体(视频、音频)文件
  9. ctfshow WEB入门 信息收集 1-20
  10. A Child&#39;s History of England.2