📄 《深入brew开发》——第八章 brew的事件处理 - gemsea的专栏 - csdnblog.htm
字号:
<DIV align=center>图8.6 状态机基本原理</DIV>
<DIV><SPAN>
</SPAN>状态机在代码上讲就是一个for(;;)循环,只有在创建一个用户界面之后才会暂时终止运行,可以实现这样功能的代码如下(可以在本书所附的示例代码Test5/FileExplorer应用目录下的AppStateMachine.c中找到这个函数):</DIV>
<TABLE
style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse"
cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD
style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid"
vAlign=top width=568>
<DIV>/*====================================================================</DIV>
<DIV>函数<SPAN> : CStateMachine_RunFSM</SPAN></DIV>
<DIV>说明<SPAN> : </SPAN>有限状态机引擎。</DIV>
<DIV>参数<SPAN> : pMe
[in]</SPAN>:指向CStateMachine对象结构的指针</DIV>
<DIV>返回值 : 无。</DIV>
<DIV>备注<SPAN> : </SPAN>无</DIV>
<DIV>====================================================================*/</DIV>
<DIV>static void CStateMachine_RunFSM(CStateMachine *pMe)</DIV>
<DIV>{</DIV>
<DIV><SPAN> NextFSMAction nextFSMAction =
NFSMACTION_WAIT;</SPAN></DIV>
<DIV><SPAN> </SPAN></DIV>
<DIV><SPAN> for(;;)</SPAN></DIV>
<DIV><SPAN> {</SPAN></DIV>
<DIV><SPAN> nextFSMAction
= pMe->m_pfnState((IStateMachine *)pMe, </SPAN></DIV>
<DIV><SPAN>
pMe->m_pUserState);</SPAN></DIV>
<DIV><SPAN> </SPAN></DIV>
<DIV><SPAN>
pMe->m_eWndRet =
WNDRET_CREATE;</SPAN></DIV>
<DIV><SPAN>
pMe->m_wWndParam = 0;</SPAN></DIV>
<DIV><SPAN>
pMe->m_dwWndParam = 0;</SPAN></DIV>
<DIV><SPAN>
</SPAN></DIV>
<DIV><SPAN> if
(nextFSMAction == NFSMACTION_WAIT)</SPAN></DIV>
<DIV><SPAN> {</SPAN></DIV>
<DIV><SPAN>
break;</SPAN></DIV>
<DIV><SPAN> }</SPAN></DIV>
<DIV><SPAN> }</SPAN></DIV>
<DIV>} // End CStateMachine_RunFSM</DIV></TD></TR></TBODY></TABLE>
<DIV><SPAN>
pMe->m_pfnState</SPAN>就是我们在应用程序中的状态函数,状态机根据这个函数的返回值nextFSMAction来判断是否暂停状态机的运行。从代码中可以看到当nextFSMAction为NFSMACTION_WAIT的时候这个for循环将被break语句打破。</DIV>
<DIV><SPAN>
</SPAN>我们定义的状态机结构体如下所示(下面的代码综合了AppStateMachine.h和.c的内容):</DIV>
<TABLE
style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse"
cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD
style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid"
vAlign=top width=568>
<DIV>// 状态处理函数返回给状态处理主函数的值类型</DIV>
<DIV>typedef enum _NextFSMAction{</DIV>
<DIV><SPAN> NFSMACTION_WAIT,</SPAN></DIV>
<DIV><SPAN> NFSMACTION_CONTINUE</SPAN></DIV>
<DIV>} NextFSMAction;</DIV>
<DIV> </DIV>
<DIV>typedef NextFSMAction (*PFNSTATE)(IStateMachine *po, void
*pUser);</DIV>
<DIV> </DIV>
<DIV>typedef struct _CStateMachine{</DIV>
<DIV><SPAN> AEEVTBL(IStateMachine)
*pvt;</SPAN></DIV>
<DIV><SPAN>
uint32
m_nRefs;</SPAN></DIV>
<DIV><SPAN> </SPAN></DIV>
<DIV><SPAN> // IShell interface</SPAN></DIV>
<DIV><SPAN>
IShell
*m_pShell;</SPAN></DIV>
<DIV><SPAN> </SPAN></DIV>
<DIV><SPAN> PFNSTATE
m_pfnState; // </SPAN>状态处理函数</DIV>
<DIV><SPAN> void
*
m_pUserState; // </SPAN>用户数据</DIV>
<DIV><SPAN> PFNAEEEVENT
m_pfnEvent; // </SPAN>事件处理函数</DIV>
<DIV><SPAN> void
*
m_pUserEvent; // </SPAN>用户数据</DIV>
<DIV><SPAN>
int
m_eWndRet; // Windows</SPAN>返回值</DIV>
<DIV><SPAN>
uint16
m_wWndParam; // Windows</SPAN>返回值word参数</DIV>
<DIV><SPAN>
uint32
m_dwWndParam; // Windows</SPAN>返回值dword参数</DIV>
<DIV><SPAN> </SPAN></DIV>
<DIV><SPAN> AEECLSID
m_dwAppClsID; //
</SPAN>当前使用此接口的应用程序Class ID</DIV>
<DIV><SPAN>
boolean
m_bSuspending; // </SPAN>当前状态机是否被挂起</DIV>
<DIV>}CStateMachine;</DIV></TD></TR></TBODY></TABLE>
<DIV><SPAN>
</SPAN>应用程序中将通过一个指针变量来保存一个这样的结构体。我们将创建的用户界面叫做一个Window。状态机使用m_pfnState来获得状态,使用m_pfnEvent来处理用户Window的事件,在m_pfnState状态函数执行的时候创建Window。</DIV>
<DIV><STRONG><FONT
size=3><SPAN>8.2.3</SPAN><SPAN>实现状态机</SPAN>管理的接口</FONT></STRONG></DIV>
<DIV><SPAN>
</SPAN>为了能够管理状态机,我们必须提供一些管理状态机的接口:</DIV>
<DIV><SPAN>
1</SPAN>、启动状态机,通过这个接口应用程序可以选择在何时启动这个状态机。</DIV>
<DIV><SPAN>
2</SPAN>、终止状态机,通过这个接口应用程序可以选择在何时终止状态机的运行。</DIV>
<DIV><SPAN>
3</SPAN>、挂起状态机,通过这个接口应用程序可以暂停状态机的运行,同时保存相关的状态数据,以便于恢复状态机的运行。</DIV>
<DIV><SPAN>
4</SPAN>、恢复状态机,通过这个接口应用程序可以恢复一个被挂起的状态机继续运行。</DIV>
<DIV><SPAN>
5</SPAN>、转移状态,通过这个接口应用程序可以转移到下一个状态去处理。</DIV>
<DIV><SPAN>
6</SPAN>、创建一个窗口(Window),通过这个接口应用程序可以创建一个显示界面。</DIV>
<DIV><SPAN>
7</SPAN>、关闭一个窗口(Window),通过这个接口应用程序可以关闭一个显示界面,同时设置相应的Window返回值给状态处理函数。</DIV>
<DIV><SPAN>
8</SPAN>、Window事件捕获函数,应用程序将通过这个接口将事件传递给Window的事件捕获函数。</DIV>
<DIV><SPAN>
9</SPAN>、辅助函数,如获得当前的状态,以及获得当前窗口的返回值等操作。</DIV>
<DIV><SPAN>
</SPAN>与上面描述功能基本相近的各个函数已经定义在了FileExplorer应用程序中的AppStateMachine.c的文件中。他们的形式如下:</DIV>
<TABLE
style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse"
cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD
style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid"
vAlign=top width=568>
<DIV>/*====================================================================</DIV>
<DIV>函数<SPAN>
</SPAN>:IStateMachine_HandleEvent</DIV>
<DIV>描述<SPAN>
</SPAN>:状态机的事件捕获函数,在此函数中将事件传递给在当前状态中打开的窗口</DIV>
<DIV>参数<SPAN> </SPAN>:po[in] 指向当前状态机结构体的指针</DIV>
<DIV><SPAN>
eCode[in] </SPAN>当前的事件代码</DIV>
<DIV><SPAN>
wParam[in] </SPAN>事件的16位参数</DIV>
<DIV><SPAN>
dwParam[in] </SPAN>事件的32位参数</DIV>
<DIV>返回值 :如果捕获事件则返回TRUE,否则返回FALSE</DIV>
<DIV>====================================================================*/</DIV>
<DIV>static boolean IStateMachine_HandleEvent(IStateMachine
*po,</DIV>
<DIV><SPAN>
AEEEvent eCode,</SPAN></DIV>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -