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{
        @Override
        public void paintComponent(Graphics g){//重写paintComponent
            super.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
        @Override
        public 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{
        @Override
        public void paintComponent(Graphics g){//重写paintComponent
            super.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
        @Override
        public 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);//启动程序
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/951959.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于YOLOv8的车辆跟踪、车速计算和车辆统计应用

1、环境搭建 通过conda创建一个python≥3.8环境&#xff0c;激活环境后安装ultralytics8.2、python-opencv、shapely>2.0.0: conda create -n yolov8 python3.10 conda activate yolov8 pip install ultralytics8.2 pip install python-opencv pip install shapely>2.0…

如何提升scrapy的效率

如何提升scrapy的效率 在settings配置文件中修改CONCURRENT_REQUESTS 100 scrapy默认开启的线程数量为32个&#xff0c;这样设置可以使其线程数量为100个在运行scrapy时,会有大量的日志信息输出&#xff0c;为了减少cpu的使用率&#xff0c;可以设置log输出信息为WORNING或者…

网络安全 | 网络安全法规:GDPR、CCPA与中国网络安全法

网络安全 | 网络安全法规&#xff1a;GDPR、CCPA与中国网络安全法 一、前言二、欧盟《通用数据保护条例》&#xff08;GDPR&#xff09;2.1 背景2.2 主要内容2.3 特点2.4 实施效果与影响 三、美国《加利福尼亚州消费者隐私法案》&#xff08;CCPA&#xff09;3.1 背景3.2 主要内…

HarmonyOS(ArkUI框架介绍)

ArkUI框架介绍 ArkUI简介 基本概念 UI&#xff1a; 即用户界面。开发者可以将应用的用户界面设计为多个功能页面&#xff0c;每个页面进行单独的文件管理&#xff0c;并通过页面路由API完成页面间的调度管理如跳转、回退等操作&#xff0c;以实现应用内的功能解耦。 组件&…

EasyExcel(二)导出Excel表自动换行和样式设置

EasyExcel(一)导出Excel表列宽自适应 背景 在上一篇文章中解决导出列宽自适应,然后也解决了导出列宽不可超过255的问题。但是实际应用场景中仍然会有导出数据的长度超过列宽255。这时导出效果就会出现如下现象: 多出列宽宽度的内容会浮出来,影响后边列数据的显示。 解决…

记录一下vue2项目优化,虚拟列表vue-virtual-scroll-list处理10万条数据

文章目录 封装BrandPickerVirtual.vue组件页面使用组件属性 select下拉接口一次性返回10万条数据&#xff0c;页面卡死&#xff0c;如何优化&#xff1f;&#xff1f;这里使用 分页 虚拟列表&#xff08;vue-virtual-scroll-list&#xff09;&#xff0c;去模拟一个下拉的内容…

迅为RK3568开发板篇OpenHarmony配置HDF驱动控制LED-配置创建私有配置文件

接 下 来 新 建 vendor/hihope/rk3568/hdf_config/khdf/topeet/topeet_config.hcs 文 件 &#xff0c;topeet_config.hcs 为驱动私有配置文件&#xff0c;用来填写一些驱动的默认配置信息。HDF 框架在加载驱动时&#xff0c;会获取相应的配置信息并将其保存在 HdfDeviceObject …

nginx负载均衡-基于端口的负载均衡(一)

注意&#xff1a; (1) 做负载均衡技术至少需要三台服务器&#xff1a;一台独立的负载均衡器&#xff0c;两台web服务器做集群 一、nginx分别代理后端web1 和 web2的三台虚拟主机 1、web1&#xff08;nginx-10.0.0.7&#xff09;配置基于端口的虚拟主机 [rootOldboy extra]# …

金融项目实战 02|接口测试分析、设计以及实现

目录 ⼀、接口相关理论 二、接口测试 1、待测接口&#xff1a;投资业务 2、接口测试流程 3、设计用例理论 1️⃣设计方法 2️⃣工具 4、测试点提取 5、测试用例&#xff08;只涉及了必测的&#xff09; 1️⃣注册图⽚验证码、注册短信验证码 2️⃣注册 3️⃣登录 …

vue3使用vue3-video-play播放m3u8视频

1.安装vue3-video-play npm install vue3-video-play --save2.在组件中使用 import vue3-video-play/dist/style.css; import VideoPlay from vue3-video-play;// 视频配置项 const options reactive({src: https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8, //视频源mute…

Redis:数据类型

1. 字符串&#xff08;String&#xff09; 简介 概念&#xff1a;这是最简单的数据类型&#xff0c;可以存储字符串、整数或浮点数。特点&#xff1a;支持原子操作&#xff0c;如递增和递减数值。 示例 # 设置一个键值对 SET mykey "Hello, Redis!"# 获取该键的值…

【Web安全】SQL 注入攻击技巧详解:UNION 注入(UNION SQL Injection)

【Web安全】SQL 注入攻击技巧详解&#xff1a;UNION 注入&#xff08;UNION SQL Injection&#xff09; 引言 UNION注入是一种利用SQL的UNION操作符进行注入攻击的技术。攻击者通过合并两个或多个SELECT语句的结果集&#xff0c;可以获取数据库中未授权的数据。这种注入技术要…

移远BC28_opencpu方案_pin脚分配

先上图&#xff0c;BC28模块的pin脚如图所示&#xff1a; 下面看看GPIO的复用管脚 然后我自己整理了一份完整的pin功能列表

PHP多功能投票小程序源码

多功能投票小程序&#xff1a;全方位打造专属投票盛宴的得力助手 &#x1f389; &#x1f527; 基于先进的ThinkPHP框架与Uniapp技术深度融合&#xff0c;我们匠心独运&#xff0c;精心雕琢出一款功能全面、操作便捷的投票小程序&#xff0c;旨在为您带来前所未有的投票体验。…

ORB-SALM3配置流程及问题记录

目录 前言 一、OPB-SLAM3基本配置流程 1.下载编译Pangolin 二、ORB-SLAM3配置 1.下载源码 2.创建ROS工作空间并编译ORB-SLAM3-ROS源码 3.尝试编译 三、运行测试 一、OPB-SLAM3基本配置流程 ORB-SLAM3是一个支持视觉、视觉加惯导、混合地图的SLAM&#xff08;Simultane…

RabbitMQ介绍与使用

RabbitMQ官网 RabbitMQ 介绍 RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;基于 AMQP&#xff08;高级消息队列协议&#xff09;标准&#xff0c;使用 Erlang 编程语言构建。它是消息队列&#xff08;MQ&#xff09;的一种&#xff0c;广泛应用于分布式系统中&#x…

自然语言处理之jieba分词和TF-IDF分析

jieba分词和TF-IDF分析 目录 jieba分词和TF-IDF分析1 jieba1.1 简介1.2 终端下载1.3 基本语法 2 TF-IDF分析2.1 什么是语料库2.2 TF2.3 IDF2.4 TF-IDF2.5 函数导入2.6 方法 3 实际测试3.1 问题解析3.2 代码测试 1 jieba 1.1 简介 结巴分词&#xff08;Jieba&#xff09;是一个…

rust学习——环境搭建

rust安装&#xff1a;https://kaisery.github.io/trpl-zh-cn/ch01-01-installation.html 1、vscode装插件&#xff1a; toml语法支持 依赖管理 rust语法支持 2、创建demo 3、查看目录 4、执行文件的几种方式&#xff1a; rust安装&#xff1a;https://www.rust-lang.org/z…

Opencv查找、绘制轮廓、圆形矩形轮廓和近似轮廓

查找、绘制轮廓、圆形矩形轮廓和近似轮廓 目录 查找、绘制轮廓、圆形矩形轮廓和近似轮廓1 轮廓查找和绘制1.1 轮廓查找1.1.1 函数和参数1.1.2 返回值 1.2 轮廓绘制1.2.1 函数和参数 1.3 步骤1.4 实际测试绘制轮廓 2 绘制近似轮廓2.1 函数和参数2.2 查找特定轮廓2.3 近似轮廓测试…

K8s Pod OOMKilled,监控却显示内存资源并未打满

1. 问题现象 pod一直重启&#xff0c;通过grafana查看&#xff0c;发现内存使用率并没有100%。 2. 排查过程 2.1 describe查看pod最新一次的状态 可以明显看到&#xff0c;最近一次的重启就是因为内存不足导致的。 2.2 describe 查看node节点状态 找到原因了&#xff0c;原来…