在界面上,除了可以实现点击,鼠标移动等操作的***,还有可以自动运行的线程
线程是指令执行的最小单位,而且多个线程是共用一个进程的内存的,也就是说我们在一个程序中可以开很多个线程,不过线程开多了当然占用的内存就多
现在我们要实现的是,运行主程序,自动跳出界面,自动出现很多小球,他们的大小,位置,运动方向速度,完全是随机的,同时碰到界面边界还要反弹
这样的要求我们的第一反应往往是一个小球开一个线程,可是这种方法在小球数量很多的时候就会越来越卡,所以我们考虑只用两个线程,一个线程创建小球,将创建的小球存在队列中,一个线程让小球动起来,从队列中一个一个的获得小球
除此之外,我们还需要一个球类,包含球的属性和运动的方法,以便线程调用,还有一个窗体类,里面包含主方法
在这四个类中,包含的变量有坐标,半径,速度,画笔,窗体,列表。我们是在球类中定义坐标,半径,速度,并且运动的方法也在球类中,所以只需要球类自己包含坐标,半径,速度即可
画笔,窗体,列表都需要在窗体类中定义,并且画笔和窗体要传到球类,因为要画球的运动轨迹
画笔,窗体,列表要传到创建小球的线程中,因这里要不断的创建小球到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) {};
}
}
}
}