(转)WTL入门(2)-- WTL基础

 源代码下载: http://download.csdn.net/source/3522792

WTL Overview

WTL的类可以分为以下几类:

1)窗口实现类 - CFrameWindowImpl, CMDIFrameWindowImpl …
2)控件封装类 - CButton, CListViewCtrl …
3)GDI封装类 - CDC, CMenu …
4)特殊的UI特性 - CSplitterWindow, CUpdateUI, CDialogResize, CCustomDraw …
5)基础类和宏 - CString, CRect, BEGIN_MSG_MAP_EX …

Beginning a WTL EXE

我们从零开始不通过WTL AppWizard创建一个WTL项目。

1)在Stdafx.h添加头文件和定义宏

[cpp]  view plain copy
  1. // stdafx.h  
  2.   
  3. #define STRICT  
  4.   
  5. #define WIN32_LEAN_AND_MEAN  
  6.   
  7. #define _WTL_USE_CSTRING   // 如果计划使用WTL封装的CString类,需要定义此宏。  
  8.   
  9. // CString是在atlmisc.h中定义的,但是在其他的头文件中可能会用到此类,尤其在atlmisc.h之前被包含的头文件如AtlApp.h  
  10.   
  11. // 因此,通过这种方法可以预声明一个CString类,以告诉其他头文件CString是个什么东东  
  12.   
  13.    
  14.   
  15. #include <atlbase.h>       // base ATL classes  
  16.   
  17. #include <atlapp.h>        // base WTL classes,包含消息处理和CAppModule的定义(派生于CComModule类)  
  18.   
  19. extern CAppModule _Module; // WTL version of CComModule,它包含我们所需要的空闲进程和UI更新等特性  
  20.   
  21. #include <atlwin.h>        // ATL GUI classes  
  22.   
  23. #include <atlframe.h>      // WTL frame window classes  
  24.   
  25. #include <atlmisc.h>       // WTL utility classes like CString  
  26.   
  27. #include <atlcrack.h>      // WTL enhanced msg map macros  


2)定义一个Frame Window,其派生于CFrameWindowImpl。并且用DECLARE_FRAME_WND_CLASS宏定义窗口类。

[cpp]  view plain copy
  1. // MyWindow.h:  
  2.   
  3. class CMyWindow : public CFrameWindowImpl<CMyWindow>  
  4.   
  5. {  
  6.   
  7. public:  
  8.   
  9.      // 两个参数,前者表示窗口名字,如果为NULL,WTL将自动生成一个  
  10.   
  11.      // 后者表示窗口的资源ID。  
  12.   
  13. // WTL将会根据此ID搜索图标、菜单、快捷键表等资源,并在窗口创建时加载它们。  
  14.   
  15. // 同样也通过此ID搜索一个字符串用于窗口的Title  
  16.   
  17.      DECLARE_FRAME_WND_CLASS(_T("First WTL window"), IDR_MAINFRAME);  
  18.   
  19.    
  20.   
  21.      BEGIN_MSG_MAP(CMyWindow)  
  22.   
  23.          // 用这种方法将消息链到其基类中(值得注意的是WM_SIZE和WM_DESTORY)  
  24.   
  25. CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>)  
  26.   
  27.      END_MSG_MAP()  
  28.   
  29. }  


3)WinMain函数,与上一节相似:

[cpp]  view plain copy
  1. #include "stdafx.h"  
  2.   
  3. #include "MyWindow.h"  
  4.   
  5.    
  6.   
  7. CAppModule _Module;  
  8.   
  9.    
  10.   
  11. int APIENTRY WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,  
  12.   
  13.                          LPSTR lpCmdLine, int nCmdShow )  
  14.   
  15. {  
  16.   
  17.      _Module.Init ( NULL, hInstance );  
  18.   
  19.    
  20.   
  21.      CMyWindow wndMain;  
  22.   
  23.      MSG msg;  
  24.   
  25.    
  26.   
  27.      // Create the main window  
  28.   
  29.      if ( NULL == wndMain.CreateEx() )  
  30.   
  31.          return 1;       // Window creation failed  
  32.   
  33.    
  34.   
  35.      // Show the window  
  36.   
  37.      wndMain.ShowWindow ( nCmdShow );  
  38.   
  39.      wndMain.UpdateWindow();  
  40.   
  41.    
  42.   
  43.      // Standard Win32 message loop  
  44.   
  45.      while ( GetMessage ( &msg, NULL, 0, 0 ) > 0 )  
  46.   
  47.      {  
  48.   
  49.          TranslateMessage ( &msg );  
  50.   
  51.          DispatchMessage ( &msg );  
  52.   
  53.      }  
  54.   
  55.    
  56.   
  57.      _Module.Term();  
  58.   
  59.      return msg.wParam;  
  60.   
  61. }  


