Java一个简单的反弹动画练习

embedded/2025/1/11 9:18:29/

文章目录

  • 说明
  • 代码详解
    • 创建窗体代码
    • 创建绘图板
    • 创建线程
  • 运行结果
  • 完整代码

说明

做了一个小球和星型做反弹动画的窗体作为练习,分享给大家,为了方便和我一样的小白可以看的比较明白,所以尽量详细的标注了注释,希望能帮到同样在学习路上的朋友

代码详解

创建窗体代码

java">public class AnimationJFrame extends JFrame {//实例化属性private final DrawCircleAndStar drawCircleAndStar = new DrawCircleAndStar();//实例化图形绘制private final JButton jButton = new JButton();//实例化按钮private final AnimationRun animationRun = new AnimationRun();//实例化线程//设置绘图全局属性private int circleX = 0;//圆形的初始位置X坐标private int circleY = 10;//圆形的初始位置Y坐标private int circleXDirection = 1;//圆形运动X轴方向private int circleYDirection = 1;//圆形运动Y轴方向private int starX = 355;//星型的初始位置X坐标private int starY = 200;//星型的初始位置Y坐标private int starXDirection = 1;//星形运动X轴方向private int starYDirection = 1;//星形运动Y轴方向//构造方法构造窗体public AnimationJFrame(){//窗体基本设置Container conn = getContentPane();//建立窗体容器setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗体关闭方式setBounds(300,300,400,400);//设置窗体位置及大小setResizable(false);//窗体大小不可改变setLayout(null);//清空窗体布局管理器,不采用默认布局//创建动画布局JPanel jPanel = new JPanel();//实例化布局jPanel.setLayout(null);//清空布局的布局管理器,不采用默认布局jPanel.setBounds(10, 10, 365, 300);//动画布局的位置及大小jPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));//设置动画布局的边框jPanel.setBackground(Color.LIGHT_GRAY);//设置动画布局的底色//创建动画图形的标签容器JLabel jLabel = new JLabel();//实例化标签jLabel.setBounds(0,0,365,300);//设置动画标签的大小和位置//设置绘图标签drawCircleAndStar.setBackground(new Color(0,0,0,0));//设置绘图标签的背景透明drawCircleAndStar.setSize(365,300);//设置绘图标签的大小jLabel.add(drawCircleAndStar);//添加绘图板到标签jPanel.add(jLabel);//添加动画标签到动画布局//设置按键jButton.setText("开始");//设置按键显示文字jButton.setFont(new Font("黑体", Font.PLAIN, 14));//设置按键文字的字体jButton.setBounds(275, 320, 100, 22);//设置按键的位置和大小//添加原件到窗体容器conn.add(jPanel);//添加动漫布局到容器conn.add(jButton);//添加按钮到容器//给按钮添加监听jButton.addActionListener(e -> {if (e.getActionCommand().equals("开始")){jButton.setText("暂停一下");//更改按键文字animationRun.start();//启动线程}else if (e.getActionCommand().equals("暂停一下")){jButton.setText("继续");animationRun.pause();//暂停线程}else if (e.getActionCommand().equals("继续")){jButton.setText("暂停一下");animationRun.restart();//重启线程}});}

这里需要说明的是,代码中直接把窗体创建在构造方法中,但是直接在构造方法中设置窗体只适用于线程较简单的程序,如果在正式的项目中,应该避免这种写法,因为swing是线程不安全的,应该对窗体单独建立窗体方法容器,例如:

java"> public AnimationJFrame() {SwingUtilities.invokeLater(() -> {initUI();});}private void initUI() {//代码块...........}

创建绘图板

