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是线程不安全的,应该对窗体单独建立窗体方法容器,例如:

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

创建绘图板

    //创建绘图板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);//填充星型}}

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

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

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

创建线程

    //创建运行线程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

运行结果

在这里插入图片描述

完整代码

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.mzph.cn/news/892399.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

监控观测数据标签体系的应用实践

前言 在复杂的应用系统环境下&#xff0c;监控数据量呈现出海量且繁杂的特点&#xff0c;如何高效地对这些监控数据进行管理、分析以及从中挖掘出有价值的信息&#xff0c;成为保障系统稳定运行和优化性能的关键所在。数据标签体系的建立就变得十分重要&#xff0c;它能够为监…

Vue中el-tree结合vuedraggable实现跨组件元素拖拽

实现效果&#xff1a; 左侧el-tree: <template><el-treeclass"filter-tree":data"treeData":props"defaultProps":filter-node-method"filterNode"node-key"id"draggable:allow-drop"allowDrop"node-dr…

PHP民宿酒店预订系统小程序源码

&#x1f3e1;民宿酒店预订系统 基于ThinkPHPuniappuView框架精心构建的多门店民宿酒店预订管理系统&#xff0c;能够迅速为您搭建起专属的、功能全面且操作便捷的民宿酒店预订小程序。 该系统不仅涵盖了预订、退房、WIFI连接、用户反馈、周边信息展示等核心功能&#xff0c;更…

点击底部的 tabBar 属于 wx.switchTab 跳转方式,目标页面的 onLoad 不会触发(除非是第一次加载)

文章目录 1. tabBar 的跳转方式2. tabBar 跳转的特点3. 你的配置分析4. 生命周期触发情况5. 总结 很多人不明白什么是第一次加载&#xff0c;两种情况讨论&#xff0c;第一种情况假设我是开发者&#xff0c;第一次加载就是指点击微信开发者工具上边的编译按钮&#xff0c;每点击…

三维卷积( 3D CNN)

三维卷积&#xff08; 3D CNN&#xff09; 1.什么是三维卷积 1.1 三维卷积简介 二维卷积是在单通道的一帧图像上进行滑窗操作&#xff0c;输入是高度H宽度W的二维矩阵。 三维卷积输入多了深度C这个维度&#xff0c;输入是高度H宽度W深度C的三维矩阵。在卷积神经网络中&…

电脑硬盘系统迁移及问题处理

一、系统迁移准备 1、确认你的电脑主板是否支持安装两块硬盘,如电脑主板有多个M2硬盘接口,我们将新硬盘安装到主板上,原来的老硬盘安装在第二个接口上,主板只有一个M2接口的话可以使用移动硬盘盒。 2、新硬盘安装好后,我们进入原来的系统,在 此电脑–右键–管理–磁盘管…

游戏语音的历史是什么样的?

游戏中&#xff0c;离不开游戏社交。 无社交&#xff0c;不游戏&#xff0c;大家都深知社交在游戏体验中的重要性。 游戏语音的发展史是怎么样的&#xff1f;问了下AI&#xff0c;给我的回答是 早期阶段 1970年代&#xff1a;1970年代出现了第一个语音游戏“尤瓦尔的冒险”&am…

GDPU Android移动应用 重点习题集

目录 程序填空 ppt摘选 题目摘选 “就这两页ppt&#xff0c;你还背不了吗” “。。。” 打开ppt后 “Sorry咯&#xff0c;还真背不了&#x1f61c;” 更新日志 考后的更新日志 没想到重点勾了一堆&#xff0c;还愣是没考到其中的内容&#xff0c;翻了一下&#xff0c;原…

排序:插入、选择、交换、归并排序

排序 &#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性 &#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&#xff0c;…

计算机网络 (34)可靠传输的工作原理

前言 计算机网络可靠传输的工作原理主要依赖于一系列协议和机制&#xff0c;以确保数据在传输过程中能够准确无误地到达目的地。 一、基本概念 可靠传输指的是数据链路层的发送端发送什么&#xff0c;在接收端就收到什么&#xff0c;即保证数据的完整性、正确性和顺序性。由于网…

