WTL起步玩转图形界面.docx
- 文档编号:30018207
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:93
- 大小:904.04KB
WTL起步玩转图形界面.docx
《WTL起步玩转图形界面.docx》由会员分享,可在线阅读,更多相关《WTL起步玩转图形界面.docx(93页珍藏版)》请在冰豆网上搜索。
WTL起步玩转图形界面
序言
WTL是2000年1月随Windows的平台SDK始发的。
起初是ATL项目组写的一个基于ATL的,封装了相关win32窗口API的例程。
自ATL2.0开始,ATL就已经有一些简单的相关窗口函数的封装类,例如:
CWindow,CWindowImpl和CDialogImpl。
然而,当我们比较MFC的界面相关部分的功能时,ATL对界面编程的支持简直就是一个玩笑。
甚至到了ATL3.0,ATL仍然没有对诸如MDI,命令条,DDX,打印,GDI等流行功能的支持。
最被人喜爱的MFC的CString也没被支持进来。
没有对这些功能的支持,ATL很难满足拥有压倒性数量的使用MFC的编程人员的需求。
WTL就是ATL项目组认为ATL风格的窗口编程模型应该有的样子。
表1列出了WTL与MFC在界面编程相关功能方面的比较。
特性
MFC
WTL
依赖库
支持
不支持(构建ATL之上)
应用向导支持
支持
支持
类向导支持
支持
不支持(第三方插件VisualFC支持)
微软的公开支持
支持
不支持(微软内部的志愿者支持)
支持OLE文档
支持
不支持
支持视图
支持
支持
支持文档
支持
不支持
基本win32/通用控件封装
支持
支持
高级通用控件封装(平坦滚动条、IP地址控件、页面控件等)
不支持
支持
命令条支持(包含bitmappedcontextmenus)
不支持(MFC提供对话条)
支持
CString
支持
支持
GDI封装
支持
支持
辅助类(CRect,CPoint,等)
支持
支持
Wizards属性页/向导
支持
支持
SDI,MDI支持
支持
支持
多线程SDI支持
不支持
支持
MRU支持
支持
支持
可停靠窗口/条
支持
不支持
分隔窗口
支持
支持
DDX
支持
支持(不是MFC的扩展)
打印/打印预览
支持
支持
滚动视图
支持
支持
客户自画封装
不支持
支持
消息/命令路由
支持
支持
通用对话框
支持
支持
HTML视图
支持
支持
简单实例应用
不支持
不支持
UI更新
支持
支持
基于模板
不支持
支持
带工具条,状态条和菜单的不做任何情事的SDI应用静态链接时大小
超过228KB
(+MSVCRT.DLL(288KB))
24k(带/OPT:
NOWIN98)
(+MSVCRT.DLL如果使用CString)
带工具条,状态条和菜单的不做任何情事的SDI应用动态链接时大小
24KB+MFC42.DLL(972KB)+
MSVCRT.DLL(288KB)
N/A
对运行时库的依赖
CRT(+MFC42.DLL,如果动态链接)
None(如果使用需要CStringCRT)
表1WTL与MFC的比较
当然,WTL不可能(也不愿意)做所有MFC都能做的事儿。
MFC支持经典的OLE,文档/视图框架和可停靠窗口,而WTL没有。
而且还缺乏微软的“官方”支持。
然而,来自于前ATL项目组成员,以及活跃在ATL开发社区的“非官方”支持,可以减轻您对支持方面的担心。
为何ATL开发社区喜欢WTL?
因为这四点:
1>WTL是基于C++模板技术的;
2>应用程序的最小编译代码小于24K;
3>没有任何多如的动态链接库依赖(如果您用CString,会链接CRT);
4>拥有ATL一样的灵活和小巧。
此外,WTL和MFC的界面编程模型非常接近,还包括了从它移植过来的CString。
在我们这本分两部分的书里,我将揭开WTL神秘的面纱。
在第一部分里,我们讨论WTL框架窗口的实现结构。
我们将解释如何编写基于WTL的SDI,MDI和多线程SDI,以及IE浏览器样式的应用程序。
进而,我们讨论WTL的辅助类,包括对DDX的封装。
最后,我们看一下WTL的AppWizard和本书附带的例程。
在本书的第二部分,我们讨论WTL命令条的实现结构,以及对Windows通用控件的封装和一些自定义的用户界面小部件。
我们还将进一步讨论WTL的Windows消息路由结构,包括消息分解,过滤和空闲处理。
我们的WTL之旅没有结束,直到我们讨论完通用对话框,属性页/属性表,打印支持,以及滚动窗口。
所有的这一切我们计划放在第二部分。
在我们告诉你如何用WTL开发程序之前,让我们先复习一下怎样用纯ATL(即不包含WTL)来开发应用程序。
第一部分基础篇
第一章WTL的基础--ATL
ATL提供了一套编写Windows用户界面的C++模板类。
ATL本来的目的是用来支持COM组件和OLE属性页框架的。
这套C++模板类当然成为WTL的基础。
这套类提供了对所有基本的Windows窗口函数的封装,包括窗口/对话框的创建和管理,窗口函数,消息路由,窗口子类化,超类化和消息链。
图1展示了ATL这套C++模板类的层次。
图1:
ATL界面相关类的层次
如果想直接用ATL来创建一个窗口或者对话框,你需要从CWindowImpl或者CDialogImpl派生类。
给你一个具体的例子。
图2提供了一个简单的用前面讲到的这套C++类来开发SDI程序的示意图。
图2简单SDI应用程序
这个例子的应用程序有一个SDI的框架窗口,这个窗口有一个菜单条,状态条和客户区。
它也提供了一个对话框用来演示在ATL里怎样使用对话框。
我们就从vc6创建一个简单win32工程以及添加一些必要的启动ATL的代码来开始这个例子。
图3展示了这个例子的主要源文件的源代码。
stdafx.h:
#if!
defined(AFX_STDAFX_H__DE06DA2F_25B6_41BA_9B20_A17362C38C8C__INCLUDED_)
#defineAFX_STDAFX_H__DE06DA2F_25B6_41BA_9B20_A17362C38C8C__INCLUDED_
#if_MSC_VER>1000
#pragmaonce
#endif//_MSC_VER>1000
#defineSTRICT
#ifndef_WIN32_WINNT
#define_WIN32_WINNT0x0400
#endif
#define_ATL_APARTMENT_THREADED
#include
//如果想重载某些方法,你可以从CComModule类派生一个类
//但是不得改变_Module的名字
externCComModule_Module;
#include
//{{AFX_INSERT_LOCATION}}
//MicrosoftVisualC++将即时从此行之前插入附加声明。
#endif//!
defined(AFX_STDAFX_H__DE06DA2F_25B6_41BA_9B20_A17362C38C8C__INCLUDED)
MainFrame.H
#pragmaonce
#ifndef_MAINFRAME_H_
#define_MAINFRAME_H_
#include"commctrl.H"
classCMainFrame:
publicCWindowImpl WS_CLIPCHILDREN,WS_EX_APPWINDOW|WS_EX_WINDOWEDGE>> { public: CMainFrame(): m_hWndStatusBar(NULL),m_hBmp(NULL) { m_hBmp=LoadBitmap(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDB_ATLWINDOWING)); } ~CMainFrame() { if(m_hBmp) { : : DeleteObject(m_hBmp); m_hBmp=NULL; } } BEGIN_MSG_MAP(CMainFrame) MESSAGE_HANDLER(WM_PAINT,OnPaint) MESSAGE_HANDLER(WM_CREATE,OnCreate) MESSAGE_HANDLER(WM_SIZE,OnSize) MESSAGE_HANDLER(WM_CLOSE,OnClose) COMMAND_ID_HANDLER(ID_FILE_EXIT,OnFileExit) COMMAND_ID_HANDLER(ID_APP_ABOUT,OnAbout) END_MSG_MAP() voidOnFinalMessage(HWND/*hWnd*/){} LRESULTOnCreate(UINT,WPARAMwParam,LPARAMlParam,BOOL&bHandled) { DefWindowProc(); m_hWndStatusBar=: : CreateStatusWindow(WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS| SBARS_SIZEGRIP,_T("Ready"),m_hWnd,1); return0L; } LRESULTOnSize(UINT,WPARAMwParam,LPARAMlParam,BOOL&bHandled) { DefWindowProc(); : : SendMessage(m_hWndStatusBar,WM_SIZE,0,0); return0L; } LRESULTOnPaint(UINT,WPARAM,LPARAM,BOOL&) { PAINTSTRUCTps; HDChdc=BeginPaint(&ps); RECTrect; GetClientRect(&rect); //位图 HDChDCMem=: : CreateCompatibleDC(hdc); HBITMAPhBmpOld=(HBITMAP): : SelectObject(hDCMem,m_hBmp); BITMAPbmp; : : GetObject(m_hBmp,sizeof(BITMAP),&bmp); SIZEsize={bmp.bmWidth,bmp.bmHeight}; : : BitBlt(hdc,rect.left,rect.top,(size.cx),(size.cy),hDCMem,0,0,SRCCOPY); //清除 : : SelectObject(hDCMem,hBmpOld); : : DeleteDC(hDCMem); hDCMem=NULL; EndPaint(&ps); return0; } LRESULTOnClose(UINT,WPARAM,LPARAM,BOOL&) { DestroyWindow(); PostQuitMessage(0); return0L; } LRESULTOnFileExit(WORD,WORDwID,HWND,BOOL&) { SendMessage(WM_CLOSE); return0L; } LRESULTOnAbout(WORD,WORDwID,HWND,BOOL&) { CAboutDialogdlg; dlg.DoModal(); return0L; } private: structCAboutDialog: publicCDialogImpl { enum{IDD=IDD_ABOUT}; BEGIN_MSG_MAP(CAboutDialog) COMMAND_ID_HANDLER(IDOK,OnClose) END_MSG_MAP() LRESULTOnClose(WORD,WORDwID,HWND,BOOL&) { EndDialog(wID); return0L; } }; HWNDm_hWndStatusBar; HBITMAPm_hBmp; }; #endif AtlHelloWindowing.Cpp #include"stdafx.h" #include"resource.h" #include"MainFrame.H" CComModule_Module; extern"C"intWINAPI_tWinMain(HINSTANCEhInstance,HINSTANCE,LPTSTRlpCmdLine,intnShowCmd) { lpCmdLine=GetCommandLine();//该行_ATL_MIN_CRT所必要的 _Module.Init(0,hInstance,NULL); //加载通用控件 INITCOMMONCONTROLSEXiccx; iccx.dwSize=sizeof(iccx); iccx.dwICC=ICC_WIN95_CLASSES|ICC_BAR_CLASSES; : : InitCommonControlsEx(&iccx); HMENUhMenu=LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME)); CMainFramewndFrame; wndFrame.GetWndClassInfo().m_wc.hIcon=: : LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_FORM)); wndFrame.GetWndClassInfo().m_wc.style=0;//CS_HREDRAW|CS_VREDRAW; wndFrame.Create(GetDesktopWindow(),CWindow: : rcDefault,_T("ATLWindowingiscool"),0,0,(UINT)hMenu); wndFrame.ShowWindow(nShowCmd); wndFrame.UpdateWindow(); MSGmsg; while(GetMessage(&msg,0,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } _Module.Term(); return0; } 在MainFrame.h里,CMainFrame有两个数据成员: 状态条的HWND和HBITMAP。 CMainFrame通过通过调用comctl32.dll的CreateStatusWindow()函数,在WM_CREATRE消息处理函数里把状态条创建成一个子窗口,而且通过发送WM_SIZE消息,调整状态条的大小。 WM_PAINT消息的处理函数使用上述的HBITMAP演示了一点ATL里的GDI编程。 由于ATL对GDI没有提供包装类,所以这里的GDI编程是直接调用Win32的API来完成的。 然而MESSAGE_HANDLER宏需要你做你自己的消息分解,ATL通过一系列的宏为你分解了WM_COMMAND和WM_NOTIFY消息。 MainFrame.h展示了如何使用COMMAND_ID_HANDLER宏,CMainFrame用这个宏来处理它的菜单命令。 最后,CAboutDialog是一个对话框类,继承自CDialogImpl类。 OnAbout命令处理函数调用了DoModal用来显示这个对话框。 HelloAtlWindowing.cpp里有个_tWinMain,这是ATL程序的入口函数,它创建了一个CMainFrame的实例,而后调用该实例的Create()函数,以及ShowWindow()和UpdateWindow()这些成员函数,这些成员函数很明显是与他们名字相似的win32API的封装。 最后,因为这个程序从根本上来说,是一个Win32窗口程序,我们必须从窗口的消息队列里通过GetMessage、DispatchMessage循环来抽出消息。 如果你熟悉win32API编程的话,你会注意到这个程序缺少RegisterClass()的调用和处理窗口消息的窗口过程,其他的部分你都能理解。 如果你熟悉MFC,你可能奇怪ATL没有提供那些最基本的支持,比如创建状态条和菜单。 好吧,程序既然能运行,事实证明ATL肯定支持了。 不过ATL并没有做足这方面的支持。 我们不要忘记ATL的主要目的(ATL主要目的是支持COM编程)。 ATL允许你,但是并没有直接支持MDI,多线程SDI,或IE浏览器样式的应用程序,也没有封装通用控件,DDX,和GDI相关函数。 如果你对这些感兴趣,那么我们就进入WTL的世界。 第二章WTL之路 WTL类使得我们更加容易地创建SDI框架窗口成为可能,这个类就是CFrameWindowImpl。 图3WTL的SDI窗口层次关系 类CFrameWindowImpl从类CFrameWindowImplBase派生,因此继承了标准应用程序框架窗口的所有功能。 下面列出了一个WTL创建的框架窗口提供和支持的特性: 1)集合了工具条,菜单条,状态条和Rebar条; 2)基本视图处理,包括视图与框架同步大小,Rebar带维护(包括添加或调整带的大小); 3)命令条菜单; 4)键盘快捷键; 5)工具条按钮的工具提示; 6)在状态条显示帮助字符串; 7)显示框架图标。 为了创建一个SDI应用,步骤如下: 1)从类CFrameWindowImpl派生你的框架类; 2)添加WTL的宏DECLARE_FRAME_WND_CLASS,指定工具条和菜单的资源ID; 3)添加消息映射和消息响应处理,需要包含链入框架基类的链路。 例子: classCMainFrame: publicCFrameWindowImpl { 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 END_MSG_MAP() LRESULTOnCreate(UINT,WPARAM,LPARAM,BOOL&) { CreateSimpleToolBar();//创建工具条并设置为CFrameWindowImplBase: : m_hWndToolBar成员 CreateSimpleStatusBar();//并创建状态条 return0; } LRESULTOnFileExit(WORD,WORDwID,HWND,BOOL&) { SendMessage(WM_CLOSE);//框架知道PostQuitMessage return0L; } … }; 宏DECLARE_FRAME_WND_CLASS为框架设置通用资源ID。 相同资源ID可以用在字符串表中用来作为框架标题,菜单资源,快捷键表,图标和工具条资源等。 如果WTL在创建框架窗口时,用通用资源ID找到了资源,就自动加载。 唯一的例外是工具条资源,你需要使用成员函数CreateSimpleToolBar()来手工加载。 状态条不需要通用资源。 在消息映射中,使用宏CHAIN_MSG_MAP来路由消息给类CFrameWindowImpl,小心处理像WM_SIZE(重置工具条和状态条的大小)和WM_DESTROY(调用PostQuitMessage)之类的消息。 为了支持WTL的功能,你需要在stdafx.h中包含atlapp.h和atlframe.h: #defineWIN32_LEAN_AND_MEAN #include #include externCAppModule_Module; #include #include 头文件atlapp.h定义了CAppModule结构,它是从标准ATL的CComModule类派生,并添加有消息循环的变量。 头文件atlframe.h定义CFrameWindowImpl类。 为了在我们WTL世界中创建SDI窗口,你需要实例化CMainFrame对象,并在winMain()调用基类的成员函数CreateEx()。 CAppModule_Module; intAPIENTRYWinMain(…) { : : InitCommonControls(); _Module.Init(NULL,hInstance); CMainFramewndMain; wndMain.CreateEx(); wndMain.ShowWindow(nCmdShow); wndMain.UpdateWindow(); CMessageLooptheLoop; _Module.AddMessageLoop(&theLoop); intnRet=theLoop.Run(); _Module.RemoveMessageLoop(); _Module.Term(); returnnRet; } CreateEx()成员函数调用基类的CWindowImpl: : Create()成员函数,并使用通用资源ID来加载资源。 CMessageLoop对象代替我们需要的手工消息队列。 ATL允许每个线程有一个消息队列,这就是多线程SDI的实现。 当我们学习WTL的消息路由框架时,我们将第二部分分析CMessageLoop类和CAppModule类的细节。 就这样,我们的SDI应用看起来就如图4所示: 图4使用WTL创建的SDI应用 我们设法简化了我们的代码,并添加了一个新的特性: 工具条。 当然,工具条和菜单条是老的风格。 用户更喜欢命令条,就像他们在IE和MSOffice中所看到的那
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- WTL 起步 图形界面