java">    //创建绘图板class DrawCircleAndStar extends JLabel{@Overridepublic void paintComponent(Graphics g){//重写paintComponentsuper.paintComponent(g);//继承父类的构造方法Graphics2D graphics2D = (Graphics2D) g;graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//设置绘图抗锯齿//绘制圆形graphics2D.setColor(Color.RED);//设置填充颜色,红色graphics2D.fillOval(circleX,circleY,15,15);//设置圆形的位置和大小//绘制星型graphics2D.setColor(Color.BLUE);//设置填充色,蓝色//设置星型的属性int radius = 10;//设置星型的大小int[] xPoints = new int[10];//星型顶点的X坐标int[] yPoints = new int[10];//星型顶点的Y坐标//计算星型顶点的坐标及初始角度for (int i = 0; i < 10; i++) {double baseAngle = i * 2 * Math.PI / 10 + Math.PI / 2;//初始角度if (i % 2 == 0) {//外围顶点的坐标xPoints[i] = starX + (int) (radius * Math.cos(baseAngle));yPoints[i] = starY - (int) (radius * Math.sin(baseAngle));} else {//内部顶点的坐标xPoints[i] = starX + (int) (radius * Math.cos(baseAngle) * 0.5);yPoints[i] = starY - (int) (radius * Math.sin(baseAngle) * 0.5);}}Polygon star = new Polygon(xPoints, yPoints, 10);//绘制星型graphics2D.fillPolygon(star);//填充星型}}

创建绘图板,别的没有什么可说的,这里切记一点,无论绘图板继承自布局还是标签,相对的布局和标签是没有大小的,必须在窗体设置中,为它们设定尺寸,比如本代码中的

java">        drawCircleAndStar.setBackground(new Color(0,0,0,0));//设置绘图标签的背景透明drawCircleAndStar.setSize(365,300);//设置绘图标签的大小

如果不设置大小,将无法将绘图板图形显示到容器

创建线程

java">    //创建运行线程class AnimationRun extends Thread{boolean flag = false;//设置挂起标志synchronized void pause(){//暂停方法flag = true;}synchronized void restart(){//重启方法notifyAll();flag = false;}//重写run@Overridepublic void run(){//动画运行while (true) {//挂起区synchronized (this){while (flag){try {wait();//等待挂起} catch (InterruptedException e) {throw new RuntimeException(e);}}}//判断圆形运动方向if (circleX == 0) {circleXDirection = 1;} else if (circleX == 350) {circleXDirection = -1;}if (circleY == 0) {circleYDirection = 1;} else if (circleY == 285) {circleYDirection = -1;}//判断星型运动方向if (starX == 10){starXDirection = 1;}else if (starX == 355){starXDirection = -1;}if (starY == 10){starYDirection = 1;}else if (starY == 290){starYDirection = -1;}//设置绘图延迟try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}//计算新的圆形位置和星型的位置circleX += circleXDirection;circleY += circleYDirection;starX += starXDirection;starY += starYDirection;//重绘绘图板drawCircleAndStar.repaint();}}}

synchronized相对来说并不是最优的选择,消耗较高,建议优化,另外一个这里重写的不是paint而是重写的paintComponent因为重写paintComponent只绘制图形主体,不会影响边框和背景,建议单独绘制元素的时候使用paintComponent而不是paint

运行结果

在这里插入图片描述

完整代码