C++:string

一、string概念 之前介绍过通过字符数组保存字符串&#xff0c;然后对字符数组中的字符串做各种操作&#xff1b;为了更加简单方便&#xff0c;在C中&#xff0c;又增加了 string 来处理字符串。 char str[20] "hello world"; string 字符串其实是一种更加高级的封…

SQL Server 数据库给第三方用户开权限,限制可见内容

单独数据库权限的设置&#xff1a; 方法&#xff1a; 给外方公司开用户&#xff0c;让其访问本地有限资源。 分两步&#xff0c;1新建服务器登录名&#xff0c;2设置数据库用户权限 1&#xff0c;首先用管理员sa登录数据库&#xff0c;在服务器级别下“安全性\登录名”&#…

Opus Clip AI技术浅析(二):上传与预处理

1. 视频上传 1.1 用户接口 用户通过网页或移动应用上传视频文件。文件上传通常使用HTTP协议&#xff0c;支持多种视频格式&#xff08;如MP4, AVI, MOV等&#xff09;。上传接口需要处理大文件上传、断点续传等问题。 1.2 文件传输 上传的视频文件通过安全的传输协议&#…

二叉树层序遍历 Leetcode102.二叉树的层序遍历

二叉树的层序遍历相当于图论的广度优先搜索&#xff0c;用队列来实现 &#xff08;二叉树的递归遍历相当于图论的深度优先搜索&#xff09; 102.二叉树的层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右…

Linux第一课:c语言 学习记录day06

四、数组 冒泡排序 两两比较&#xff0c;第 j 个和 j1 个比较 int a[5] {5, 4, 3, 2, 1}; 第一轮&#xff1a;i 0 n&#xff1a;n个数&#xff0c;比较 n-1-i 次 4 5 3 2 1 // 第一次比较 j 0 4 3 5 2 1 // 第二次比较 j 1 4 3 2 5 1 // 第三次比较 j 2 4 3 2 1 5 // …

保护性暂停原理

什么是保护性暂停&#xff1f; 保护性暂停&#xff08;Guarded Suspension&#xff09;是一种常见的线程同步设计模式&#xff0c;常用于解决 生产者-消费者问题 或其他需要等待条件满足后再继续执行的场景。通过这种模式&#xff0c;一个线程在执行过程中会检查某个条件是否满…

嵌入式C语言:二维数组

目录 一、二维数组的定义 二、内存布局 2.1. 内存布局特点 2.2. 内存布局示例 2.2.1. 数组元素地址 2.2.2. 内存布局图&#xff08;简化表示&#xff09; 2.3. 初始化对内存布局的影响 三、访问二维数组元素 3.1. 常规下标访问方式 3.2. 通过指针访问 3.2.1. 指向数…

【ArcGIS微课1000例】0137:色彩映射表转为RGB全彩模式

本文讲述ArcGIS中,将tif格式的影像数据从色彩映射表转为RGB全彩模式。 参考阅读:【GlobalMapper精品教程】093:将tif影像色彩映射表(调色板)转为RGB全彩模式 文章目录 一、色彩映射表预览二、色彩映射表转为RGB全彩模式一、色彩映射表预览 加载配套数据包中的0137.rar中的…

Java 将RTF文档转换为Word、PDF、HTML、图片

RTF文档因其跨平台兼容性而广泛使用&#xff0c;但有时在不同的应用场景可能需要特定的文档格式。例如&#xff0c;Word文档适合编辑和协作&#xff0c;PDF文档适合打印和分发&#xff0c;HTML文档适合在线展示&#xff0c;图片格式则适合社交媒体分享。因此我们可能会需要将RT…

基于 GEE 下载逐年 MODIS 地表温度 LST 数据

目录 1 地表温度&#xff08;LST&#xff09; 2 数据准备 3 代码实现 3.1 加载研究区与数据集 3.2 数据预处理与标准化 3.3 逐年批量导出 3.4 可视化结果 4 运行结果 5 完整代码 1 地表温度&#xff08;LST&#xff09; 在遥感领域&#xff0c;地表温度&#xff08;L…