此时运行程序,将会起动一个空窗口的。

WTL Message Map Enhancements

ATL中需要对消息参数WPARAM和LPARAM进行解包的,但是WTL中增强的消息路由机制已经帮我们解决了此问题,
对于ATL3.0,必须用宏BEGIN_MSG_MAP_EX定义消息路由
对于ATL7.0/7.1,从CwindowImpl和CDialogImpl派生的类可以直接使用 宏BEGIN_MSG_MAP定义消息路由,其他类必须使用宏BEGIN_MSG_MAP_EX定义消息路由。

4)添加WM_CREATE消息处理

[cpp]  view plain copy
  1. class CMyWindow : public CFrameWindowImpl<CMyWindow>  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7. BEGIN_MSG_MAP_EX(CMyWindow)  
  8.   
  9.     // 用这种方法声明WM_CREATE消息的处理  
  10.   
  11.         MSG_WM_CREATE(OnCreate)  
  12.   
  13.         CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>)  
  14.   
  15.     END_MSG_MAP()  
  16.   
  17.    
  18.   
  19.     // OnCreate(...) ?  
  20.   
  21. };  
  22.   
  23.          MSG_WM_CREATE宏的定义如下:  
  24.   
  25. #define MSG_WM_CREATE(func) \  
  26.   
  27.     if (uMsg == WM_CREATE) \  
  28.   
  29.     { \  
  30.   
  31.         SetMsgHandled(TRUE); \  
  32.   
  33.         lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \  
  34.   
  35.         if(IsMsgHandled()) \  
  36.   
  37.             return TRUE; \  
  38.   
  39. }  


可以看出,消息参数被解包为LPCREATESTRUCT,只有一个参数,返回值为LRESULT对象。同时没有了bHandle参数,通过SetMsgHandled()代替此参数。

[cpp]  view plain copy
  1. class CMyWindow : public CFrameWindowImpl<CMyWindow>  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.     BEGIN_MSG_MAP_EX(CMyWindow)  
  8.   
  9.         MSG_WM_CREATE(OnCreate)  
  10.   
  11.         CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>)  
  12.   
  13.     END_MSG_MAP()  
  14.   
  15.    
  16.   
  17.     LRESULT OnCreate(LPCREATESTRUCT lpcs)  
  18.   
  19.     {  
  20.   
  21.         SetTimer ( 1, 1000 );  
  22.   
  23.         SetMsgHandled(false);  
  24.   
  25.         return 0;  
  26.   
  27.     }  
  28.   
  29. };  

    CFrameWindowImpl派生于CWindow,故其有SetTimer()函数。设置每1s触发一个计时消息的计时器。同时用SetMsgHandled(false);设置其基类也能处理该消息。这是一个好的习惯。

5)添加WM_DESTORY处理,销毁计时器
MSG_WM_DESTORY宏的定义如下:

[cpp]  view plain copy
  1. #define MSG_WM_DESTROY(func) \  
  2.   
  3.     if (uMsg == WM_DESTROY) \  
  4.   
  5.     { \  
  6.   
  7.         SetMsgHandled(TRUE); \  
  8.   
  9.         func(); \  
  10.   
  11.         lResult = 0; \  
  12.   
  13.         if(IsMsgHandled()) \  
  14.   
  15.             return TRUE; \  
  16.   
  17. }  

         其定义如下:
[cpp]  view plain copy
  1. class CMyWindow : public CFrameWindowImpl<CMyWindow>  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.     BEGIN_MSG_MAP_EX(CMyWindow)  
  8.   
  9.         MSG_WM_CREATE(OnCreate)  
  10.   
  11.         MSG_WM_DESTROY(OnDestroy)  
  12.   
  13.         CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>)  
  14.   
  15.     END_MSG_MAP()  
  16.   
  17.    
  18.   
  19.     void OnDestroy()  
  20.   
  21.     {  
  22.   
  23.         KillTimer(1);  
  24.   
  25.         SetMsgHandled(false);  
  26.   
  27.     }  
  28.   
  29. };  

