Version1
下面是模拟消息循环程序的第一个版本,使用C++编写。用户可以输入特定的命令(如"QUIT"、“CREATE”、“PAINT”),程序会根据这些命令执行相应的操作。如果用户输入的命令不在预定义的命令列表中,程序会将其视为其他类型的消息并处理。
状态机
使用状态机将version1消息循环模拟系统分为以下三个状态。(此处的消息循环模拟系统是一个使用状态机实现的模拟消息循环的程序,没有实现系统与应用程序互相发消息这一主要功能。与Windows的消息循环并非完全等同,version1中包含许多非message loop的部分)
状态名 | 状态描述 |
---|---|
READ_INPUT | 消息触发 |
PROCESS_MESSAGE_IN_MESSAGEQUEUE | 处理消息队列中的消息 |
WAIT_INPUT | 等待输入 |
枚举消息循环的状态State。初始化一个变量currentState用于存储当前状态,并将其设为等待输入状态。
状态机的事件有四种,如下表所示。
Event名 | Event描述 |
---|---|
newInputAvailable | 输入中有新的消息 |
NoNewInput | 输入中没有新的消息 |
messageQueueEmpty | 消息队列为空 |
messageQueueEmpty | 消息队列不为空 |
状态转换表如下
CURRSTATE | EVENT | NEXTSTATE |
---|---|---|
READ_INPUT | newInputAvailable | READ_INPUT |
READ_INPUT | NoNewInput | PROCESS_MESSAGE_IN_MESSAGEQUEUE |
PROCESS_MESSAGE_IN_MESSAGEQUEUE | newInputAvailable | READ_INPUT |
PROCESS_MESSAGE_IN_MESSAGEQUEUE | messageQueueEmpty | WAIT_INPUT |
PROCESS_MESSAGE_IN_MESSAGEQUEUE | messageQueueNotEmpty | PROCESS_MESSAGE_IN_MESSAGEQUEUE |
WAIT_INPUT | newInputAvailable | READ_INPUT |
状态转换图如下
消息类型
枚举消息类型Message。消息类型我自定义了四种,分别是QUIT, CREATE, PAINT, OTHERS。规定当收到QUIT消息时消息循环结束。
消息队列
初始化一个队列messageQueue,用于存储待处理的消息。
消息循环
消息循环是一个while循环,循环中是switch语句,根据当前的状态执行相应的操作。while循环的循环条件是一个全局变量isRunning,类型是布尔值,初始值设为true。当处理消息时处理的消息为QUIT时将isRunning设为false。
switch语句的具体的操作如下。
如果当前状态是读取输入,就执行readInput函数。
如果当前状态是处理消息,就执行processMessageInMessageQueue函数。
如果当前状态是等待输入,就执行waitInput函数。
读取输入
readInput函数用于读取用户的输入,函数没有形式参数,没有返回值。如果用户有新的输入,就读取输入字符并使用convertToMessage函数将其转换为消息,然后使用postMessage函数将消息添加到消息队列中。
-
读取输入字符
注意,这里使用了_kbhit()和_getche()函数读取用户的输入字符,有以下三点好处。- 非阻塞读取
_kbhit()函数是一个非阻塞函数,会立即返回是否有键盘输入的结果。因此,如果没有键盘输入时,程序不会停止并等待用户输入,而是可以继续执行其他任务。 - 即时显示输入
_getche()函数在读取用户输入的同时,也会将输入的字符显示在控制台上。因此用户可以立即看到输入的字符。 - 读取单个字符
_getche()函数可以读取单个字符,不需要用户按下回车键。
- 非阻塞读取
-
将字符转化为消息
convertToMessage函数将字符转化为消息。函数的形式参数为字符串类型的input。它包含一个映射,将字符串映射到对应的Message枚举值。然后检查字符串input是否在映射中。如果在映射中,函数会将message设置为映射中对应的Message枚举值。如果不在映射中,函数将message设置为OTHERS。最后返回message作为函数的返回值。 -
将消息添加到消息队列中
postMessage函数的形式参数为Message类型的message。函数的作用是将message加入消息队列。
处理消息队列中的消息
processMessageInMessageQueue函数的主要作用是处理消息队列中的消息。函数没有形式参数,没有返回值。具体操作如下。
首先,检查消息队列是否为空。如果不为空,使用getMessage函数从队列中获取一个消息,然后使用processMessage函数处理这个消息。再次检查消息队列是否为空。如果不为空,就将当前状态设置为PROCESS_MESSAGE_IN_MESSAGEQUEUE,也就是说在下一次循环中将处理消息队列中的消息。如果消息队列为空,则将当前状态设置为WAIT_INPUT,也就是说在下一次循环中将等待用户的输入。最后检查是否有新的用户输入。如果有新的输入,就将当前状态设置为READ_INPUT,这意味着在下一次循环中将读取用户的输入。如果消息队列一开始就是空的,就将当前状态设置为WAIT_INPUT。
- 从消息队列读取消息
getMessage函数没有形式参数,返回值是Message类型。当消息队列不为空时,getMessage函数会从消息队列队头取出一个消息,并将该消息作为返回值返回。 - 处理消息
processMessage函数用于处理消息的输出,形式参数是Message类型的message。对于不同的消息有不同的处理方式。具体来说,如果消息是QUIT,函数会输出"quit",然后将全局变量isRunning设置为false,这将导致消息循环结束,程序退出,函数返回-1。如果消息是CREATE,函数会输出"create",函数返回0。如果消息是PAINT,函数会输出"paint",然后返回0。如果消息是其他类型(default),函数会输出"others",然后返回0。
等待输入
waitInput函数的作用是让消息循环系统在当前没有消息需要处理时等待用户的输入,函数没有形式参数,没有返回值。函数使用_kbhit()函数检查是否有键盘输入。如果有键盘输入就使用_getche()函数读取输入的字符,并将当前状态设置为READ_INPUT,也就是说在下一次循环中,程序将读取用户的输入。