~這些年,我們一起學過的java~09~線程之Thread的控制

        今天下午學到內容比較的多,還好自己中午睡了一覺,下午還算精神,在聽課的時候記錄下來了強哥說的一些比較重要的地方,當然,今天的主要內容是如何控制線程中的對象的開始動作和暫停動作以及停止,但是因爲基礎比較薄弱,強哥在講解的過程中補充了其他的基礎內容,當然,等下我會另起一篇博客做個小小的整理。

        還是先把今天的重點內容梳理一遍,雖然自己在做這個的過程中bug不斷,還好自己現在慢慢也學會處理一些常見的bug,也會翻翻源代碼,儘管大多數的時候還是看得不太明朗。雖然自己對界面的要求還是有的,但是,因爲如果把重心更多的放在界面上,我擔心4點左右上完課後,開始自己敲代碼,然後再寫博客的時間會不夠,所以對界面就沒有怎麼花時間,重心是在功能的實現方面,因爲現在還在積累知識,也還木有想好要做哪個項目,所以,界面太醜,見諒見諒……

 

 

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class BallControlled {
	JFrame jf;//這裏的JFrame可以定義爲全局變量,也可以放在init方法裏面
	JPanel jp2;//這裏是必須要定義爲全局變量,因爲後面不只一個方法裏面有調用,甚至在另外一個類裏面也要調用,期間要進行傳值,所以最好定義爲全局變量

	ArrayList<Myball> array=new ArrayList<Myball>();//這裏也是要用到數組隊列來保存每個球的相關數據,方便控制
	public static void main(String[] args) {

		BallControlled bc=new BallControlled();
		bc.init();//這個就是很基礎的實例化對象,並調用方法
	}
	public void init(){
		jf=new JFrame();
		jf.setBounds(400, 20, 800, 600);
		jf.setDefaultCloseOperation(3);
		jf.setLayout(null);//這裏很明顯就是做一個窗體,設置了空佈局,這個是懶人的做法……聰明人勿學……
		
		JPanel jp1=new JPanel();
		jp1.setBounds(0, 0, 800, 100);
		jp1.setLayout(null);//我把整個窗體分爲了兩個部分,分別放上兩個JPanel,這是爲了防止小球運動的時候把按鈕覆蓋了
		
		JButton jb1=new JButton("start");
		JButton jb2=new JButton("pause");
		JButton jb3=new JButton("resume");
		JButton jb4=new JButton("stop");
		
		jb1.setBounds(100, 20, 100, 50);
		jb2.setBounds(250, 20, 100, 50);
		jb3.setBounds(400, 20, 100, 50);
		jb4.setBounds(550, 20, 100, 50);
		jp1.add(jb1);
		jp1.add(jb2);
		jp1.add(jb3);
		jp1.add(jb4);//這幾行代碼很容易看懂,就是在面板1上添加四個按鈕
		
		jp2=new JPanel();
		jp2.setBounds(0, 100, 800, 485);
		jp2.setBackground(new Color(255,255,255));
		jf.add(jp1);
		jf.add(jp2);
		jb1.addActionListener(l);
		jb2.addActionListener(l);
		jb3.addActionListener(l);
		jb4.addActionListener(l);//這裏就是在四個按鈕上面添加監聽器
		jf.setVisible(true);//當然,這裏就是讓窗體可見,不然寫了這麼多也顯示不出來
		
	}
	
	//匿名內部類
	ActionListener l=new ActionListener(){

		@Override
		public void actionPerformed(ActionEvent e) {
			String str=e.getActionCommand();
			if("start".equals(str)){//不知道大家有沒有發現這行代碼和以前的風格不太一樣,今天下午聽了強哥的解釋,豁然開朗,稍後會在另外一篇博客中提到
				Myball ball=new Myball(jp2);//點擊一次鼠標,就創建一個Myball類的對象,把面板2傳過去
				ball.start();//這個是Thread類的對象啓動線程的方法,該方法會自動執行run的方法
				array.add(ball);//當然這裏是將新創建的對象保存進數組隊列,因爲線程只能被調用一次,不能重複,調用完就消失了,不在創建的時候就保持進來,供之後的獲取調用,就容易流失……
				
			}
			if("pause".equals(str)){//因爲我們不知道用戶點擊了多少次,創建了多少個線程,所以,我們遍歷一遍。這裏主要是修改pauseflag的布爾值來控制線程,等到寫Thread那個類的對象時會解釋
				for(int i=0;i<array.size();i++){
					Myball ball=array.get(i);
					ball.setPauseflag(true);
				}
				
			}
			if("resume".equals(str)){//這裏和上面那個if要跳到後面看run方法,注意改的是pauseflag的布爾值而不是什麼resmueflag的值
				for(int i=0;i<array.size();i++){
					Myball ball=array.get(i);
					ball.setPauseflag(false);
				}
			}
			if("stop".equals(str)){//這裏也一樣,調到後面看run方法……
				for(int i=0;i<array.size();i++){
					Myball ball=array.get(i);
					ball.setStopflag(true);
				}
			}
		}
		
	};

}

 

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

import javax.swing.JPanel;

public class Myball extends Thread{
	private int radius=10;
	private int x=0,y=0,vx=1,vy=1;
	private Color color;//這裏都是先給各個變量附上初始值,之後這些都會變成一個隨機變量
	Graphics g;//因爲要畫圓嘛,所以畫筆畫布是必須滴……
	JPanel jp2;//這裏就是方便後面的構造器傳參……
	public Myball(JPanel jp2){
		this.jp2=jp2;
		define();//這個方法就是定義每個球最最開始的各個量的值,當時敲這段代碼的時候把它放在了run方法裏面,結果導致了程序運行出來變成一個運動軌跡上冒出N多個大小不一,顏色不一的圓
	}
	public void define(){
		Random ran=new Random();
		radius=ran.nextInt(30)+20;//這行代碼使得半徑大小發生變化(20,49)
		x=ran.nextInt(jp2.getWidth());//這裏就是設置球的出發點的x值,只要在JPanel的長度範圍之內都可以
		y=ran.nextInt(jp2.getHeight());//這裏就是設置球的出發點的y值,只要在JPanel的長度範圍之內都可以
		vx=ran.nextInt(5)+1;
		vy=ran.nextInt(5)+1;//這裏是改變球的運動方向
		color=new Color(ran.nextInt(256),ran.nextInt(256),ran.nextInt(256));//當然,很明顯這裏是改變球的顏色
	}
public boolean pauseflag=false,stopflag=false;//記住這裏一開始附的值是false
	//這裏就是特別關鍵的布爾標記變量,這裏就是寫了兩個set方法,在之前的那個BallControlled裏面有在判斷是否點擊了某個按鈕後有調用,就是爲了改值
	public void setPauseflag(boolean pauseflag) {
		this.pauseflag = pauseflag;
	}
	public void setStopflag(boolean stopflag) {
		this.stopflag = stopflag;
	}
	public void run(){//接下來就是重頭戲啦
		g=jp2.getGraphics();//這行代碼的意思就是說圓要畫在面板2上
		while(true){//當然這個死循環,主要是讓它前行,如果需要暫停或者停止的話,再跳出循環即可
			try {//這個方法的存在一般是爲了捕捉異常的情況拋出,不然容易報錯
				Thread.sleep(10);//注意休眠的方法主要是爲了控制圓的運動速度,值越小,速度越大
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			if(pauseflag &&stopflag==false){//當然這裏一定要強調stopflag==false,因爲一旦用戶先點了pause的話,就會一直循環前面而沒有實質性操作,而如果這樣的話,用戶不管點沒點stop,都沒有用,所以這裏一定要強調一下
				continue;//這裏是表示用戶確實按了pause鍵之後,應該跳出此次操作,進入下一次循環,但由於這行代碼前面只是設置了速度,並沒有其他的操作,因此這個操作就可以讓它一直循環下去,但沒有做實質性的操作,所以它就實現了暫停
			}
			clear();//這個方法是將圓的尾巴清理,所謂清理就是用背景色覆蓋,因爲大家可以試驗下,如果沒有這個clear的方法的話,我們會清晰地看到圓的運動痕跡……
			if(stopflag){
				return;//這裏就是直接跳出整個循環,而不是單詞的循環了……這樣相對於整個run的方法都結束了,自然就消失了……
			}
			
			draw();//顧名思義,這裏就是畫圓,方法之前做五子棋的時候有詳細說明
			move();//move這裏就是想讓他反彈,,所以需要判斷邊界啦……
		}
	}
	public void clear(){
		g.setColor(jp2.getBackground());
		g.fillOval(x, y, 2*radius, 2*radius);
		x+=vx;
		y+=vy;//這兩行代碼至關重要,大家不妨測試下,如果沒有這兩行代碼,圓無法動彈,因爲,圓在往前走,覆蓋背景色沒有跟着走的話,一樣沒有效果
	}
	public void draw(){//畫一個圓就不多贅述啦
		g.setColor(color);
		g.fillOval(x, y, 2*radius, 2*radius);
	}
	
	public void move(){
		if(x+radius*2>=jp2.getWidth()){//這裏就是記得要扣掉直徑的長度
			vx=-Math.abs(vx);
		}
		if(x<=0){
			vx=Math.abs(vx);
		}
		if(y+radius*2>=jp2.getHeight()){//這裏就是記得要扣掉直徑的長度
			vy=-Math.abs(vy);
		}
		if(y<=0){
			vy=Math.abs(vy);
		}
	}
	
}


 


 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章