6)添加WM_TIMER处理,每秒刷新一次窗口
[cpp]  view plain copy
  1. class CMyWindow : public CFrameWindowImpl<CMyWindow>  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.     BEGIN_MSG_MAP_EX(CMyWindow)  
  8.   
  9.         MSG_WM_CREATE(OnCreate)  
  10.   
  11.         MSG_WM_DESTROY(OnDestroy)  
  12.   
  13.         MSG_WM_TIMER(OnTimer)  
  14.   
  15.         CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>)  
  16.   
  17.     END_MSG_MAP()  
  18.   
  19.    
  20.   
  21.     void OnTimer ( UINT uTimerID, TIMERPROC pTimerProc )  
  22.   
  23.     {  
  24.   
  25.         if ( 1 != uTimerID )  
  26.   
  27.             SetMsgHandled(false);  
  28.   
  29.         else  
  30.   
  31.             RedrawWindow();  
  32.   
  33.     }  
  34.   
  35. };  

7)添加WM_ERASEBKGND消息处理,用于刷新背景色,绘制当前时间
[cpp]  view plain copy
  1. class CMyWindow : public CFrameWindowImpl<CMyWindow>  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.     BEGIN_MSG_MAP_EX(CMyWindow)  
  8.   
  9.         MSG_WM_CREATE(OnCreate)  
  10.   
  11.         MSG_WM_DESTROY(OnDestroy)  
  12.   
  13.         MSG_WM_TIMER(OnTimer)  
  14.   
  15.         MSG_WM_ERASEBKGND(OnEraseBkgnd)  
  16.   
  17.         CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>)  
  18.   
  19.     END_MSG_MAP()  
  20.   
  21.    
  22.   
  23.     LRESULT OnEraseBkgnd ( HDC hdc )  
  24.   
  25.     {  
  26.   
  27.        CDCHandle  dc(hdc);  
  28.   
  29.        CRect      rc;  
  30.   
  31.        SYSTEMTIME st;  
  32.   
  33.        CString    sTime;  
  34.   
  35.    
  36.   
  37.         // Get our window's client area.  
  38.   
  39.         GetClientRect ( rc );  
  40.   
  41.    
  42.   
  43.         // Build the string to show in the window.  
  44.   
  45.         GetLocalTime ( &st );  
  46.   
  47.         sTime.Format ( _T("The time is %d:%02d:%02d"),   
  48.   
  49.                        st.wHour, st.wMinute, st.wSecond );  
  50.   
  51.    
  52.   
  53.         // Set up the DC and draw the text.  
  54.   
  55.         dc.SaveDC();  
  56.   
  57.    
  58.   
  59.         dc.SetBkColor ( RGB(255,153,0) );  
  60.   
  61.         dc.SetTextColor ( RGB(0,0,0) );  
  62.   
  63.         dc.ExtTextOut ( 0, 0, ETO_OPAQUE, rc, sTime,   
  64.   
  65.                         sTime.GetLength(), NULL );  
  66.   
  67.    
  68.   
  69.         // Restore the DC.  
  70.   
  71.         dc.RestoreDC(-1);  
  72.   
  73.         return 1;    // We erased the background (ExtTextOut did it)  
  74.   
  75.     }  
  76.   
  77. };  

Generate Codes by AppWizard(VC8)

1)   自动生成了三个类:CMainFrame,CAboutDlg,CxxxView。
2)   自动生成了程序入口函数_tWinMain(),用于初始化COM、普通控件以及_module,然后调用一个全局的Run()。Run()里创建消息循环类CMessageLoop,并且创建窗口。
3)   CMainFrame类:

[cpp]  view plain copy
  1. class CMainFrame : public CFrameWindowImpl<CMainFrame>,  
  2.   
  3.                    public CUpdateUI<CMainFrame>,  
  4.   
  5.                    public CMessageFilter,  
  6.   
  7.                    public CIdleHandler  
  8.   
  9. {  
  10.   
  11. public:  
  12.   
  13.     DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)  
  14.   
  15.    
  16.   
  17.     BEGIN_UPDATE_UI_MAP(CMainFrame)  
  18.   
  19.     END_UPDATE_UI_MAP()  
  20.   
  21.    
  22.   
  23.     BEGIN_MSG_MAP(CMainFrame)  
  24.   
  25.         // ...  
  26.   
  27.         CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)  
  28.   
  29.         CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)  
  30.   
  31.     END_MSG_MAP()  
  32.   
  33.    
  34.   
  35.     BOOL PreTranslateMessage(MSG* pMsg);  
  36.   
  37.     BOOL OnIdle();  
  38.   
  39.    
  40.   
  41. protected:  
  42.   
  43.     CWTLClockView m_view;  
  44.   
  45. };  

