這一活生生的例子雖然看著有些悲涼(排隊打飯的情景相信曾經是學生的你一定經歷過,可能沒這般悲涼而已),卻像極了消息機制的原理,也許發明消息機制的靈感就是原來於這樣的生活吧!排隊的學生就是消息隊列,值日生分發飯菜就消息循環並完成消息處理,學生吃飯就類似於事件處理。
什麼是消息?何為消息?消息就是帶有某種信息的信號,如你用鼠標點擊一個窗口會產生鼠標的消息,鍵盤輸入字符會產生鍵盤的消息,一個窗口大小的改變也會產生消息。
消息從何而來?根據馮·諾依曼的體系結構計算機有運算器、存儲器、控制器和輸入設備和輸出設備五大部件組成,消息主要來自輸入設備,如鍵盤、鼠標、掃描儀等,也可來自已窗口和操作系統。
消息機制的三大要點:消息隊列、消息循環(分發)、消息處理。其結構如下:
圖 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 messageQueue = new ArrayBlockingQueue(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);
}
}
}這裡模擬用例中只有一個消息輸入源,且是一種線程阻塞的,只有輸入結束後才會進行消息的處理。真實的Windows操作系統中的消息機制會有多個消息輸入源,且消息輸入的同時也能進行消息的處理。
原文來自:http://blog.csdn.net/luoweifu/article/details/45568411
本文地址:http://www.linuxprobe.com/program-message.html
http://www.bkjia.com/Linuxjc/1191948.html TechArticle