The WTL Way
WTL 的 CFrameWindowImpl 类 可以让你无比轻松地 创建 SDI 窗口 程序 。 Figure 4 显示了 WTL SDI 窗口框架结构。
Figure 4: WTL’s SDI Windowing Hierarchy
CFrameWindowImpl 类继承自 CFrameWindowImplBase 因此也就拥有了标准应用程序主框架窗口的一切功能 . 下面具体列出使用 WTL 创建的主框架窗口时支持的特性:
1) 工具条 , 菜单栏 , 状态栏 , 复合控件 (rebars)
2) 基本的视图控制 , 当主框架窗口大小变化时 , 视图自动同步调整大小
3) 复合控件区间 (Rebar band) 控制 , 增加区间或调整区间大小
4) 图案菜单 Chevron menu
5) 键盘加速键 Keyboard accelerators
6) 工具按钮上的工具提示 (Tooltips)
7) 状态栏显示帮助字符串
8) 显示框架图标
为了创建 SDI 应用程序 , 你需要 :
1) 从 CFrameWindowImpl 派生自己的框架窗口类
2) 添加 WTL DECLARE_FRAME_WND_CLASS 宏 , 并指定工具条和菜单的资源 ID
3) 添加消息映射和相应的消息映射函数,并使用 CHAIN_MSG_MAP() 把消息映射路由到框架窗口基类
For example, you can write our simple SDI example CMainFrame class using WTL like so:
例如 , 基于 WTL 的 SDI 程序中的主框架窗口类 CMainFrame 看起来像这个样子:
public:
DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
BEGIN_MSG_MAP(CMainFrame)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
COMMAND_ID_HANDLER(ID_FILE_EXIT, OnFileExit)
COMMAND_ID_HANDLER(ID_HELP_ABOUT, OnAbout)
CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
END_MSG_MAP()
LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&) {
// Create the Toolbar and set
// CFrameWindowImplBase::m_hWndToolBar
CreateSimpleToolBar();
// And the statusbar
CreateSimpleStatusBar();
return 0;
}
LRESULT OnFileExit(WORD,WORD wID, HWND,BOOL&) {
SendMessage(WM_CLOSE); // Frame knows to PostQuitMessage
return 0L;
}
…
};
DECLARE_FRAME_WND_CLASS 宏设定了框架窗口的通用资源 ID( 包括默认定制的菜单条 , 工具条等等 ). 你可以有选择地把同一个资源 ID 应用于框架窗口的标题字符串资源 , 菜单资源 , 加速键资源 , 图标资源和工具条资源 . WTL 在创建框架窗口过程中检查这一通用 ID 对应的各个资源 , 然后自动加载相应的资源 . 唯一的例外是你必须调用 CreateSimleToolBar() 成员函数手动加载工具条资源 , 而状态条不需要资源 .
消息映射中的 CHAIN_MSG_MAP 宏把消息映射路由至框架窗口基类 CFrameWindowImpl, 其中提供乐对 WM_SIZE 和 WM_DESTROY 的默认处理。
为支持 WTL, 你必须在 stdafx.h 中包含 atlapp.h 和 atlframe.h :
#define WIN32_LEAN_AND_MEAN
#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>
#include <atlframe.h>
头文件 atlapp.h 定义了 CAppModule 结构 , 它继承自 ATL 的 CComModule 并添加了对可变数量的消息映射的支持 . 头文件 atlframe 中定义了 CFrameWindowImpl 类 , 创建 WTL 的 SDI 窗口 , 我们只需要创建一个 CMainFrame 的对象实例 , 并在 WinMain() 中调用它的成员函数 CreateEx() 创建窗口 .
CAppModule _Module;
int APIENTRY WinMain(…) {
::InitCommonControls();
_Module.Init(NULL, hInstance);
CMainFrame wndMain;
wndMain.CreateEx();
wndMain.ShowWindow(nCmdShow);
wndMain.UpdateWindow();
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
_Module.Term();
return nRet;
}
成员函数 CreateEx() 调用基类成员函数 CWindowImpl::Create(), 加载与通用资源 ID 对应的资源 . CMessageLoop 类对象取代了消息循环 . ATL 允许每个线程有一个消息循环 , Multi-SDI 就是据此实现的 . 在第二部分学习 WTL 消息路由机制的时候会详细解释 CMessageLoop 和 CAppModule 类 .
到此为止应用 WTL, 我们的 SDI 应用程序看起来像 Figure 5a 所示 .
Figure 5a: SDI Application using WTL
我们尽量使我们的代码简单的同时增加了一点新特性 : 工具条 . 然而 , 添加的都是老式的工具条和菜单条 . 用户希望看到的是精美的命令条控件 , 就像 MS Office 和 IE 中看到的一样 .
In Command with Command Bars
To be continued...