java畫圖板之三——用執行緒讓多個小球在介面自動運動
阿新 • • 發佈:2019-01-23
在介面上,除了可以實現點選,滑鼠移動等操作的監聽器,還有可以自動執行的執行緒
執行緒是指令執行的最小單位,而且多個執行緒是共用一個程序的記憶體的,也就是說我們在一個程式中可以開很多個執行緒,不過執行緒開多了當然佔用的記憶體就多
現在我們要實現的是,執行主程式,自動跳出介面,自動出現很多小球,他們的大小,位置,運動方向速度,完全是隨機的,同時碰到介面邊界還要反彈
這樣的要求我們的第一反應往往是一個小球開一個執行緒,可是這種方法在小球數量很多的時候就會越來越卡,所以我們考慮只用兩個執行緒,一個執行緒建立小球,將建立的小球存在佇列中,一個執行緒讓小球動起來,從佇列中一個一個的獲得小球
除此之外,我們還需要一個球類,包含球的屬性和運動的方法,以便執行緒呼叫,還有一個窗體類,裡面包含主方法
在這四個類中,包含的變數有座標,半徑,速度,畫筆,窗體,列表。我們是在球類中定義座標,半徑,速度,並且運動的方法也在球類中,所以只需要球類自己包含座標,半徑,速度即可
畫筆,窗體,列表都需要在窗體類中定義,並且畫筆和窗體要傳到球類,因為要畫球的運動軌跡
畫筆,窗體,列表要傳到建立小球的執行緒中,因這裡要不斷的建立小球到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) {};
}
}
}
}