BREW开发教程(9):推荐采用的应用程序框架

BREW SDK本身没有提供统一的应用程序框架, 开发者可以自已选择适合自已的程序框架。但是采用良好的程序结构可以开发代码结构清晰,可读性更高,易于维护。BREW SDK中带有一个例子MediaPlayer。提供了一个IWindow接口的结构证明是一个比较好的程序框架。

这里推荐使用的IWinApp、IWindow对上述结构进行了进一步封装,采用了一个类似MFC的文档-视图模块。MFC开发时一般提供了CWinApp,CFrameWnd, CDocument和一个CView的派生类。

仿照MFC,这里为BREW开发提出了一个IWinApp和IWindow接口。IWinApp接口的作用相当于MFC中的CWinApp和CDocument。IWindow接口则相当于CFrameWnd和CView的功能。

下面对这个接口的设计作一个简单的介绍。

消息分发顺序

  • BREW AEE在接收到系统发送的消息,首先将消息发送到IWinApp接口的Handle_Event函数。
  • IWinApp接口再将消息转发至IWindow接口的Handle_Event函数。
  • IWindow接口再将消息转发到其中的当前活动的IControl的Handle_Event函数。
  • 如果IControl处理该消息,则返回TRUE,否则IWindow接着判断是否处理该消息,如是处理,则返回TRUE。否则IWinApp判断是否处理该消息,如果处理,则返回TRUE。否则BREW调用缺省的消息处理器完成对该消息的处理。

因此要求所有UI相关的窗口都必需实现IWindow接口。

IWindow接口

接口定义如下:

typedef struct _IWindow IWindow;

QINTERFACE(IWindow)

{

// Enables/Disables the window. Window controls will not process

// events if the window is disabled.

void (*Enable)(IWindow * po, boolean bEnable);

// Redraws the window if enabled

void (*Redraw)(IWindow * po);

// Handles the events routed to the window

boolean (*HandleEvent)(IWindow * po, AEEEvent eCode, uint16 wParam, uint32 dwParam);

// Releases the window resources

void (*Delete)(IWindow * po);

};

#define IWINDOW_Enable(p) GET_PVTBL(p, IWindow)->Enable(p, TRUE)

#define IWINDOW_Disable(p) GET_PVTBL(p, IWindow)->Enable(p, FALSE)

#define IWINDOW_Redraw(p) GET_PVTBL(p, IWindow)->Redraw(p)

#define IWINDOW_HandleEvent(p, e, w, dw) GET_PVTBL(p, IWindow)->HandleEvent(p, e, w, dw)

#define IWINDOW_Delete(p) GET_PVTBL(p, IWindow)->Delete(p)

#define IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel) \

(pVtbl)->Enable = (pfnEn); \

(pVtbl)->Redraw = (pfnRd); \

(pVtbl)->HandleEvent = (pfnHE); \

(pVtbl)->Delete = (pfnDel)

typedef struct _AEE_BASE_WINDOW_T AEE_BASE_WINDOW_T;

#define INHERIT_BASEWINDOW(iname) \

DECLARE_VTBL(iname) \

IWinApp* m_pOwner; \

IShell* m_pIShell; \

IDisplay* m_pIDisplay; \

flg m_bActive:1

IWindow接口定义了四个虚函数:

虚函数 说明
Enable 激活该IWindow派生类,要必要重画该窗口
Redraw 窗口重画函数,IWinApp接口根据需要会调用该函数来重画当前活动窗口。
HandleEvent 窗口消息处理函数,IWinApp接口调用该函数将消息转发至IWindow接口类。
Delete 清除该IWindow接口。

其它定义的几个宏是为IWindow派生类提供的。

如果需要从IWindow派生UI Window时,可以采用如下的方式。例如:

typedef struct _TestScrollWin TestScrollWin;

struct _TestScrollWin

{

INHERIT_BASEWINDOW(IWindow);

PIRADIOBOX pRadio[12];

PICHECKBOX pCheck[12];

ITextCtl* m_pServerName; //server name input box

ITextCtl* m_pDomainName; //Domain name input box

ITextCtl* m_pUserName; //User name input box

ITextCtl* m_pPassword; //User password input box

IContainer* m_pContainer;

IMenuCtl * m_pSoftkey;

};

PUBLIC IWindow* TestScrollWin_New(IWinApp *pApp,void *pData);

PUBLIC boolean TestScrollWin_HandleEvent(IWindow * po, AEEEvent eCode, uint16 wParam, uint32 dwParam);

PUBLIC void TestScrollWin_Redraw(IWindow * po);

PUBLIC void TestScrollWin_Delete(IWindow * po);

PUBLIC void TestScrollWin_Enable(IWindow * po, boolean bEnable);

这里要注意的xxxx_New函数的实现,例子如下:

IWindow* TestScrollWin_New(IWinApp *pApp,void *pData)

{

TestScrollWin *pThis=NULL;

VTBL(IWindow) vtbl;

IWINDOW_SETVTBL(&vtbl, TestScrollWin_Enable,

TestScrollWin_Redraw, TestScrollWin_HandleEvent,

TestScrollWin_Delete);

pThis = (TestScrollWin *)AEE_BASE_WINDOW_New(sizeof(TestScrollWin),

pApp, &vtbl);

if (!pThis)

return NULL;

pThis->m_pOwner=pApp;

pThis->m_pIDisplay=pApp->a.m_pIDisplay;

pThis->m_pIShell=pApp->a.m_pIShell;

。。。

其中宏IWINDOW_SETVTBL 是为从IWindow派生的类初始化四个虚函数指针。函数AEE_BASE_WINDOW_New则是为该派生类分配内存。

IWinApp接口

IWinApp进一步提供了对AEEApplet结构的封,提供了消息映射及消息分发功能。

其主要定义如下:

#define AEE_MAX_EVENT_HANDLERS 256 //Max events handlers

#define AEE_MAX_WINDOWS 256 //Max window type

#define AEE_WINDOW_CLASS_NONE 0

typedef struct _IWinApp IWinApp;

typedef IWindow *(*WINDOWCONSTRUCTOR)(IWinApp *pApp,void *pData);

struct AEE_MSGMAP_ENTRY

{

AEEEvent nID; // control ID (or 0 for windows messages)

AEEEvent nLastID; // used for entries specifying a range of control id’s

AEEHANDLER pfn; // routine to call (or special value)

};

struct AEE_WINMAP_ENTRY

{

uint16 nWindowClass; //Window class ID

WINDOWCONSTRUCTOR pfn; //Window constructor

};

typedef struct AEE_MSGMAP_ENTRY PAEE_MSGMAP_ENTRY[AEE_MAX_EVENT_HANDLERS];

#define DECLARE_MESSAGE_MAP() \

struct AEE_MSGMAP_ENTRY m_tMessageEntries[AEE_MAX_EVENT_HANDLERS]

#define INHERIT_IWinApp \

AEEApplet a; \

IWindow* m_pActiveWindow; \

uint16 m_nEventNum; \

uint16 m_nWindowsNum; \

AEECallback m_cbRedraw; \

flg m_bRedraw:1; \

uint16 m_nActiveWindowType; \

struct AEE_WINMAP_ENTRY m_tWindowClassEntries[AEE_MAX_WINDOWS]; \

DECLARE_MESSAGE_MAP()

struct _IWinApp

{

INHERIT_IWinApp;

};

PUBLIC void BEGIN_MESSAGE_MAP(IWinApp *pApp);

#define END_MESSAGE_MAP(p)

PUBLIC void ON_EVENT(IWinApp *pApp,AEEEvent eCode,AEEHANDLER pfn);

PUBLIC void ON_EVENT_RANGE(IWinApp *pApp,AEEEvent eCode1,AEEEvent eCode2,AEEHANDLER pfn);

PUBLIC boolean IWINAPP_HandleEvent(IWinApp * pApp, AEEEvent eCode,uint16 wParam, uint32 dwParam);

PUBLIC boolean IWINAPP_RegisteWindowClass(IWinApp * pApp,uint16 nClass,WINDOWCONSTRUCTOR pfn);

PUBLIC void IWINAPP_Redraw(IWinApp *pThis, boolean bDefer);

PUBLIC void IWINAPP_RedrawNotify(IWinApp *pThis);

#define IWINAPP_CancelRedraw(p) { CALLBACK_Cancel(&(p)->m_cbRedraw); (p)->m_bRedraw = FALSE; }

#define IWINAPP_DisableWin(p) { IWINDOW_Disable((p)->m_pActiveWindow); IWINAPP_CancelRedraw(p); }

PUBLIC void IWINAPP_InitMessageMap(IWinApp * pApp);

PUBLIC boolean IWINAPP_InitInstance(IWinApp * pApp);

PUBLIC void IWINAPP_ExitInstance(IWinApp * pApp);

PUBLIC boolean IWINAPP_SetWindow(IWinApp *pThis,uint16 eWin, void *pData);

其中关键的是消息映谢处理:

宏BEGIN_MESSAGE_MAP为定义消息映射开始。

宏ON_EVENT定义一个消息与处理函数对应关系。

宏ON_EVENT_RANGE定义一个消息段与处理函数之间的对应关系。

宏END_MESSAGE_MAP结束消息定义。

所有的消息处理函数类型为AEEHANDLER

其定义为

typedef boolean (*AEEHANDLER)(void * pData, AEEEvent evt, uint16 wParam, uint32 lParam);

用法示例如下:

PUBLIC void IWINAPP_InitMessageMap(IWinApp *pApp)

{

BEGIN_MESSAGE_MAP(pApp);

ON_EVENT(pApp,EVT_APP_START,OnStart);

ON_EVENT(pApp,EVT_KEY,OnKey);

ON_EVENT_RANGE(pApp,EVT_KEY,EVT_CTL_SET_TEXT,OnKey);

END_MESSAGE_MAP(pApp);

}

函数IWINAPP_InitMessageMap 是由IWinApp提供一个函数,用于初始化消息映射。

采用这个结构在程序入口点函数AEEClsCreateInstance 会有如下代码。

if(AEEApplet_New(sizeof(CHelloApp), ClsId, pIShell,pMod,(IApplet**)ppObj,

(AEEHANDLER)IWINAPP_HandleEvent,

(PFNFREEAPPDATA)IWINAPP_ExitInstance) == TRUE)

从IWinApp派生类中无需再定义自已的HandleEvent函数。IWinApp接口直接完成消息处理。

函数IWINAPP_RegisteWindowClass 用于向IWinApp接口注册一个IWindow派生类。IWINAPP_SetWindow则将某个注册过的IWindow派生类设为当前活动窗口。

你可能感兴趣的:(brew)