java画图板之三——用线程让多个小球在界面自动运动

在界面上,除了可以实现点击,鼠标移动等操作的***,还有可以自动运行的线程

线程是指令执行的最小单位,而且多个线程是共用一个进程的内存的,也就是说我们在一个程序中可以开很多个线程,不过线程开多了当然占用的内存就多

现在我们要实现的是,运行主程序,自动跳出界面,自动出现很多小球,他们的大小,位置,运动方向速度,完全是随机的,同时碰到界面边界还要反弹

这样的要求我们的第一反应往往是一个小球开一个线程,可是这种方法在小球数量很多的时候就会越来越卡,所以我们考虑只用两个线程,一个线程创建小球,将创建的小球存在队列中,一个线程让小球动起来,从队列中一个一个的获得小球

除此之外,我们还需要一个球类,包含球的属性和运动的方法,以便线程调用,还有一个窗体类,里面包含主方法

在这四个类中,包含的变量有坐标,半径,速度,画笔,窗体,列表。我们是在球类中定义坐标,半径,速度,并且运动的方法也在球类中,所以只需要球类自己包含坐标,半径,速度即可

画笔,窗体,列表都需要在窗体类中定义,并且画笔和窗体要传到球类,因为要画球的运动轨迹

画笔,窗体,列表要传到创建小球的线程中,因这里要不断的创建小球到list中,每一个小球都要保存属于他的画笔和窗体,也就是说每创一个小球,传一次画笔和窗体,这样每个小球执行的运动方法就是独特的,不受别的小球干扰的。

列表传到让小球运动的线程中,因为要取出每个小球,并循环每个的运动方法,这样小球的坐标就不断在变,就像动起来一样

此外还要注意,不要用线程调用线程,所以两个线程最好在主函数中调用

以下是源代码
窗体类

package com.thread;

import java.awt.FlowLayout;
import java.awt.Graphics;
import java.util.ArrayList;
import javax.swing.JFrame;

public class Framball extends JFrame{
    private static ArrayList <Ball> list = new ArrayList<Ball>();//新建的list一定要初始化
    private Graphics g;
    public void showUI() {

        this.setTitle("小球");
        this.setSize(1000, 600);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        // 设置布局,流式布局
        this.setLayout(new FlowLayout());
        this.setVisible(true);
         g=this.getGraphics();
    }

    public static void main(String[] args) {
        Framball fb=new Framball();
        fb.showUI();//可见才能得到画布

        drawBall db=new drawBall();
        db.setG(fb.g,fb,list);//传三个参数
        db.start();//启动线程,线程启动后,他会自动运行,并且只运行run方法,想要运行其他方法必须另外调用

        //moveBall中的list是来自drawBall中的,所以必须等db执行完才能启动moveBall
        moveBall mb=new moveBall();
        mb.setL(list);
        mb.start();//启动线程

    }

}

小球类

package com.thread;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class Ball {
    Random rand = new Random();
    int x = rand.nextInt(1000);
    int y = rand.nextInt(600);
    int R = rand.nextInt(100);// 半径
    private int speedX = rand.nextInt(20), speedY = rand.nextInt(20);// 小球运动速度
    private int r = 1000, d = 600;// 右限,下限
    private Graphics g;
    private Framball fb;

    public void setG(Graphics g, Framball fb) {
        this.g = g;
        this.fb = fb;
    }

    public void run() {// 表示小球的运动,可反弹,必须放在while循环中才能跑起来
        g.setColor(fb.getContentPane().getBackground());//切换为背景色
        g.fillOval(x - R - speedX, y - R - speedY, R, R);//减掉R表示在坐标替换为圆心,减掉速度表示将上一个小球掩盖掉
        g.setColor(Color.black);
        g.fillOval(x - R, y - R, R, R);
        if (y >= d)//当y接触到下限时
            speedY *= -1;//速度反向
        else if (y <= 0)
            speedY *= -1;
        if (x >= r)
            speedX *= -1;
        else if (x <= 0)
            speedX *= -1;
        x += speedX;//每一次run,就移动一次速度值
        y += speedY;
        //只执行一次run方法,小球是不会动的
    }
}

创建球的线程

package com.thread;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;

public class drawBall extends Thread{
    ArrayList <Ball> list=new ArrayList<Ball>();//注意后面的写法,写错会报空指针异常
    Graphics g;
    Framball fb;

    public void setG(Graphics g,Framball fb,ArrayList <Ball> list) {
        this.g=g;
        this.fb=fb;
        this.list=list;
    }

    public void run() {
        while(true) {
            Ball b=new Ball();//循环中不断新建一个球
            b.setG(g, fb);//每个球都设置自己的g和fb
            list.add(b);//把球放进队列中
            try{
                sleep(10);
            }catch(Exception ef) {}
            System.out.println(list.size());
            if(list.size()==10)break;//设置小球存储的个数
        }
    }
}

移动球的线程

package com.thread;
import java.util.ArrayList;

public class moveBall extends Thread{
    int i=0;
    private ArrayList<Ball> list;//=new ArrayList<Ball>();
    public void setL( ArrayList <Ball> list) {
        this.list=list;
    }
    public void run() {
        try {
            sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while(true) {
            for(i=0;i<list.size();i++) {
                list.get(i).run();
                try{sleep(100);}
                catch(Exception ef) {};
            }
        }
    }
}

全部评论

相关推荐

01-28 16:12
中南大学 Java
几年前还没有chatgpt的时候,刷题真的是很痛苦。刷不出来只能看题解,题解有几个问题:第一个是每次看的写题解的人都不一样,很难有一个统一的思路;第二个也是最重要的是,题解只提供了作者自己的思路,但是没有办法告诉你你的思路哪里错了。其实很少有错误的思路,我只是需要被引导到正确的思路上面去。所以传统题解学习起来非常困难,每次做不出来难受,找题解更难受。但是现在chatgpt能做很多!它可以这样帮助你&nbsp;-1.&nbsp;可以直接按照你喜欢的语言生成各种解法的题解和分析复杂度。2.&nbsp;把题和你写的代码都发给它,它可以告诉你&nbsp;你的思路到底哪里有问题。有时候我发现我和题解非常接近,只是有一点点🤏想错了。只要改这一点点就是最优解。信心倍增。3.&nbsp;如果遇到不懂的题解可以一行一行询问为什么要这样写,chatgpt不会嫌你烦。有时候我觉得自己的range写错了,其实那样写也没错,只是chat老师的题解有一点优化,这个它都会讲清楚。4.&nbsp;它可以帮你找可以用同类型解法来做的题。然后它可以保持解法思路不变,用一个思路爽刷一个类型的题。如果题目之间思路又有变化,它会告诉你只有哪里变了,其他的地方还是老思路。5.&nbsp;它也可以直接帮你总结模板,易错点。经过chat老师的指导,我最大的改变是敢刷题了。之前刷题需要先找某一个人写的算法题repo,然后跟着某一个人他的思路刷他给的几个题。如果想写别的题,套用思路失败了,没有他的题解,也不知道到底哪里错了;看别人的题解,思路又乱了。这个问题在二分查找和dp类型的题里面特别常见。但是现在有chat老师,他会针对我的代码告诉我我哪里想错了,应该怎么做;还按照我写代码的习惯帮我总结了一套属于我的刷题模板。每天写题全是正反馈!
牛客981:不刷才是爽
AI时代的工作 VS 传...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务