什么是消息?
何为消息?消息就是带有某种信息的信号,如你用鼠标点击一个窗口会产生鼠标的消息,键盘输入字符会产生键盘的消息,一个窗口大小的改变也会产生消息。
消息从何而来?根据冯·诺依曼的体系结构计算机有运算器、存储器、控制器和输入设备和输出设备五大部件组成,消息主要来自输入设备,如键盘、鼠标、扫描仪等,也可来自已窗口和操作系统。
消息机制的三大要点:消息队列、消息循环(分发)、消息处理。其结构如下:
图 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操作系统中的消息机制会有多个消息输入源,且消息输入的同时也能进行消息的处理。