(源代码下载地址http://t.cn/zW0J6lj)该框架在设计之初的目标之一是做到可移植,由此带来两个问题:第一,如何在不修改代码的前提下,在不同的平台上运行基于该框架的应用程序。第二,如何让程序能在尽量多的平台上运行。要做到第一点,一般常用的方法是抽象一些通用接口,然后针对不同的平台分别实现,框架和应用程序不依赖具体平台代码,而只依赖这些通用接口,也就是常说的依赖倒置。要做到第二点,一般需要用C语言编写代码,因为目前为止还有很大一部分平台不支持C++(尤其是嵌入式平台),而C语言又难以表达面向对象思想,所以大家看到源码工程中有两个带"_C"后缀的工程(MobileDemo_C和Win32Adapter_C),这两个工程分别是将C++转换成C后的工程,方便做到更多平台的适配。在这里我们不详细介绍如何将C++代码转换成C(以后有机会再向大家介绍),而是着重介绍如何做到系统适配。
打开Win32Adapter工程,和系统适配相关的文件主要包括以下几个:EMyUi、EScreen、EWndGc、Win32File、Win32Thread、Win32Os等,下面分别介绍。
1.EScreen是对屏幕的抽象,比如我们的手机有显示屏,PC也有显示屏。由于是在PC中运行,这里EScreen可以看做是对硬件屏幕的一种抽象。
#include "EWndGc.h"class CEMyUi;class CEScreen : public CWnd{// Constructionpublic: CEScreen();// Attributespublic:// Operationspublic:// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CEScreen) public: virtual BOOL PreTranslateMessage(MSG* pMsg); //}}AFX_VIRTUAL// Implementationpublic: // Generated message map functionsprotected: //{{AFX_MSG(CEScreen) afx_msg void OnPaint(); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnSetFocus(CWnd* pOldWnd); afx_msg void OnKillFocus(CWnd* pNewWnd); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnTimer(UINT nIDEvent); afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); //}}AFX_MSG afx_msg LRESULT OnImeChar(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP()public: virtual BOOL Create(LPCTSTR lpszWindowName, const RECT& rect, CWnd* pParentWnd); void Key(AWS_KeyType type, AWS_KeyCode code); void SetUi(CEMyUi* pMyUi);protected: static BOOL RegisterClass();protected: static CString m_strClassName;private: CEMyUi* m_pMyUi; CEWndGc m_oWndGc; bool m_bIsFirstKeyDown; bool m_bNoChar;};看如上代码,CEScreen由CWnd继承而来,所以这里我们是用一个Windows窗口来模拟实际硬件屏幕。在该类的实现中会截获一些系统消息,比如按键、鼠标等消息,还有绘制消息,请看下面代码:
void CEScreen::Key(AWS_KeyType type, AWS_KeyCode code){ if ( NULL != m_pMyUi ) m_pMyUi->OnKey(type, code);}void CEScreen::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default AWS_KeyCode code = AWS_KeyCode_Null; switch ( nChar ) { case VK_BACK: code = AWS_KeyCode_Delete; break; case '0': code = AWS_KeyCode_0; break; case '1': code = AWS_KeyCode_1; break; case '2': code = AWS_KeyCode_2; break; case '3': code = AWS_KeyCode_3; break; case '4': code = AWS_KeyCode_4; break; case '5': code = AWS_KeyCode_5; break; case '6': code = AWS_KeyCode_6; break; case '7': code = AWS_KeyCode_7; break; case '8': code = AWS_KeyCode_8; break; case '9': code = AWS_KeyCode_9; break; case VK_NUMPAD0: break; case VK_NUMPAD1: break; case VK_NUMPAD2: code = AWS_KeyCode_DownArrow; break; case VK_NUMPAD3: break; case VK_NUMPAD4: code = AWS_KeyCode_LeftArrow; break; case VK_NUMPAD5: code = AWS_KeyCode_OK; break; case VK_NUMPAD6: code = AWS_KeyCode_RightArrow; break; case VK_NUMPAD7: code = AWS_KeyCode_LeftMenu; break; case VK_NUMPAD8: code = AWS_KeyCode_UpArrow; break; case VK_NUMPAD9: code = AWS_KeyCode_RightMenu; break; case VK_DECIMAL: code = AWS_KeyCode_Delete; break; } if ( nChar >= VK_NUMPAD0 && nChar <= VK_DIVIDE ) m_bNoChar = true; if ( AWS_KeyCode_Null != code && NULL != m_pMyUi ) { if ( m_bIsFirstKeyDown ) { m_pMyUi->OnKey(AWS_Key_Down, code); m_pMyUi->OnKey(AWS_Key, code); m_bIsFirstKeyDown = false; } else { m_pMyUi->OnKey(AWS_Key, code); } } CWnd::OnKeyDown(nChar, nRepCnt, nFlags);}
void CEScreen::OnPaint(){ CPaintDC dc(this); // device context for painting RECT rt; GetWindowRect(&rt); RECT rect = { 0 }; rect.right = rt.right - rt.left; rect.bottom = rt.bottom - rt.top; dc.FillSolidRect(&rect, RGB(255, 255, 255)); CEspRect ert; ert.m_ptRB.m_nX = rect.right; ert.m_ptRB.m_nY = rect.bottom; TRACE0("screen paint\n"); m_pMyUi->OnDraw(ert);}
OnKeyDown函数截获了系统按键消息,然后通过m_pMyUi->OnKey(AWS_Key, code);将其传递给框架系统处理。OnPaint函数截获了系统绘制消息,通过m_pMyUi->OnDraw(ert);函数传递给框架系统处理。Key函数可以用于产生虚拟的按键消息。
2.EMyUi是对UI的一种抽象,其父类是CAwsUi,包括了消息路由和其他