java">import javax.swing.*;
import java.awt.*;public class AnimationJFrame extends JFrame {//实例化属性private final DrawCircleAndStar drawCircleAndStar = new DrawCircleAndStar();//实例化图形绘制private final JButton jButton = new JButton();//实例化按钮private final AnimationRun animationRun = new AnimationRun();//实例化线程//设置绘图全局属性private int circleX = 0;//圆形的初始位置X坐标private int circleY = 10;//圆形的初始位置Y坐标private int circleXDirection = 1;//圆形运动X轴方向private int circleYDirection = 1;//圆形运动Y轴方向private int starX = 355;//星型的初始位置X坐标private int starY = 200;//星型的初始位置Y坐标private int starXDirection = 1;//星形运动X轴方向private int starYDirection = 1;//星形运动Y轴方向//构造方法构造窗体public AnimationJFrame(){//窗体基本设置Container conn = getContentPane();//建立窗体容器setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗体关闭方式setBounds(300,300,400,400);//设置窗体位置及大小setResizable(false);//窗体大小不可改变setLayout(null);//清空窗体布局管理器,不采用默认布局//创建动画布局JPanel jPanel = new JPanel();//实例化布局jPanel.setLayout(null);//清空布局的布局管理器,不采用默认布局jPanel.setBounds(10, 10, 365, 300);//动画布局的位置及大小jPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));//设置动画布局的边框jPanel.setBackground(Color.LIGHT_GRAY);//设置动画布局的底色//创建动画图形的标签容器JLabel jLabel = new JLabel();//实例化标签jLabel.setBounds(0,0,365,300);//设置动画标签的大小和位置//设置绘图标签drawCircleAndStar.setBackground(new Color(0,0,0,0));//设置绘图标签的背景透明drawCircleAndStar.setSize(365,300);//设置绘图标签的大小jLabel.add(drawCircleAndStar);//添加绘图板到标签jPanel.add(jLabel);//添加动画标签到动画布局//设置按键jButton.setText("开始");//设置按键显示文字jButton.setFont(new Font("黑体", Font.PLAIN, 14));//设置按键文字的字体jButton.setBounds(275, 320, 100, 22);//设置按键的位置和大小//添加原件到窗体容器conn.add(jPanel);//添加动漫布局到容器conn.add(jButton);//添加按钮到容器//给按钮添加监听jButton.addActionListener(e -> {if (e.getActionCommand().equals("开始")){jButton.setText("暂停一下");//更改按键文字animationRun.start();//启动线程}else if (e.getActionCommand().equals("暂停一下")){jButton.setText("继续");animationRun.pause();//暂停线程}else if (e.getActionCommand().equals("继续")){jButton.setText("暂停一下");animationRun.restart();//重启线程}});}//创建绘图板class DrawCircleAndStar extends JLabel{@Overridepublic void paintComponent(Graphics g){//重写paintComponentsuper.paintComponent(g);//继承父类的构造方法Graphics2D graphics2D = (Graphics2D) g;graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//设置绘图抗锯齿//绘制圆形graphics2D.setColor(Color.RED);//设置填充颜色,红色graphics2D.fillOval(circleX,circleY,15,15);//设置圆形的位置和大小//绘制星型graphics2D.setColor(Color.BLUE);//设置填充色,蓝色//设置星型的属性int radius = 10;//设置星型的大小int[] xPoints = new int[10];//星型顶点的X坐标int[] yPoints = new int[10];//星型顶点的Y坐标//计算星型顶点的坐标及初始角度for (int i = 0; i < 10; i++) {double baseAngle = i * 2 * Math.PI / 10 + Math.PI / 2;//初始角度if (i % 2 == 0) {//外围顶点的坐标xPoints[i] = starX + (int) (radius * Math.cos(baseAngle));yPoints[i] = starY - (int) (radius * Math.sin(baseAngle));} else {//内部顶点的坐标xPoints[i] = starX + (int) (radius * Math.cos(baseAngle) * 0.5);yPoints[i] = starY - (int) (radius * Math.sin(baseAngle) * 0.5);}}Polygon star = new Polygon(xPoints, yPoints, 10);//绘制星型graphics2D.fillPolygon(star);//填充星型}}//创建运行线程class AnimationRun extends Thread{boolean flag = false;//设置挂起标志synchronized void pause(){//暂停方法flag = true;}synchronized void restart(){//重启方法notifyAll();flag = false;}//重写run@Overridepublic void run(){//动画运行while (true) {//挂起区synchronized (this){while (flag){try {wait();//等待挂起} catch (InterruptedException e) {throw new RuntimeException(e);}}}//判断圆形运动方向if (circleX == 0) {circleXDirection = 1;} else if (circleX == 350) {circleXDirection = -1;}if (circleY == 0) {circleYDirection = 1;} else if (circleY == 285) {circleYDirection = -1;}//判断星型运动方向if (starX == 10){starXDirection = 1;}else if (starX == 355){starXDirection = -1;}if (starY == 10){starYDirection = 1;}else if (starY == 290){starYDirection = -1;}//设置绘图延迟try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}//计算新的圆形位置和星型的位置circleX += circleXDirection;circleY += circleYDirection;starX += starXDirection;starY += starYDirection;//重绘绘图板drawCircleAndStar.repaint();}}}public static void main(String[] args) {new AnimationJFrame().setVisible(true);//启动程序}
}

http://www.ppmy.cn/embedded/152965.html

相关文章

OpenCV计算机视觉 06 图像轮廓检测(轮廓的查找、绘制、特征、近似及轮廓的最小外接圆外接矩形)

目录 图像轮廓检测 轮廓的查找 轮廓的绘制 轮廓的特征 面积 周长 根据面积显示特定轮廓 轮廓的近似 给定轮廓的最小外接圆、外接矩形 外接圆 外接矩形 图像轮廓检测 轮廓的查找 API函数 image, contours, hierarchy cv2.findContours(img, mode, method) 代入参…

深度学习张量的秩、轴和形状

深度学习张量的秩、轴和形状 秩、轴和形状是在深度学习中我们最关心的张量属性。 秩轴形状 秩、轴和形状是在深度学习中开始使用张量时我们最关心的三个属性。这些概念相互建立&#xff0c;从秩开始&#xff0c;然后是轴&#xff0c;最后构建到形状&#xff0c;所以请注意这…

儿童玩具加拿大SOR/2011-17测试安全标准

加拿大儿童玩具都有什么标准&#xff1f; SOR/2011-17&#xff08;玩具法规&#xff09;SOR/2016-188&#xff08;邻苯二甲酸盐法规&#xff09;SOR/2016-193&#xff08;表面涂层材料法规&#xff09;SOR/2018-83&#xff08;含铅消费品法规&#xff09; 加拿大的技术法规通常…

深入理解 pytest_runtest_makereport:如何在 pytest 中自定义测试报告

pytest_runtest_makereport 是 pytest 系统中的一个钩子函数&#xff0c;它允许我们在测试执行时获取测试的报告信息。通过这个钩子&#xff0c;我们可以在测试运行时&#xff08;无论是成功、失败还是跳过&#xff09;对测试结果进一步处理&#xff0c;比如记录日志、添加自定…

HTML5 加载动画(Loading Animation)

加载动画&#xff08;Loading Animation&#xff09;详解 概述 加载动画是指在数据加载过程中&#xff0c;向用户展示的一种视觉效果&#xff0c;旨在提升用户体验&#xff0c;告知用户系统正在处理请求。它可以减少用户的等待焦虑感&#xff0c;提高界面的互动性。 常见的加…

集成Log4j2以及异步日志

文章目录 1.环境搭建1.在sunrays-common下创建一个单独的模块2.依赖关系1.继承父模块的版本和通用依赖 3.创建自动配置相关1.目录2.pom.xml3.Log4j2AutoConfiguration.java 自动配置类4.META-INF/spring.factories 指定自动配置类 2.集成Log4j2以及异步日志1.目录2.引入依赖3.l…

Nacos server 2.4.0 版本已知问题和 Bug 汇总

Nacos server 2.4.0 版本已知问题和 Bug 汇总 核心功能问题 集群模式下的数据一致性问题 在特定条件下&#xff0c;可能出现节点间数据同步延迟某些情况下会出现脑裂现象Issue #9876: 数据同步时可能出现死锁 内存泄漏问题 长时间运行后可能出现内存泄漏当配置变更频繁时&…

Dart语言的数据结构

Dart 语言中的数据结构 Dart 是一种现代化的编程语言&#xff0c;广泛用于构建高效、逻辑清晰的移动、Web 和服务器端应用程序。作为一种面向对象的语言&#xff0c;Dart 提供了一系列强大的数据结构&#xff0c;帮助开发者更高效地管理和操作数据。在本文中&#xff0c;我们将…