从WTL的应用程序生成向导能得到什么
WTL的发布版本附带一个很棒的应用程序生成向导,让我们以一个SDI 应用为例看看它有什么特性。
使用向导的整个过程 在VC的IDE环境下单击File|New菜单,从列表中选择ATL/WTL AppWizard,我们要重写时钟程序,所以用WTLClock作为项目的名字:
在下一页你可以选择项目的类型,SDI,MDI或者是基于对话框的应用,当然还有其它选项,如下图所示设置这些选项,然后点击“下一步”:
在最后一页你可以选择是否使用toolbar,rebar和status bar,为了简单起见,取消这些选项并单击“结束”。
查看生成的代码 向导完成后,在生成的代码中有三个类:CMainFrame, CAboutDlg, 和CWTLClockView,从名字上就可以猜出这些类的作用。虽然也有一个是视图类,但它仅仅是从CWindowImpl派生出来的一个简单的窗口类,没有象MFC那样的文档/视图结构。
还有一个_tWinMain()函数,它先初始化COM环境,公用控件和_Module,然后调用全局函数Run()。Run()函数创建主窗口并开始消息循环,Run()调用CMessageLoop::Run(),消息泵实际上是位于CMessageLoop::Run()内,我将在下一个章节介绍CMessageLoop的更多细节。
CAboutDlg是CDialogImpl的派生类,它对应于ID IDD_ABOUTBOX资源,我在第一部分已经介绍过对话框,所以你应该能看懂CAboutDlg的代码。
CWTLClockView是我们的程序的视图类,它的作用和MFC的视图类一样,没有标题栏,覆盖整个主窗口的客户区。CWTLClockView类有一个PreTranslateMessage()函数,也和MFC中的同名函数作用相同,还有一个WM_PAINT的消息响应函数。这两个函数都没有什么特别之处,只是我们会填写OnPaint()函数来显示时间。
最后是我们的CMainFrame类,它有许多有趣的新东西,这是这个类的定义缩略版本:
class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>, public CMessageFilter, public CIdleHandler { public: DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
CWTLClockView m_view;
virtual BOOL PreTranslateMessage(MSG* pMsg); virtual BOOL OnIdle();
BEGIN_UPDATE_UI_MAP(CMainFrame) END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CMainFrame) // ... CHAIN_MSG_MAP(CUpdateUI<CMainFrame>) CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>) END_MSG_MAP() }; |
CMessageFilter是一个嵌入类,它提供PreTranslateMessage()函数,CIdleHandler也是一个嵌入类,它提供了OnIdle()函数。 CMessageLoop, CIdleHandler 和 CUpdateUI三个类互相协同完成界面元素的状态更新(UI update),就像MFC中的ON_UPDATE_COMMAND_UI宏一样。
CMainFrame::OnCreate()中创建了视图窗口并保存这个窗口的句柄,当主窗口改变大小时视图窗口的大小也会随之改变。OnCreate()函数还将CMainFrame对象添加到由CAppModule维持的消息过滤器队列和空闲处理队列,我将在稍后介绍这些。
LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, |WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);
// register object for message filtering and idle updates CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter(this); pLoop->AddIdleHandler(this);
return 0; } |
m_hWndClient是CFrameWindowImpl对象的一个成员变量,当主窗口大小改变时此窗口的大小也将改变。
在生成的CMainFrame中还添加了对File|New, File|Exit, 和 Help|About菜单消息的处理。我们的时钟程序不需要这些默认的菜单项,但是现在将它们留在代码中也没有害处。现在可以编译并运行向导生成的代码,不过这个程序确实没有什么用处。如果你感兴趣的话可以深入CMainFrame::CreateEx()函数的内部看看主窗口和它的资源是如何被加载和创建得。
我们的下一步WTL之旅是CMessageLoop,它掌管消息泵和空闲处理。