JAVA——多執行緒(碰撞的球)
阿新 • • 發佈:2019-01-07
多執行緒(碰撞的球)
1.要求
本例項運用多執行緒控制球的運動,通過視窗中的滑條,對球的大小和顏色進行選擇後,隨機從視窗左右兩方擇一進入,小球在遇到障礙或邊界後會折回。
2.原理
- 多執行緒是為了使得多個執行緒並行地工作以完成多項任務,以提高系統的效率。執行緒是在同一時間需要完成多項任務的時候被實現的。
- 碰撞的小球運用多執行緒實現,球的運動速度隨著時間的變動可能加快,這也是體現多執行緒的好處之一。從左右兩側出現的球是運用兩個執行緒分別控制的。當碰到面板的邊緣時則折回。
3.語法
- BallFrame類繼承JFramea類實現ActionListener與ChangeListeneri介面。實現ActionListener介面必須實現actionPerformed()方法,實現 ChangeListenert介面必須實現state Changed()方法。在BallFrame類的構造方法中建立面板並設定面板的大小、位置、背景顏色;建立預覽面板並設定預覽面板的大小、位置與背景顏色:建立文字框作為狀態列並設定其大小、位置,初始不可編輯;建立紅綠藍和球大小的四個標籤,並設定標籤的位置,建立紅綠藍以及球大小四個滑塊並設定滑塊的大小、位置、填充滑塊、繪製勾號標記、設定主要的勾號標記大小、設定次要的勾號標記大小、設定主要刻度的數字標記以及新增監聽器。建立注入球按鈕,當單擊該按鈕時觸發事件在面板中匯入兩個運動的球。建立窗體容器並設定其佈局為空,這樣可以在窗體容器中隨意擺放元件,再將相關的元件訴加到窗體容器中,設定窗體容器的位置大小以及視覺化,當關閉窗體時呼叫系統的exit(0)方法安全退出程式。
- BallFrame類的actionPerformed()方法根據紅綠藍滑塊中指定的顏色獲取當前球的顏色。根據面板、球的大小以及球的顏色建立 RightBall和LeftBall物件,並啟動執行緒。這樣球就可以注入到面板中運動了。
- BallFrame類的stateChanged()方法獲得預覽面板中的畫筆,在預覽面板的中心畫一個圓,並設定該圖形的顏色為白色和填充外接指定矩形框的圓。根據設定球大小的滑塊值設定圓的半徑。重新設定圖形的顏色和填充外接指定矩形框的圓, Graphics類的dispose()方法將所畫的圓顯示出來。
- LeftBall類和 RightBall類繼承 Thread類擴充套件run()方法,其構造方法獲得球的面板、大小以及顏色。run()方法根據面板的 getGraphics()方法獲得球的圖形,並根據獲得的球的大小計算畫球時橫縱座標的最大座標。運用條件始終為真進行迴圈,球毎移動一步,將上一步畫的球的顏色設定為白色來將球擦掉,並獲得新的球的橫縱座標。如果球運動到面板的邊緣則球轉向。設定左球與右球毎隔30毫秒移動一次。
4.程式碼
主程式:
public class rw34 {
//操作運用執行緒實現碰撞的球的類
public static void main(String[] args) {
// TODO Auto-generated method stub
new BallFrame();//例項化物件
}
}
對視窗介面進行設計:
class BallFrame extends JFrame implements ActionListener,ChangeListener{
private static final long serialVersionUID=1L;
JPanel panel; //畫板
JPanel preview;//預覽畫板
JSlider red;//紅色滑塊
JSlider blue;//藍色滑塊
JSlider green;//綠色滑塊
JSlider JS_SIZE;//滑塊的大小
int x=45,y=45;//方位
int BALL_SIZE=30;//球的大小
public BallFrame() {
//構造方法進行初始化
super("碰撞的球");
panel=new JPanel();//建立面板
panel.setBounds(20, 0, 450, 200);//設定面板的位置及大小
panel.setBackground(Color.WHITE);//面板背景色為白色
preview=new JPanel(); //建立預覽球的面板
preview.setBounds(350,220,120,120);
preview.setBackground(Color.WHITE);//設定狀態列
JTextField status=new JTextField("請選擇球的顏色、大小然後單擊按鈕");
status.setBounds(1,404,492,20);//設定狀態列的位置以及大小
status.setEditable(false);//初始不能編輯
JLabel redLabel=new JLabel("紅");//建立紅色標籤
redLabel.setBounds(20,215,30,20);//設定紅色標籤的位置以及大小
JLabel greenLabel=new JLabel("綠");//建立綠色標籤
greenLabel.setBounds(20,260,30,20);//設定綠色標籤的位置以及大小
JLabel blueLabel=new JLabel("藍");//建立藍色標籤
blueLabel.setBounds(20,305,30,20);//設定藍色標籤的位置以及大小
JLabel sizeLabel=new JLabel("大小");//建立大小標籤
sizeLabel.setBounds(20,350,30,20);//設定大小標籤的位置以及大小
red=new JSlider(SwingConstants.HORIZONTAL,0,255,127);//建立紅色滑塊
red.setBounds(50, 210, 250, 45);//設定滑塊的位置以及大小
red.putClientProperty("JSlider.isFilled",Boolean.TRUE);//填充滑塊
red.setPaintTicks(true);//繪製勾號標記
red.setMajorTickSpacing(50);//主要的勾號標記大小
red.setMinorTickSpacing(25);//次要的勾號標記大小
red.setPaintLabels(true);//顯示主要刻度的數字標記
red.addChangeListener(this);//新增監聽者
blue=new JSlider(SwingConstants.HORIZONTAL,0,255,127);//建立藍色滑塊
blue.setBounds(50, 300, 250, 45);//設定滑塊的位置以及大小
blue.putClientProperty("JSlider.isFilled",Boolean.TRUE);//填充滑塊
blue.setPaintTicks(true);//繪製勾號標記
blue.setMajorTickSpacing(50);//主要的勾號標記大小
blue.setMinorTickSpacing(25);//次要的勾號標記大小
blue.setPaintLabels(true);//顯示主要刻度的數字標記
blue.addChangeListener(this);//新增監聽者
green=new JSlider(SwingConstants.HORIZONTAL,0,255,127);//建立綠色滑塊
green.setBounds(50, 255, 250, 45);//設定滑塊的位置以及大小
green.putClientProperty("JSlider.isFilled",Boolean.TRUE);//填充滑塊
green.setPaintTicks(true);//繪製勾號標記
green.setMajorTickSpacing(50);//主要的勾號標記大小
green.setMinorTickSpacing(25);//次要的勾號標記大小
green.setPaintLabels(true);//顯示主要刻度的數字標記
green.addChangeListener(this);//新增監聽者
//建立球大小的滑塊
JS_SIZE=new JSlider(SwingConstants.HORIZONTAL,10,50,30);//建立大小滑塊
JS_SIZE.setBounds(50,345,250,45);//設定滑塊的位置以及大小
JS_SIZE.putClientProperty("JSlider.isFilled", Boolean.TRUE);//填充滑塊
JS_SIZE.setPaintTicks(true);//繪製勾號標記
JS_SIZE.setMajorTickSpacing(50);//主要的勾號標記大小
JS_SIZE.setMinorTickSpacing(25);//次要的勾號標記大小
JS_SIZE.setPaintLabels(true);//顯示主要刻度的數字標記
JS_SIZE.addChangeListener(this);//新增監聽者
JButton jb=new JButton("注入球");//建立球按鈕單擊
jb.setBounds(350,360,120,30);//設定按鈕的位置以及大小
jb.addActionListener(this);
Container c=this.getContentPane();//將所有物件新增到窗體
c.setLayout(null); //佈局置空(不使用佈局)
c.add(panel);
c.add(preview);
c.add(redLabel);
c.add(blueLabel);
c.add(greenLabel);
c.add(sizeLabel);
c.add(red);
c.add(green);
c.add(blue);
c.add(JS_SIZE);
c.add(jb);
c.add(status);
this.setBounds(100,50,500,450);//設定窗體的位置和大小
this.setResizable(false);
this.setVisible(true);//可視
this.addWindowListener(new WindowAdapter(){//對視窗新增監聽事件
public void windowClosing(WindowEvent e) {//當視窗關閉時
System.exit(0);//安全退出
}
});
}
public void actionPerformed(ActionEvent e) {//實現ActionListener介面的方法
Color ball_color=new Color(red.getValue(),green.getValue(),blue.getValue());//獲取當前球的顏色
Random random=new Random();
int z = random.nextInt(2);//產生一個隨機數,使球隨機從兩邊進入,隨機數取值範圍為1,0
if(z==1) {
RightBall r=new RightBall(panel,JS_SIZE.getValue(),ball_color);//例項化右邊的球物件
r.start();//啟動執行緒
}else {
LeftBall ball=new LeftBall(panel,JS_SIZE.getValue(),ball_color);//例項化左邊的球物件
ball.start();//啟動執行緒
}
}
public void stateChanged(ChangeEvent e) {//實現ChangeListener介面的方法
Graphics g=preview.getGraphics();//獲得preview畫筆並在預覽面板中心畫個圈
g.setColor(Color.WHITE);//圖形為白色
g.fillOval(x, y, BALL_SIZE, BALL_SIZE);//填充外接指定矩形框的圓
x=60-JS_SIZE.getValue()/2;
y=60-JS_SIZE.getValue()/2;
BALL_SIZE=JS_SIZE.getValue();
g.setColor(new Color(red.getValue(),green.getValue(),blue.getValue()));
g.fillOval(x, y, BALL_SIZE, BALL_SIZE);//填充外接指定矩形框的圓
g.dispose();//顯示
}
}
繼承Thread類實現從視窗左面出現的球,視窗右邊的球與此原理相同:
class LeftBall extends Thread{//繼承Thread類實現從視窗左面出現的球
JPanel LEFTPANEL;//從視窗左面出現的球的面板
int BALL_SIZE;//球的大小
Color BALL_COLOR;//球的顏色
public LeftBall(JPanel panel,int size,Color color) {//構造方法進行初始化
this.LEFTPANEL=panel;//獲得畫板的控制代碼
this.BALL_SIZE=size;//獲得球的大小
this.BALL_COLOR=color;//獲得球的顏色
}
public void run() { //繼承Thread類實現的方法
Graphics g= LEFTPANEL.getGraphics();//獲得圖形
int x=0,y=0;
int LEFT_X=450-BALL_SIZE;//計算畫球時X軸的最大座標
int LEFT_Y=200-BALL_SIZE;//計算畫球時Y軸的最大座標
int x_increase=5,y_increase=5;//球移動的增量
while(true) {
//迴圈移動球
g.setColor(Color.WHITE);//將上一次畫的球擦掉
g.fillOval(x,y,BALL_SIZE, BALL_SIZE);//填充外接指定矩形框的圓
g.setColor(BALL_COLOR);//設定球的顏色
x=x+x_increase;//球每次X軸的位置
y=y+y_increase;//球每次Y軸的位置
g.fillOval(x,y,BALL_SIZE, BALL_SIZE);//填充外接指定矩形框的圓
if(x<=0||x>=LEFT_X)//判斷球是否到達了便捷,若到達了邊界則轉向
x_increase=-x_increase;
if(y<=0||y>=LEFT_Y)//判斷球是否到達了便捷,若到達了邊界則轉向
y_increase=-y_increase;
try {
Thread.sleep(30);//休眠一段時間
}catch(Exception e) {
//捕獲異常
}
}
}
}
獲取完整程式碼可點選此處。
5.結果
執行結果如下圖所示:
視窗介面如下圖所示: