(源代码下载地址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
{
// Construction
public:
CEScreen();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CEScreen)
public:
virtual BOOL PreTranslateMessage(MSG* pMsg);
//}}AFX_VIRTUAL
// Implementation
public:
// Generated message map functions
protected:
//{{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,包括了消息路由和其他