ATLWTL第九部分.docx
- 文档编号:6307338
- 上传时间:2023-01-05
- 格式:DOCX
- 页数:27
- 大小:109.73KB
ATLWTL第九部分.docx
《ATLWTL第九部分.docx》由会员分享,可在线阅读,更多相关《ATLWTL第九部分.docx(27页珍藏版)》请在冰豆网上搜索。
ATLWTL第九部分
第九部分-GDI类,公用对话框以及工具类
∙下载示例工程-157KB
内容
∙简介
∙GDI封装类
∙封装类里的公用函数
∙使用CDCT
∙与MFC封装类的差异
∙资源加载函数
∙使用公用对话框
∙CFileDialog
∙CFolderDialog
∙其他有用的类和全局函数
∙Struct的封装
∙处理双类型参数的类
∙其他工具类
∙全局函数
∙宏
∙示例工程
∙版权和许可
∙修订历史
简介
WTL里包含了好多封装类和工具类,而直到现在也还没有在本系列里进行过全面的介绍,比如说 CString 和 CDC。
WTL具有一个封装GDI对象的良好体系,一些用以加载资源的便利函数,以及更便于使用某些Win32公用对话框的类。
在此第九部分里,我将介绍一些使用最广泛的类。
本文讨论了四类特性:
1.GDI封装类
2.资源加载函数
3.使用打开文件公用对话框以及文件夹选择公用对话框
4.其他有用的类以及全局函数
GDI封装类
相较于MFC,WTL为其GDI封装类使用了一种相当不同的方法。
WTL的方法是,为每种类型的GDI对象准备一个模板类,每个模板都有一个名为 t_bManaged的 bool 参数。
此参数控制着该类的实例是否“管理”着(或者说是拥有)被封装的GDI对象。
如果 t_bManaged 为 false,则C++对象不会管理GDI对象的生命期,C++对象仅是围绕GDI对象句柄的一个简单封装层。
如果 t_bManaged 为 true,则有两件事情会改变:
1.析构函数会对所封装的非空句柄调用 DeleteObject()。
2.Attach() 在将C++对象关联到新的句柄之前,也会对所封装的非空句柄调用 DeleteObject()。
此设计与ATL窗口类的设计是一致的,CWindow 是对 HWND 的一个简单的封装层,而 CWindowImpl 管理了一个窗口的生命期。
GDI封装类定义于 atlgdi.h 中,不过 CMenuT 是个例外,它定义于 atluser.h 中(译者注:
此处作者的说法欠妥,菜单在Windows里原本就是属于USER32的,而不是GDI32)。
你自己不必包含这些头文件,因为 atlapp.h 总会为你包含它们。
每个类还有一个易于记忆的typedef名字:
封装的GDI对象
模板类
管理对象的typedef名
普通封装的typedef名
Pen
CPenT
CPen
CPenHandle
Brush
CBrushT
CBrush
CBrushHandle
Font
CFontT
CFont
CFontHandle
Bitmap
CBitmapT
CBitmap
CBitmapHandle
Palette
CPaletteT
CPalette
CPaletteHandle
Region
CRgnT
CRgn
CRgnHandle
Devicecontext
CDCT
CDC
CDCHandle
Menu
CMenuT
CMenu
CMenuHandle
与MFC传递对象指针相比较,我更喜欢这种方法。
你永远也不必担心收到了一个NULL指针(封装的句柄可能会是NULL,但那是另一回事),也不会有这种特殊的情况,你有一个临时对象,但你却不能把它保存下来然后对它进行不止一次的函数调用。
创建这些类的实例代价也是很低的,因为它们只有一个成员变量,即所封装的句柄。
就像 CWindow 一样,在线程之间传递封装类的对象也不会有问题,因为WTL并没有像MFC那样的线程相关的映射。
另外还有几个设备上下文的封装类,用于特定的绘制场景:
∙CClientDC:
封装了对 GetDC() 和 ReleaseDC() 的调用,用于在窗口的客户区内绘制
∙CWindowDC:
封装了对 GetWindowDC() 和 ReleaseDC() 的调用,用于在窗口内的任意地方绘制
∙CPaintDC:
封装了对 BeginPaint() 和 EndPaint() 的调用,用于 WM_PAINT 处理器中
这些类中的任一个都是在构造函数中接受一个 HWND,而行为与其在MFC中的同名类相似。
所有这三个类都派生于 CDC,因此它们都管理着自己的设备上下文。
封装类里的公用函数
GDI封装类都遵循相同的设计。
简明起见,在这儿我只介绍 CBitmapT 里的方法,但其它类工作起来都很相似。
封装的GDI对象句柄
每个类都持有一个公用成员变量,其中保留了此C++对象关联着的GDI对象的句柄。
CBitmapT 则具有一个名为 m_hBitmap 的 HBITMAP 成员。
构造函数
构造函数有一个参数,为一个 HBITMAP,其缺省值为NULL。
m_hBitmap 被初始化为此参数的值。
析构函数
如果 t_bManaged 为true,而且 m_hBitmap 不是NULL,则析构函数会调用 DeleteObject() 以销毁位图。
Attach() 和 operator =
这两个方法都接受一个 HBITMAP 句柄。
如果 t_bManaged 为 true,而且 m_hBitmap 不是NULL,这些方法会先调用 DeleteObject() 以销毁 CBitmapT 对象管理着的位图,然后将 m_hBitmap 设置为作为参数传入的 HBITMAP。
Detach()
Detach() 会将 m_hBitmap 设置为NULL,然后再返回原来在 m_hBitmap 中的值。
当 Detach() 返回后,CBitmapT 对象就不再与任何GDI有关联了。
创建GDI对象的方法
CBitmapT 对Win32中创建位图的API也有封装:
LoadBitmap()、LoadMappedBitmap()、CreateBitmap()、CreateBitmapIndirect()、CreateCompatibleBitmap()、CreateDiscardableBitmap()、CreateDIBitmap()以及 CreateDIBSection()。
如果 m_hBitmap 不是NULL时,这些方法都会产生断言。
如果要为另一个GDI位图重用本 CBitmapT 对象,就要先调用DeleteObject() 或者 Detach()。
DeleteObject()
DeleteObject() 销毁GDI位图对象并将 m_hBitmap 置为NULL。
这一方法仅当 m_hBitmap 不为NULL时才应该调用,否则会产生断言。
IsNull()
IsNull() 在 m_hBitmap 为NULL时返回 true,否则返回 false。
这一方法用来测试 CBitmapT 对象当前是否关联着一个GDI位图。
operator HBITMAP
这个转换器会返回 m_hBitmap,这就使你可以把 CBitmapT 对象传递给一个接收 HBITMAP 句柄的函数或者Win32API。
这个转换器在以下情况下也会被调用,或者是一个 CBitmapT 在布尔值的上下文环境下被求值,或者是对 IsNull() 的逻辑取反求值。
因而,这两个if语句是等效的:
CBitmapHandlebmp=/*someHBITMAPvalue*/;
if(!
bmp.IsNull()){dosomething...}
if(bmp){dosomethingmore...}
GetObject() 的封装
CBitmapT 具有一个对于Win32API GetObject()的类型安全的封装:
GetBitmap()。
有两个重载形态:
一个是接收 LOGBITMAP* 参数而直接调用 GetObject(),另一个则接收 LOGBITMAP& 参数并返回一个表示成功与否的 bool 值。
后者更为易用些。
例如:
CBitmapHandlebmp2=/*someHBITMAPvalue*/;
LOGBITMAPlogbmp={0};
boolbSuccess;
if(bmp2)
bSuccess=bmp2.GetLogBitmap(logbmp);
操作GDI对象的API的封装
CBitmapT 对接收 HBITMAP 参数的Win32API也进行了封装:
GetBitmapBits()、SetBitmapBits()、GetBitmapDimension()、SetBitmapDimension()、GetDIBits()以及 SetDIBits()。
这些方法在 m_hBitmap 为NULL时都会产生断言。
其它辅助方法
CBitmapT 还有两个作用于 m_hBitmap 上的有用的方法:
LoadOEMBitmap() 和 GetSize()。
使用CDCT
CDCT 与其它类有一点不同,因此我要单独介绍其差别。
方法上的差别
销毁一个DC的方法叫做 DeleteDC() 而不是 DeleteObject()。
将对象选入DC
MFC的 CDC 在把对象选入到其中时有一个容易导致错误的地方。
MFC的 CDC 有若干个重载的 SelectObject() 函数,每个都是接收一个指向不同类型的GDI封装类的指针(CPen*,CBitmap*,等等)作为参数。
如果你把一个C++对象而不是指向该对象的指针传递给 SelectObject(),代码最终会调用一个未文档化的,接收一个 HGDIOBJ 句柄为参数的重载,这样就会导致问题。
WTL的 CDCT 使用了一种更好的方法,它有好几个选择函数,每一个都只作于特定类型的GDI对象:
HPENSelectPen(HPENhPen)
HBRUSHSelectBrush(HBRUSHhBrush)
HFONTSelectFont(HFONThFont)
HBITMAPSelectBitmap(HBITMAPhBitmap)
intSelectRgn(HRGNhRgn)
HPALETTESelectPalette(HPALETTEhPalette,BOOLbForceBackground)
在调试模式的构建中,每个方法都会断言 m_hDC 为非NULL值,而且参数是恰当类型的GDI对象的句柄。
然后再调用 SelectObject() API,并将其返回值转型为合适的类型。
还存在着几个辅助函数,它们先用给定的常量调用 GetStockObject(),然后再把对象选入到DC:
HPENSelectStockPen(intnPen)
HBRUSHSelectStockBrush(intnBrush)
HFONTSelectStockFont(intnFont)
HPALETTESelectStockPalette(intnPalette,BOOLbForceBackground)
与MFC封装类的区别
较少的构造函数:
WTL的封装类缺少可以创建新的GDI对象的构造函数。
比如,MFC的 CBrush 有一个构造函数可以创建一个实心画刷或者模式(patterne)画刷。
而使用WTL的类,你必须使用某个方法来创建该GDI对象。
用更好的方法把对象选入DC:
参看上面使用CDCT 节
没有 m_hAttribDC:
WTL的 CDCT 没有 m_hAttribDC 成员
一些方法里有少许的参数差异:
例如,CDC:
:
GetWindowExt() 在MFC里返回一个 CSize 对象,而在WTL里返回一个 bool,而大小通过输出参数来返回。
资源加载函数
WTL里的若干个全局函数是极具帮助的加载不同类型的资源的捷径。
在接触这些函数之前,我们需要了解一个工具类:
_U_STRINGorID。
在Win32中,大多数资源可以用一个字符串(LPCTSTR)或者一个无符号整数(UINT)来标识。
接收资源标识符的API需要接收一个 LPCTSTR 参数,如果要传递一个 UINT 的话,你需要使用 MAKEINTRESOURCE 宏来将之转换为一个 LPCTSTR。
_U_STRINGorID,当作为资源标识符参数类型来使用的时候,会隐藏这一不同,因而调用者就可以直接传递 UINT 或者 LPCTSTR。
如果需要的话,函数可以使用一个 CString 来加载字符串:
voidsomefunc(_U_STRINGorIDid)
{
CStringstr(id.m_lpstr);
//usestr...
}
voidfunc2()
{
//Call1-usingastringliteral
somefunc(_T("WillowRosenberg"));
//Call2-usingastringresourceID
somefunc(IDS_BUFFY_SUMMERS);
}
这能够工作的原因是,CString 接收 LPCTSTR 的构造函数会检查参数是否是一个字符串ID。
如果是的话,就会从字符串表中加载该字符串并赋予该 CString。
在VC6里,_U_STRINGorID 由WTL在 atlwinx.h 中提供;在VC7里,_U_STRINGorID 是ATL的一部分。
无论哪种,这个类的定义总会被其他的ATL/WTL头文件包含进来。
此节中的函数都是从保存在 _Module 全局变量(VC6)或者 _AtlBaseModule (VC7)中的资源实例句柄加载资源。
使用其他模块的资源超出了本文的范围,因此我在这儿不会提及。
只需要记住,缺省情况下,这些函数总是在代码正运行于其中的EXE或者DLL中寻找。
这些函数并没有比调用API多做什么,它们的作用在于由 _U_STRINGorID 所提供的资源标识符的处理简化上。
HACCELAtlLoadAccelerators(_U_STRINGorIDtable)
调用流向 LoadAccelerators()。
HMENUAtlLoadMenu(_U_STRINGorIDmenu)
调用流向 LoadMenu()。
HBITMAPAtlLoadBitmap(_U_STRINGorIDbitmap)
调用流向 LoadBitmap()。
HCURSORAtlLoadCursor(_U_STRINGorIDcursor)
调用流向 LoadCursor()。
HICONAtlLoadIcon(_U_STRINGorIDicon)
调用流向 LoadIcon()。
注意一下这个函数,和 LoadIcon() 一样,仅可以加载32x32图标。
intAtlLoadString(UINTuID,LPTSTRlpBuffer,intnBufferMax)
boolAtlLoadString(UINTuID,BSTR&bstrText)
调用流向 LoadString()。
字符串可以返回至一个 TCHAR 缓冲区,或者是赋与一个 BSTR,取决于你使用哪一个重载。
注意这两个函数仅接收 UINT 作为其资源ID,因为字符串表项不能有字符串标识符。
下面这组函数封装了对 LoadImage() 的调用,而且还接受传递给 LoadImage() 的附加参数。
HBITMAPAtlLoadBitmapImage(
_U_STRINGorIDbitmap,UINTfuLoad=LR_DEFAULTCOLOR)
使用 IMAGE_BITMAP 类型调用 LoadImage(),并将 fuLoad 标志传入。
HCURSORAtlLoadCursorImage(
_U_STRINGorIDcursor,
UINTfuLoad=LR_DEFAULTCOLOR|LR_DEFAULTSIZE,
intcxDesired=0,intcyDesired=0)
使用 IMAGE_CURSOR 类型调用 LoadImage(),并将 fuLoad 标志传入。
由于一个光标资源可以包含若干个不同尺寸的光标,因而你可以把尺寸传递给cxDesired 和 cyDesired 参数以加载一个特定大小的光标。
HICONAtlLoadIconImage(
_U_STRINGorIDicon,
UINTfuLoad=LR_DEFAULTCOLOR|LR_DEFAULTSIZE,
intcxDesired=0,intcyDesired=0)
使用 IMAGE_ICON 类型调用 LoadImage(),并将 fuLoad 标志传入。
cxDesired 和 cyDesired 参数的用法同 AtlLoadCursorImage()。
下面这一组函数封装了加载系统定义的资源(例如,标准的手状光标)的调用。
其中的一些资源ID(主要是位图的那些)缺省是不被包含的,需要在你的stdafx.h 文件中 #define OEMRESOURCE 符号来引用它们。
HBITMAPAtlLoadSysBitmap(LPCTSTRlpBitmapName)
使用NULL资源句柄调用 LoadBitmap()。
使用此函数可以加载任何在 LoadBitmap() 的文档中列出的 OBM_* 位图。
HCURSORAtlLoadSysCursor(LPCTSTRlpCursorName)
使用NULL资源句柄调用 LoadCursor()。
使用此函数可以加载任何在 LoadCursor() 的文档中列出的 IDC_* 光标。
HICONAtlLoadSysIcon(LPCTSTRlpIconName)
使用NULL资源句柄调用 LoadIcon()。
使用此函数可以加载任何在 LoadIcon() 的文档中列出的 IDI_* 图标。
不过要注意此函数——就像LoadIcon() ——只能加载32x32的图标。
HBITMAPAtlLoadSysBitmapImage(
WORDwBitmapID,UINTfuLoad=LR_DEFAULTCOLOR)
使用NULL资源句柄以及 IMAGE_BITMAP 类型调用 LoadImage()。
你可以使用此函数来加载与 AtlLoadSysBitmap() 相同的位图。
HCURSORAtlLoadSysCursorImage(
_U_STRINGorIDcursor,
UINTfuLoad=LR_DEFAULTCOLOR|LR_DEFAULTSIZE,
intcxDesired=0,intcyDesired=0)
使用NULL资源句柄以及 IMAGE_CURSOR 类型调用 LoadImage()。
你可以使用此函数来加载与 AtlLoadSysCursor() 相同的光标。
HICONAtlLoadSysIconImage(
_U_STRINGorIDicon,
UINTfuLoad=LR_DEFAULTCOLOR|LR_DEFAULTSIZE,
intcxDesired=0,intcyDesired=0)
使用NULL资源句柄以及 IMAGE_ICON 类型调用 LoadImage()。
你可以使用此函数来加载与 AtlLoadSysIcon() 相同的图标,不过可以指定一个不同的尺寸,例如16x16。
最后的这组函数是对 GetStockObject() API的类型安全的封装。
HPENAtlGetStockPen(intnPen)
HBRUSHAtlGetStockBrush(intnBrush)
HFONTAtlGetStockFont(intnFont)
HPALETTEAtlGetStockPalette(intnPalette)
每个函数都会检查你是不是传入了恰当的值(比方说,AtlGetStockPen() 只接受 WHITE_PEN,BLACK_PEN 等值),然后再调用 GetStockObject()。
使用公用对话框
WTL还有些类,可以使Win32的公用对话框使用起来更容易些。
每个类都会处理公用对话框发送的消息以及回调,并依次调用那些可覆盖的函数。
这和用于属性表的设计是一样的,只不过在那儿你是为各个被 CPropertyPageImpl 在必要时调用的属性表通知编写处理器,例如 OnWizardNext(),用来处理 PSN_WIZNEXT。
WTL为每种公用对话框都包含了两个类,例如,选择文件夹对话框由 CFolderDialogImpl 和 CFolderDialog 封装。
如果需要改变缺省行为,或者是要为某个消息编写处理器,你可以从 CFolderDialogImpl 派生一个新类并在其中作改动。
如果 CFolderDialogImpl 的缺省行为已经足够了,则你可以使用 CFolderDialog。
公用对话框及其相应的WTL类有:
公用对话框
相应的Win32API
实现类
不可定制类
文件打开和文件保存
GetOpenFileName(),
GetSaveFileName()
CFileDialogImpl
CFileDialog
选择文件夹
SHBrowseForFolder()
CFolderDialogImpl
CFolderDialog
选择字体
ChooseFont()
CFontDialogImpl,
CRichEditFontDialogImpl
CFontDialog,
CRichEditFontDialog
选择颜色
ChooseColor()
CColorDialogImpl
CColorDialog
打印及打印设置
PrintDlg()
CPrintDialogImpl
CPrintDialog
打印(Windows2000及之后)
PrintDlgEx()
CPrintDialogExImpl
CPrintDialogEx
页面设置
PageSetupDlg()
CPageSetupDialogImpl
CPageSetupDialog
文本查找及替换
FindText(),
ReplaceText()
CFindReplaceDialogImpl
CFindReplaceDialog
把这些类全写出来将会使本文相当的长,因此我只选择了前两个,也正是你在使用中经常用到的两个。
CFileDialog
CFileDialog 及其基类 CFileDialogImpl 用于显示文件打开和文件保存对话框。
在 CFileDialogImpl 中最重要的两个数据成员是 m_ofn 和 m_szFileName。
m_ofn 是一个OPENFILENAME
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ATLWTL 第九 部分
![提示](https://static.bdocx.com/images/bang_tan.gif)