什麼是消息?
何為消息?消息就是帶有某種資訊的信号,如你用滑鼠點選一個視窗會産生滑鼠的消息,鍵盤輸入字元會産生鍵盤的消息,一個視窗大小的改變也會産生消息。
消息從何而來?根據馮·諾依曼的體系結構計算機有運算器、存儲器、控制器和輸入裝置和輸出裝置五大部件組成,消息主要來自輸入裝置,如鍵盤、滑鼠、掃描器等,也可來自已視窗和作業系統。
消息機制的三大要點:消息隊列、消息循環(分發)、消息處理。其結構如下:
圖 1 :消息機制原理
消息隊列就是存放消息的一種隊列,具有先進先出的特點。每産生一個消息都會添加進消息隊列中,在Window中消息隊列是在作業系統中定義的。消息隊列就如同一群排隊打飯的少男少女,這群人中光景較好的排在前面,光景較差的排在後面,可以了解成是一種優先級隊列!要想更多的了解隊列的相關知識,可參見隊列。
消息循環就是通過循環(如while)不斷地從消息隊列中取得隊首的消息,并将消息分發出去。類似于上面的例子中分發飯菜值日生。
消息處理就是在接收到消息之後根據不同的消息類型做出不同的處理。上面例子中值日生根據學生不同類型的飯票給他們不同等級的飯菜就是消息處理,學生手中的飯票就是消息所攜帶的資訊。
事件是根據接收到的消息的具體資訊做出的特定的處理,放在代碼中是事件響應函數。上面的例子中學生拿到飯菜後吃飯就是具體的事件。
消息機制模拟
在這裡我們以控制台輸入資訊模拟視窗、對話框接收滑鼠、鍵盤等消息,以ArrayBlockingQueue對象存放消息隊列。在控制台中輸入一個數值和一個字元串代表一個消息,輸入-1結束輸入。模拟代碼如下:
package message; import java.util.Queue; import java.util.Scanner; import java.util.concurrent.ArrayBlockingQueue; /** * 消息 * @author luoweifu */ class Message { //消息類型 public static final int KEY_MSG = 1; public static final int MOUSE_MSG = 2; public static final int SYS_MSG = 3; private Object source; //來源 private int type; //類型 private String info; //資訊 public Message(Object source, int type, String info) { super(); this.source = source; this.type = type; this.info = info; } public Object getSource() { return source; } public void setSource(Object source) { this.source = source; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } public static int getKeyMsg() { return KEY_MSG; } public static int getMouseMsg() { return MOUSE_MSG; } public static int getSysMsg() { return SYS_MSG; } } interface MessageProcess { public void doMessage(Message msg); } /** * 視窗模拟類 */ class WindowSimulator implements MessageProcess{ private ArrayBlockingQueue msgQueue; public WindowSimulator(ArrayBlockingQueue msgQueue) { this.msgQueue = msgQueue; } public void GenerateMsg() { while(true) { Scanner scanner = new Scanner(System.in); int msgType = scanner.nextInt(); if(msgType < 0) { //輸入負數結束循環 break; } String msgInfo = scanner.next(); Message msg = new Message(this, msgType, msgInfo); try { msgQueue.put(msg); //新消息加入到隊尾 } catch (InterruptedException e) { e.printStackTrace(); } } } @Override /** * 消息處理 */ public void doMessage(Message msg) { switch(msg.getType()) { case Message.KEY_MSG: onKeyDown(msg); break; case Message.MOUSE_MSG: onMouseDown(msg); break; default: onSysEvent(msg); } } //鍵盤事件 public static void onKeyDown(Message msg) { System.out.println("鍵盤事件:"); System.out.println("type:" + msg.getType()); System.out.println("info:" + msg.getInfo()); } //滑鼠事件 public static void onMouseDown(Message msg) { System.out.println("滑鼠事件:"); System.out.println("type:" + msg.getType()); System.out.println("info:" + msg.getInfo()); } //作業系統産生的消息 public static void onSysEvent(Message msg) { System.out.println("系統事件:"); System.out.println("type:" + msg.getType()); System.out.println("info:" + msg.getInfo()); } } /** * 消息模拟 * @author luoweifu */ public class MessageSimulator { //消息隊列 private static ArrayBlockingQueue<Message> messageQueue = new ArrayBlockingQueue<Message>(100); public static void main(String[] args) { WindowSimulator generator = new WindowSimulator(messageQueue); //産生消息 generator.GenerateMsg(); //消息循環 Message msg = null; while((msg = messageQueue.poll()) != null) { ((MessageProcess) msg.getSource()).doMessage(msg); } } }
- 1
這裡模拟用例中隻有一個消息輸入源,且是一種線程阻塞的,隻有輸入結束後才會進行消息的處理。真實的Windows作業系統中的消息機制會有多個消息輸入源,且消息輸入的同時也能進行消息的處理。