CMessageFilter是一个提供PreTranslateMessage()的混合类,CIdleHandler是一个提供OnIdle()的混合类。CMessageLoop, CIdleHandler, 和 CUpdateUI一起提供UI的更新(类似于MFC中ON_UPDATE_COMMAND_UI)。
CMainFrame::OnCreate()创建view窗口,并保存其句柄,以使主窗口大小变化时view窗口能随之变化。同时把CMainFrame对象添加到_module的消息过滤器和idle handler中。
[cpp]  view plain copy
  1. LRESULT CMainFrame::OnCreate(UINT /*uMsg*/WPARAM /*wParam*/,   
  2.   
  3.                              LPARAM /*lParam*/BOOL/*bHandled*/)  
  4.   
  5. {  
  6.   
  7.     m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, |  
  8.   
  9.                                  WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |  
  10.   
  11.                                    WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);  
  12.   
  13.    
  14.   
  15.     // register object for message filtering and idle updates  
  16.   
  17.     CMessageLoop* pLoop = _Module.GetMessageLoop();  
  18.   
  19.     pLoop->AddMessageFilter(this);  
  20.   
  21.     pLoop->AddIdleHandler(this);  
  22.   
  23.    
  24.   
  25.     return 0;  
  26.   
  27. }  

 

CMessageLoop Internals

CMessageLoop提供程序的消息泵。不仅提供TranslateMessage/DispatchMessage,还提供消息过滤PreTranslateMessage()和空闲处理OnIdle()。下面是CMessageLoop::Run()的伪代码:

[cpp]  view plain copy
  1. int Run()  
  2.   
  3. {  
  4.   
  5. MSG msg;  
  6.   
  7.    
  8.   
  9.     for(;;)  
  10.   
  11.         {  
  12.   
  13.         while ( !PeekMessage(&msg) )  
  14.   
  15.             CallIdleHandlers();  
  16.   
  17.    
  18.   
  19.         if ( 0 == GetMessage(&msg) )  
  20.   
  21.             break;    // WM_QUIT retrieved from the queue  
  22.   
  23.    
  24.   
  25.         if ( !CallPreTranslateMessageFilters(&msg) )  
  26.   
  27.             {  
  28.   
  29.             // if we get here, message was not filtered out  
  30.   
  31.             TranslateMessage(&msg);  
  32.   
  33.             DispatchMessage(&msg);  
  34.   
  35.             }  
  36.   
  37.         }  
  38.   
  39.    
  40.   
  41.     return msg.wParam;  
  42.   
  43. }  

通过在窗口对象创建时调用CMessageLoop::AddMessageFilter()和CMessageLoop::AddIdleHandler(),就可以实现消息泵了。
本消息池中不处理TranslateAccelerator() 和 IsDialogMessage()。它们在CFrameWindowImpl中处理。如果要在程序中添加非模式对话框,需要在CMainFrame:: PreTranslateMessage()中调用IsDialogMessage()。

CFrameWindowImpl Internals

CFrameWindowImpl和其基类CFrameWindowImplBase提供了大量的特性,如工具条、状态条、tooltips,toolButton等。
1)WM_SIZE消息。CFrameWindowImplBase的成员m_hWndClient存储Frame的view视图句柄。因此:

