WTL入门(2)-- WTL基础 (转)
来源:互联网 发布:大数据与医疗 编辑:程序博客网 时间:2024/06/05 19:30
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添加头文件和定义宏
// stdafx.h#define STRICT#define WIN32_LEAN_AND_MEAN#define _WTL_USE_CSTRING // 如果计划使用WTL封装的CString类,需要定义此宏。// CString是在atlmisc.h中定义的,但是在其他的头文件中可能会用到此类,尤其在atlmisc.h之前被包含的头文件如AtlApp.h// 因此,通过这种方法可以预声明一个CString类,以告诉其他头文件CString是个什么东东 #include <atlbase.h> // base ATL classes#include <atlapp.h> // base WTL classes,包含消息处理和CAppModule的定义(派生于CComModule类)extern CAppModule _Module; // WTL version of CComModule,它包含我们所需要的空闲进程和UI更新等特性#include <atlwin.h> // ATL GUI classes#include <atlframe.h> // WTL frame window classes#include <atlmisc.h> // WTL utility classes like CString#include <atlcrack.h> // WTL enhanced msg map macros
2)定义一个Frame Window,其派生于CFrameWindowImpl。并且用DECLARE_FRAME_WND_CLASS宏定义窗口类。
// MyWindow.h:class CMyWindow : public CFrameWindowImpl<CMyWindow>{public: // 两个参数,前者表示窗口名字,如果为NULL,WTL将自动生成一个 // 后者表示窗口的资源ID。// WTL将会根据此ID搜索图标、菜单、快捷键表等资源,并在窗口创建时加载它们。// 同样也通过此ID搜索一个字符串用于窗口的Title DECLARE_FRAME_WND_CLASS(_T("First WTL window"), IDR_MAINFRAME); BEGIN_MSG_MAP(CMyWindow) // 用这种方法将消息链到其基类中(值得注意的是WM_SIZE和WM_DESTORY)CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>) END_MSG_MAP()}
3)WinMain函数,与上一节相似:
#include "stdafx.h"#include "MyWindow.h" CAppModule _Module; int APIENTRY WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){ _Module.Init ( NULL, hInstance ); CMyWindow wndMain; MSG msg; // Create the main window if ( NULL == wndMain.CreateEx() ) return 1; // Window creation failed // Show the window wndMain.ShowWindow ( nCmdShow ); wndMain.UpdateWindow(); // Standard Win32 message loop while ( GetMessage ( &msg, NULL, 0, 0 ) > 0 ) { TranslateMessage ( &msg ); DispatchMessage ( &msg ); } _Module.Term(); return msg.wParam;}
此时运行程序,将会起动一个空窗口的。
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消息处理
class CMyWindow : public CFrameWindowImpl<CMyWindow>{public:BEGIN_MSG_MAP_EX(CMyWindow) // 用这种方法声明WM_CREATE消息的处理 MSG_WM_CREATE(OnCreate) CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>) END_MSG_MAP() // OnCreate(...) ?}; MSG_WM_CREATE宏的定义如下:#define MSG_WM_CREATE(func) \ if (uMsg == WM_CREATE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \ if(IsMsgHandled()) \ return TRUE; \}
可以看出,消息参数被解包为LPCREATESTRUCT,只有一个参数,返回值为LRESULT对象。同时没有了bHandle参数,通过SetMsgHandled()代替此参数。
class CMyWindow : public CFrameWindowImpl<CMyWindow>{public: BEGIN_MSG_MAP_EX(CMyWindow) MSG_WM_CREATE(OnCreate) CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>) END_MSG_MAP() LRESULT OnCreate(LPCREATESTRUCT lpcs) { SetTimer ( 1, 1000 ); SetMsgHandled(false); return 0; }};
CFrameWindowImpl派生于CWindow,故其有SetTimer()函数。设置每1s触发一个计时消息的计时器。同时用SetMsgHandled(false);设置其基类也能处理该消息。这是一个好的习惯。
5)添加WM_DESTORY处理,销毁计时器
MSG_WM_DESTORY宏的定义如下:
#define MSG_WM_DESTROY(func) \ if (uMsg == WM_DESTROY) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \}
class CMyWindow : public CFrameWindowImpl<CMyWindow>{public: BEGIN_MSG_MAP_EX(CMyWindow) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>) END_MSG_MAP() void OnDestroy() { KillTimer(1); SetMsgHandled(false); }};
class CMyWindow : public CFrameWindowImpl<CMyWindow>{public: BEGIN_MSG_MAP_EX(CMyWindow) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) MSG_WM_TIMER(OnTimer) CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>) END_MSG_MAP() void OnTimer ( UINT uTimerID, TIMERPROC pTimerProc ) { if ( 1 != uTimerID ) SetMsgHandled(false); else RedrawWindow(); }};
class CMyWindow : public CFrameWindowImpl<CMyWindow>{public: BEGIN_MSG_MAP_EX(CMyWindow) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) MSG_WM_TIMER(OnTimer) MSG_WM_ERASEBKGND(OnEraseBkgnd) CHAIN_MSG_MAP(CFrameWindowImpl<CMyWindow>) END_MSG_MAP() LRESULT OnEraseBkgnd ( HDC hdc ) { CDCHandle dc(hdc); CRect rc; SYSTEMTIME st; CString sTime; // Get our window's client area. GetClientRect ( rc ); // Build the string to show in the window. GetLocalTime ( &st ); sTime.Format ( _T("The time is %d:%02d:%02d"), st.wHour, st.wMinute, st.wSecond ); // Set up the DC and draw the text. dc.SaveDC(); dc.SetBkColor ( RGB(255,153,0) ); dc.SetTextColor ( RGB(0,0,0) ); dc.ExtTextOut ( 0, 0, ETO_OPAQUE, rc, sTime, sTime.GetLength(), NULL ); // Restore the DC. dc.RestoreDC(-1); return 1; // We erased the background (ExtTextOut did it) }};
Generate Codes by AppWizard(VC8)
1) 自动生成了三个类:CMainFrame,CAboutDlg,CxxxView。
2) 自动生成了程序入口函数_tWinMain(),用于初始化COM、普通控件以及_module,然后调用一个全局的Run()。Run()里创建消息循环类CMessageLoop,并且创建窗口。
3) CMainFrame类:
class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>, public CMessageFilter, public CIdleHandler{public: DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME) 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() BOOL PreTranslateMessage(MSG* pMsg); BOOL OnIdle(); protected: CWTLClockView m_view;};
CMainFrame::OnCreate()创建view窗口,并保存其句柄,以使主窗口大小变化时view窗口能随之变化。同时把CMainFrame对象添加到_module的消息过滤器和idle handler中。
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;}
CMessageLoop Internals
CMessageLoop提供程序的消息泵。不仅提供TranslateMessage/DispatchMessage,还提供消息过滤PreTranslateMessage()和空闲处理OnIdle()。下面是CMessageLoop::Run()的伪代码:
int Run(){MSG msg; for(;;) { while ( !PeekMessage(&msg) ) CallIdleHandlers(); if ( 0 == GetMessage(&msg) ) break; // WM_QUIT retrieved from the queue if ( !CallPreTranslateMessageFilters(&msg) ) { // if we get here, message was not filtered out TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam;}
本消息池中不处理TranslateAccelerator() 和 IsDialogMessage()。它们在CFrameWindowImpl中处理。如果要在程序中添加非模式对话框,需要在CMainFrame:: PreTranslateMessage()中调用IsDialogMessage()。
CFrameWindowImpl Internals
CFrameWindowImpl和其基类CFrameWindowImplBase提供了大量的特性,如工具条、状态条、tooltips,toolButton等。
1)WM_SIZE消息。CFrameWindowImplBase的成员m_hWndClient存储Frame的view视图句柄。因此:
LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled){ // 检查是否最小化,如果不是,调用UpdateLayout() if(wParam != SIZE_MINIMIZED) { T* pT = static_cast<T*>(this); pT->UpdateLayout(); } bHandled = FALSE; return 1;}void UpdateLayout(BOOL bResizeBars = TRUE){RECT rect; GetClientRect(&rect); // position bars and offset their dimensions UpdateBarsPosition(rect, bResizeBars); // resize client window if(m_hWndClient != NULL) ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);}
class CWTLClockView : public CWindowImpl<CWTLClockView>{public: DECLARE_WND_CLASS(NULL) BOOL PreTranslateMessage(MSG* pMsg); BEGIN_MSG_MAP_EX(CWTLClockView) MESSAGE_HANDLER(WM_PAINT, OnPaint) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) MSG_WM_TIMER(OnTimer) MSG_WM_ERASEBKGND(OnEraseBkgnd) END_MSG_MAP()};
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,用来控制时钟。
class CMainFrame : public ...{public: // ... BEGIN_UPDATE_UI_MAP(CMainFrame) UPDATE_ELEMENT(ID_CLOCK_START, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_CLOCK_STOP, UPDUI_MENUPOPUP) END_UPDATE_UI_MAP() // ...};
Calling UIEnable()
通过上面的方法,来控制UI的可操作性。
LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/){ m_hWndClient = m_view.Create(...); // register object for message filtering and idle updates // [omitted for clarity] // Set the initial state of the Clock menu items: UIEnable (ID_CLOCK_START, false ); UIEnable (ID_CLOCK_STOP, true ); return 0;}
http://download.csdn.net/source/3479570
转自:http://blog.csdn.net/wcyoot/article/details/6644863
- (转)WTL入门(2)-- WTL基础
- WTL入门(2)-- WTL基础
- WTL入门(2)-- WTL基础 (转)
- (转)WTL入门(6)--- ActiveX控件
- WTL学习(2)
- (转)WTL开发者指南(WTL Developer’s Guide翻译)
- 深入剖析WTL—WTL框架窗口分析(2)
- 深入剖析WTL—WTL框架窗口分析 (2)
- 深入剖析WTL—WTL框架窗口分析(2)
- 深入剖析WTL—WTL框架窗口分析 (2)
- 深入剖析WTL—WTL框架窗口分析 (2)
- 深入剖析WTL—WTL框架窗口分析 (2)
- WTL学习笔记——(2)WTL Hello World !
- WTL深度剖析(转)
- WTL入门(1)-- ATL背景知识 (转)
- (转)WTL入门(1)-- ATL背景知识
- (转)WTL入门(3)---工具条和状态条
- (转)WTL入门(4)--- 对话框和控件
- 【转】RoBa's blogProgramming, algorithm, and daily lifeRe: 真的ACM很有用么?
- 返回引用【3】
- [RTT例程练习] 4.1 定时器基本使用
- [操作系统实验] Todolist
- Android源码编译整理总结
- WTL入门(2)-- WTL基础 (转)
- 范型编程与STL 第二章 算法与区间
- Linux系统中添加硬盘,分区与格式化
- 程序员技术练级攻略
- 寻找更新过的数据
- Starling实录-2理解它
- 邮件发送的js和参数的传送
- 11级_Java_曹建波 04.06 Struts2 返回json数据的详细介
- hdu 1176