一 事件java
1.1 事件源 多線程
圖形用戶界面上每一個可能產生事件的組件稱爲事件源。app
1.2 事件監聽者ide
Java系統中註冊的用於接收特殊事件的類。不一樣的事件對應着不一樣的監聽者,要想事件被監聽者監聽並處理,則需先將事件源註冊到監聽者。函數
1.3 事件處理流程佈局
事件源觸發事件並將事件做爲一個參數傳遞給監聽者,監聽者實現某個接口中的抽象方法,從而實現對事件的處理。Java的事件處理機制是一個委託事件模型。測試
事件源註冊的方法以下:字體
public void addActionListener(ActionListener l)動畫
添加特定的動做,監聽接收來自事件源的動做事件,若是l爲空,不會產生任何動做。this
監聽者實現的接口爲ActionListener接口,接口ActionListener來自包java.awt.event。
在此接口中只有一個方法:
public void actionPerformed(ActionEvent e)
當事件對象e發生時,調用此方法。監聽者就須要實現這個方法。
1.4 動做事件
ActionEvent包含一個事件,該事件爲執行動做事件ACTION_PERFORMED。觸發這個事件的動做爲:
(1) 點擊按鈕。
(2) 雙擊列表中的選項。
(3) 選擇菜單項。
(4) 在文本框中輸入回車。
經常使用方法以下:
public String getActionCommand() 返回引起某個事件的命令按鈕的名字,若是名字爲空,那麼返回標籤值。
public void setActionCommand(String command) 設置引起事件的按鈕的名字,默認設置爲按鈕的標籤。
例:測試動做事件
1 package test; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.applet.*; 6 public class UseButton extends Applet implements ActionListener{ 7 /** 8 * 9 */ 10 private static final long serialVersionUID = 1L; 11 12 String str = new String(); 13 Button b1; //聲明按鈕對象; 14 Button b2; 15 Color c; 16 public void init() 17 { 18 b1 = new Button("按鈕對象1"); 19 b2 = new Button("按鈕對象2"); 20 //添加事件監聽者 21 b1.addActionListener(this); 22 b1.setBackground(Color.yellow); 23 b2.addActionListener(this); 24 this.add(b1); 25 this.add(b2); 26 27 } 28 public void start() 29 { 30 str = b1.getLabel(); 31 //repaint(); 32 } 33 public void paint(Graphics g) 34 { 35 g.setColor(c); 36 g.drawString("引起事件的對象的標籤:" + str, 80,60); 37 } 38 //實現接口中的方法,響應動做事件 39 public void actionPerformed(ActionEvent e) 40 { 41 String arg = e.getActionCommand(); 42 if(arg == "按鈕對象1") 43 { 44 c = Color.red; 45 str = "按鈕對象1"; 46 } 47 else if(arg == "按鈕對象2") 48 { 49 c = Color.green; 50 str = "按鈕對象2"; 51 } 52 repaint(); 53 } 54 }
點擊按鈕對象1 ,點擊按鈕對象2
輸出結果:
1.5 文本事件(TextEvent)
文本事件即表明文本區域中文本變化的事件TEXT_VALUE_CHANGED,在文本區域中改變文本內容。
public void addTextListener(TextListener l) 添加特定的文本事件,監聽者接收來自文本對象的文本事件。若是l爲空,那麼不會拋出任何異常,並且也不會完成任何動做。
public interface TextListener extends EventListener 用於接收文本事件的監聽者接口。當對象的文本發生變化時,調用監聽者對象的方法。
接口中的方法爲:
public void textValueChanged(TextEvent e) 當文本發生改變時調用。
public Object getSource() 發生事件的對象,從EventObject繼承來的方法。
例:測試文本事件
1 package test; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.applet.Applet; 6 public class UseTextEvent extends Applet implements ActionListener, TextListener{ 7 /** 8 * @ YMM 2016/05/09 9 */ 10 private static final long serialVersionUID = 1L; 11 TextField tOld; 12 TextArea tNew; 13 Panel p; 14 public void init() 15 { 16 tOld = new TextField(25); 17 tNew = new TextArea("",8,25,TextArea.SCROLLBARS_NONE);; 18 //添加事件監聽者 19 tOld.addActionListener(this); 20 tOld.addTextListener(this); 21 //設置界面 22 p = new Panel(new BorderLayout()); 23 24 p.add(tOld,BorderLayout.NORTH); 25 p.add(tNew,BorderLayout.SOUTH); 26 27 add(p); 28 } 29 //響應文本事件 30 public void textValueChanged(TextEvent e) 31 { 32 if(e.getSource() == tOld) 33 tNew.setText(tOld.getText()); 34 } 35 //響應動做事件 36 public void actionPerformed(ActionEvent e) 37 { 38 if(e.getSource() == tOld) 39 tNew.setText(""); 40 } 41 };
1.6 選擇事件(ItemEvent)
選擇事件中包含以事件爲表明的選擇項,選中狀態發生變化的事件ITEM_STATE_ CHANGED。引起的動做爲:
(1) 改變列表類List對象選項的選中或不選中狀態。
(2) 改變下拉列表類Choice對象選項的選中或不選中狀態。
(3) 改變複選按鈕類Checkbox對象的選中或不選中狀態。
事件源對象註冊的方法以下:
public void addItemListener(ItemListener l) 添加特定的項監聽者,接收對象的選擇項發生變化的事件。
public ItemSelectable getItemSelectable() ItemEvent事件的方法,返回產生事件的事件源對象。
public interface ItemListener extends EventListener 接收選項事件的監聽者接口。當選項中事件發生時,調用監聽對象的itemStateChanged方法。
public void itemStateChanged(ItemEvent e) 當用戶選中一項或未選中一項時,調用這個方法。
1 package test; 2 import java.awt.*; 3 import java.awt.event.*; 4 import java.applet.*; 5 6 7 public class UseItemEvent extends Applet implements ItemListener{ 8 /** 9 * 2016/05/09 @author jftt 10 */ 11 private static final long serialVersionUID = 1L; 12 Checkbox cDisp; //複選按鈕 13 Button btnDisp; // 14 Choice cFont; //下拉列表 15 public void init() 16 { 17 cDisp = new Checkbox("紅色"); 18 btnDisp = new Button("顏色顯示"); 19 //setLayout(null); 20 btnDisp.setSize(120,120); 21 cFont = new Choice(); 22 cFont.add("10"); 23 cFont.add("12"); 24 cFont.add("14"); 25 //添加事件 26 cDisp.addItemListener(this); 27 cFont.addItemListener(this); 28 add(cDisp); 29 add(cFont); 30 add(btnDisp); 31 } 32 //接口事件 33 public void itemStateChanged(ItemEvent e) 34 { 35 Checkbox temp; 36 Choice temp2; 37 Font oldF; 38 //複選框 39 if(e.getItemSelectable() instanceof Checkbox) 40 { 41 temp = (Checkbox)(e.getItemSelectable()); 42 //選中爲紅色,不然爲藍色 43 if(temp.getState()) 44 btnDisp.setBackground(Color.red); 45 else 46 btnDisp.setBackground(Color.yellow); 47 } 48 //組合框 49 if(e.getItemSelectable() instanceof Choice) 50 { 51 oldF = btnDisp.getFont(); 52 temp2 = (Choice)(e.getItemSelectable()); 53 String s = temp2.getSelectedItem(); 54 String s1=oldF.getName(); 55 int s2=oldF.getStyle(); 56 //設置字體 57 btnDisp.setFont(new Font(s1,s2,Integer.parseInt(s)));// 字體,樣式(粗體,斜體等),字號 58 } 59 } 60 61 }
1.7 調整事件(AdjustmentEvent)
調整事件包含一個事件,即ADJUSTMENT_VALUE_CHANGED事件,當操縱滾動條改變其滑塊位置時引起動做。AjustEvent的方法以下:
public Adjustable getAdjustable() 返回引起事件的對象。
public int getValue() 返回調整事件中的當前值。
public void addAdjustmentListener(AdjustmentListener l) 添加調整監聽者來接收來自對象的AdjustmentEvent實例。
public interface AdjustmentListener extends EventListener 接收調整事件的監聽接口,有一個方法:
public void adjustmentValueChanged(AdjustmentEvent e) 可在調整改變時調用這個值。
例:測試調整事件。設置一個水平滾動條,取值爲1~36,隨着滑塊的變化,滾動條的值將顯示在文本區域中,而且字體大小也會跟隨變化
1 package test; 2 import java.awt.*; 3 import java.awt.event.*; 4 import java.applet.*; 5 6 public class UseAdjustmentEvent extends Applet implements AdjustmentListener{ 7 /** 8 * @author YMM 2016/05/09 9 */ 10 private static final long serialVersionUID = 1L; 11 Scrollbar s; 12 TextArea txtValue; 13 Panel p; 14 public void init() { 15 s = new Scrollbar(Scrollbar.HORIZONTAL,0,1,10,36); 16 //添加監聽者 17 s.addAdjustmentListener(this); 18 txtValue = new TextArea(5,25); 19 //界面佈局 20 p = new Panel(new BorderLayout()); 21 p.add(s,BorderLayout.NORTH); 22 p.add(txtValue,BorderLayout.SOUTH); 23 add(p); 24 } 25 public void adjustmentValueChanged(AdjustmentEvent e) { 26 int value; 27 Font oldF; 28 if(e.getAdjustable() == s) 29 { 30 //獲得滾動條的值 31 value = e.getValue(); 32 //將值寫入文本區域 33 txtValue.setText(new Integer(value).toString()); 34 //按照滾動條的值設置字體 35 oldF = txtValue.getFont(); 36 txtValue.setFont(new Font(oldF.getName(),oldF.getStyle(),value)); 37 } 38 } 39 }
1.8 鼠標事件(MouseEvent)
代表畫布或界面組件中發生的鼠標事件,包含按下鼠標、釋放鼠標、單擊鼠標、進入部件的地理位置的鼠標事件和退出部件的地理位置的鼠標事件,以及鼠標移動事件(鼠標移動和鼠標拖動)。
鼠標使用addMouseListener方法註冊,經過MouseListener接收鼠標事件;鼠標還可使用addMouseMotionListener方法註冊,經過MouseMotionListener監聽者監聽鼠標移動事件。
監聽者中有具體的方法分別針對上述具體的鼠標事件,系統可以自動分辨鼠標事件的類型並調用相應的方法,因此只需編碼實現相應的代碼就能夠了。
public int getButton() 返回哪一個按鈕發生變化。
public int getClickCount() 返回與這個事件相關的鼠標單擊的次數。
public Point getPoint() 返回同源部件相對的事件發生的x、y位置。
public int getX() 返回同源部件相對的事件發生的x位置。
public int getY() 返回同源部件相對的事件發生的y位置。
例:測試按鈕和畫布的鼠標事件,包括單擊、按下、進入和退出等
1 package test; 2 import java.awt.*; 3 import java.awt.event.*; 4 import java.applet.*; 5 6 public class UseMouseEvent extends Applet implements MouseListener,MouseMotionListener{ 7 /** 8 * 9 */ 10 private static final long serialVersionUID = 1L; 11 Button btn; 12 public void init() 13 { 14 btn = new Button("演示鼠標事件"); 15 add(btn); 16 //給按鈕添加鼠標事件和鼠標移動事件 17 btn.addMouseListener(this); 18 btn.addMouseMotionListener(this); 19 //給畫布添加鼠標事件和鼠標移動事件 20 this.addMouseListener(this); 21 this.addMouseMotionListener(this); 22 } 23 //單擊事件 24 public void mouseClicked(MouseEvent e) 25 { 26 Point p = new Point(); 27 if(e.getSource() == btn)//getSource()發生事件的對象,從EventObject繼承來的方法。 28 29 { 30 if(e.getClickCount() == 1) 31 { 32 btn.setLabel("單擊鼠標"); 33 } 34 else if(e.getClickCount() == 2) 35 { 36 btn.setLabel("雙擊鼠標"); 37 } 38 } 39 else 40 { 41 if(e.getClickCount() == 1) 42 { 43 p = e.getPoint(); 44 showStatus(p.x + "," + p.y + "單擊鼠標"); 45 } 46 else if(e.getClickCount() == 2) 47 { 48 p = e.getPoint(); 49 showStatus(p.x + "," + p.y + "雙擊鼠標"); 50 } 51 } 52 } 53 //進入事件 54 public void mouseEntered(MouseEvent e) 55 { 56 if(e.getSource() == btn) 57 btn.setLabel("進入Button"); 58 else 59 showStatus("進入Applet"); 60 } 61 public void mouseExited(MouseEvent e) 62 { 63 if(e.getSource() == btn) 64 btn.setLabel("退出Button"); 65 else 66 showStatus("退出Applet"); 67 } 68 //按下事件 69 public void mousePressed(MouseEvent e) 70 { 71 if(e.getSource() == btn) 72 btn.setLabel("按下鼠標"); 73 else 74 showStatus("按下鼠標"); 75 } 76 //釋放事件 77 public void mouseReleased(MouseEvent e) 78 { 79 if(e.getSource() == btn) 80 btn.setLabel("鬆開鼠標"); 81 else 82 showStatus("鬆開鼠標"); 83 } 84 //移動事件 85 public void mouseMoved(MouseEvent e) 86 { 87 if(e.getSource() == btn) 88 btn.setLabel("移動鼠標"); 89 else 90 showStatus("移動鼠標,新位置" + e.getX() + "," + e.getY()); 91 } 92 //拖動事件 93 public void mouseDragged(MouseEvent e) 94 { 95 if(e.getSource() == btn) 96 btn.setLabel("拖動鼠標"); 97 else 98 showStatus("拖動鼠標"); 99 } 100 }
1.9 鍵盤事件(KeyEvent)
鍵盤事件有三個:鍵盤按鍵按下,按鍵釋放,按鍵被敲擊。經常使用方法以下:
public char getKeyChar() 返回事件中鍵的字符。
public int getKeyCode() 返回整數鍵碼。
public static String getKeyText(int keyCode) 返回描述這個鍵碼的字符串,例如「HOME」、「F1」或者「A」等。
public interface KeyListener extends EventListener 用來接收鍵盤事件。使用方法addKeyListener註冊。
針對鍵盤的三個事件接口提供相應的方法進行處理,具體方法以下:
public void keyPressed(KeyEvent e) 按鍵時引起事件處理。
public void keyReleased(KeyEvent e) 釋放鍵時引起事件處理。
public void keyTyped(KeyEvent e) 鍵入鍵時引起事件處理。
例:
1 package test; 2 3 import java.applet.Applet; 4 import java.awt.*; 5 import java.awt.RenderingHints.Key; 6 import java.awt.event.ActionEvent; 7 import java.awt.event.ActionListener; 8 import java.awt.event.KeyEvent; 9 import java.awt.event.KeyListener; 10 import java.awt.event.TextEvent; 11 import java.awt.event.TextListener; 12 13 14 public class UseKeyEvent extends Applet implements KeyListener,ActionListener, TextListener { 15 /** 16 * 17 */ 18 private static final long serialVersionUID = 1L; 19 Key key; 20 Button btn; 21 TextField txt; 22 public void init() 23 { 24 btn = new Button("演示鍵盤事件"); 25 add(btn); 26 27 btn.addKeyListener(this); 28 29 this.addKeyListener(this); 30 txt = new TextField(25); 31 //添加事件監聽者 32 txt.addActionListener(this); 33 txt.addTextListener(this); 34 //設置界面 35 36 37 add(txt,BorderLayout.NORTH); 38 39 } 40 @Override 41 public void keyTyped(KeyEvent e) {//鍵入鍵時引起事件處理 42 // TODO 自動生成的方法存根 43 char ch = e.getKeyChar(); 44 if(ch =='Y' || ch == 'y') 45 txt.setText ("贊成"); 46 else if (ch == 'N' || ch == 'n') 47 txt.setText ("反對"); 48 else 49 txt.setText ("無效"); 50 51 } 52 @Override 53 public void keyPressed(KeyEvent e) { 54 // TODO 自動生成的方法存根 55 btn.setLabel("按鍵時引起事件處理"); 56 } 57 @Override 58 public void keyReleased(KeyEvent e) { 59 // TODO 自動生成的方法存根 60 btn.setLabel("釋放鍵時引起事件處理"); 61 } 62 @Override 63 public void textValueChanged(TextEvent e) { 64 // TODO 自動生成的方法存根 65 66 } 67 @Override 68 public void actionPerformed(ActionEvent e) { 69 // TODO 自動生成的方法存根 70 71 } 72 }
二 多 線 程 機 制
2.1 線程簡介
線程(thread)就是進程中的一個執行線索。Java虛擬機容許進程中同時執行多個線程。每一個線程都有一個優先級。具備較高優先級的線程先執行。
線程是操做系統分配 CPU 時間的基本實體。每個應用程序至少有一個線程,也能夠擁有多個線程。線程是程序中的代碼流。多個線程能夠同時運行並能共享資源。
線程與進程不一樣,每一個進程都須要操做系統爲其分配獨立的地址空間,而同一進程中的各個線程是在同一塊地址空間中工做。
在 Java 程序中,一些動態效果(如動畫的實現、動態的字幕等)常利用多線程技術來實現。
線程存在一個生命週期,由如下方法體現:
(1) start()方法:啓動一個線程。
(2) run()方法:定義該線程的動做。
(3) sleep()方法:使線程睡眠一段時間,單位爲ms。
(4) suspend()方法:使線程掛起。
(5) resume()方法:恢復掛起的線程。
(6) yield()方法:把線程移到隊列的尾部。
(7) stop()方法:結束線程生命週期並執行清理工做。
(8) destroy()方法:結束線程生命週期但不作清理工做。
其中最經常使用的是方法start()、run()、sleep()、stop()。
2.2 線程類和Runnable接口
2.2.1. 創建Thread類的子類
class myThread extends Thread
{
...
public void start()//啓動線程
{
...
}
public void run()//運行線程
{
...
}
}
例:多線程實例,主函數給予調用
1 public class MThread 2 { 3 public static void main(String[] args) 4 { 5 System.out.println("Hello World!"); 6 thread2 t1 = new thread2("線程實例1"); //建立線程實例 7 t1.start(); //調用 8 thread2 t2 = new thread2("線程實例2"); 9 t2.start(); 10 thread2 t3 = new thread2("線程實例3"); 11 t3.start(); 12 } 13 } 14 //自定義線程類thread2 15 class thread2 extends Thread 16 { 17 Thread thread; //定義線程實例 18 String str; 19 //構造函數 20 public thread2(String str) 21 { 22 this.str = str; 23 } 24 //啓動線程 25 public void start() 26 { 27 thread = new Thread(this); 28 thread.start(); 29 } 30 public void run() 31 { 32 int i = 0; 33 while(thread != null) 34 { 35 try 36 { 37 //計數到5時睡眠10秒 38 if(i == 5) 39 sleep(10000); 40 } 41 catch(Exception e) 42 { 43 System.out.println(e.getMessage()); 44 } 45 System.out.println(str); 46 i++; 47 } 48 } 49 };
2.2.2. 實現接口Runnable
public interface Runnable
Runnable接口能夠由任意試圖實現線程機制的類來實現。接口包含一個run方法。
public void run()
對象實現Runnable接口時,建立一個線程,啓動線程致使對象run方法的調用。
實現接口Runnable進行多線程設計的方法較爲經常使用。下面給出一個例子。
例:編寫Applet,實現Runnable接口進行簡單的動畫演示:三幅圖片依次上移
1 package test; 2 3 import java.applet.Applet; 4 import java.awt.Graphics; 5 import java.awt.Image; 6 import java.awt.Toolkit; 7 8 import javax.print.DocFlavor.URL; 9 10 11 public class UseRunnable extends Applet implements Runnable{ 12 /** 13 * 14 */ 15 private static final long serialVersionUID = 1L; 16 Thread t; 17 Image imgs[]; 18 int high,h1,h2,h3; 19 public void init() 20 { 21 high = getHeight()/3; 22 h1 = high; 23 h2 = high * 2; 24 h3 = high * 3; 25 imgs = new Image[3]; 26 for (int i = 0; i < 3; i ++) 27 { 28 /*java.net.URL url=getDocumentBase(); 29 imgs[i] = getImage(getDocumentBase(),(i+1) + ".jpg");*/ 30 imgs[i]=Toolkit.getDefaultToolkit().getImage("E:\\WorkSpace\\ecplise-luna\\JavaTest\\src\\test\\"+(i+1)+".jpg "); 31 } 32 } 33 public void start() 34 { 35 t = new Thread(this); 36 t.start(); 37 } 38 public void stop() 39 { 40 t = null; 41 } 42 //實現接口的run方法,得到動畫效果 43 public void run() 44 { 45 while( t != null) 46 { 47 try 48 { 49 Thread.sleep(100); 50 repaint(); 51 h1 --; 52 //上移,到頂點時睡眠 53 if(h1 == 0) 54 { 55 Thread.sleep(3000); 56 h2 = high; 57 } 58 //上移,到頂點時睡眠 59 h2 --; 60 if(h2 == 0) 61 { 62 Thread.sleep(3000); 63 h3 = high; 64 } 65 //上移,到頂點時睡眠 66 h3--; 67 if(h3 == 0) 68 { 69 Thread.sleep(3000); 70 h1 = high; 71 } 72 }catch(InterruptedException e){ 73 System.out.println(e.getMessage()); 74 } 75 } 76 } 77 public void paint(Graphics g) 78 { 79 //三幅圖片依次顯示 80 g.drawImage(imgs[0],0,h1,this); 81 g.drawImage(imgs[1],0,h2,this); 82 g.drawImage(imgs[2],0,h3,this); 83 } 84 public void update(Graphics g) 85 { 86 paint(g); 87 } 88 }