[cpp]  view plain copy
  1. LRESULT OnSize(UINT /*uMsg*/WPARAM wParam, LPARAM /*lParam*/BOOL& bHandled)  
  2.   
  3. {  
  4.   
  5.     // 检查是否最小化,如果不是,调用UpdateLayout()  
  6.   
  7.     if(wParam != SIZE_MINIMIZED)  
  8.   
  9.     {  
  10.   
  11.         T* pT = static_cast<T*>(this);  
  12.   
  13.         pT->UpdateLayout();  
  14.   
  15.     }  
  16.   
  17.    
  18.   
  19.     bHandled = FALSE;  
  20.   
  21.     return 1;  
  22.   
  23. }  
  24.   
  25. void UpdateLayout(BOOL bResizeBars = TRUE)  
  26.   
  27. {  
  28.   
  29. RECT rect;  
  30.   
  31.     GetClientRect(&rect);  
  32.   
  33.    
  34.   
  35.     // position bars and offset their dimensions  
  36.   
  37.     UpdateBarsPosition(rect, bResizeBars);  
  38.   
  39.    
  40.   
  41.     // resize client window  
  42.   
  43.     if(m_hWndClient != NULL)  
  44.   
  45.         ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,  
  46.   
  47.             rect.right - rect.left, rect.bottom - rect.top,  
  48.   
  49.             SWP_NOZORDER | SWP_NOACTIVATE);  
  50.   
  51. }  

Back to the Clock Program
[cpp]  view plain copy
  1. class CWTLClockView : public CWindowImpl<CWTLClockView>  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.     DECLARE_WND_CLASS(NULL)  
  8.   
  9.    
  10.   
  11.     BOOL PreTranslateMessage(MSG* pMsg);  
  12.   
  13.    
  14.   
  15.     BEGIN_MSG_MAP_EX(CWTLClockView)  
  16.   
  17.         MESSAGE_HANDLER(WM_PAINT, OnPaint)  
  18.   
  19.         MSG_WM_CREATE(OnCreate)  
  20.   
  21.         MSG_WM_DESTROY(OnDestroy)  
  22.   
  23.         MSG_WM_TIMER(OnTimer)  
  24.   
  25.         MSG_WM_ERASEBKGND(OnEraseBkgnd)  
  26.   
  27.     END_MSG_MAP()  
  28.   
  29. };  

UI Updating

处理UI的更新需要三个类的结合:CMessageLoop,CIdleHandler,CUpdateUI。CUpdateUIBase中存储5个常量对应于5中控件的更新。

  • menu bar items: UPDUI_MENUBAR
  • popup menu items: UPDUI_MENUPOPUP
  • toolbar buttons: UPDUI_TOOLBAR
  • status bar panes: UPDUI_STATUSBAR
  • child windows: UPDUI_CHILDWINDOW

CUpdateUI可以设置控件的enabled state, checked state, and text of items等。
关于UI更新,我们有四件事情要做:
1)   从CUpdateUI和CIdleHandler派生Frame窗口类
2)   从CFrameWindow链接消息到CUpdateUI
3)   添加Frame窗口类到_module的Idle handles的列表中
4)   填充Frame窗口下的UPDATE_UI_MAP宏

New menu items to control the clock

添加两个菜单项 ID_CLOCK_START, ID_CLOCK_STOP,用来控制时钟。

[cpp]  view plain copy
  1. class CMainFrame : public ...  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.     // ...  
  8.   
  9.     BEGIN_UPDATE_UI_MAP(CMainFrame)  
  10.   
  11.         UPDATE_ELEMENT(ID_CLOCK_START, UPDUI_MENUPOPUP)  
  12.   
  13.         UPDATE_ELEMENT(ID_CLOCK_STOP, UPDUI_MENUPOPUP)  
  14.   
  15.     END_UPDATE_UI_MAP()  
  16.   
  17.     // ...  
  18.   
  19. };  

Calling UIEnable()

通过上面的方法,来控制UI的可操作性。

[cpp]  view plain copy
  1. LRESULT CMainFrame::OnCreate(UINT /*uMsg*/WPARAM /*wParam*/,   
  2.   
  3.                              LPARAM /*lParam*/BOOL/*bHandled*/)  
  4.   
  5. {  
  6.   
  7.     m_hWndClient = m_view.Create(...);  
  8.   
  9.    
  10.   
  11.     // register object for message filtering and idle updates  
  12.   
  13.     // [omitted for clarity]  
  14.   
  15.    
  16.   
  17.     // Set the initial state of the Clock menu items:  
  18.   
  19.     UIEnable (ID_CLOCK_START, false );  
  20.   
  21.     UIEnable (ID_CLOCK_STOP, true );  
  22.   
  23.    
  24.   
  25.     return 0;  
  26.   
  27. }  

参考原文

http://download.csdn.net/source/3479570


转自:http://blog.csdn.net/wcyoot/article/details/6644863

你可能感兴趣的:((转)WTL入门(2)-- WTL基础)