第九章 GDI 封装类
无论你的应用程序有多少个视图, 无论你如何管理这些视图, 你总是会在一些视图上做些绘画. WTL 对所有 Win32 GDI 资源对象进行了简单的封装, 如 Table2 所示.
Table 2: WTL Wrappers for Win32 GDI Objects
HDC CDCT
HPEN CPenT
HBRUSH CBrushT
HFONT CFontT
HBITMAP CBitmapT
HRGN CRgnT
HPALETTE CPalletT
事实上, 对每个 GDI 资源的封装类都有两种版本:托管的(managed)和非托管的(unmanaged). 托管类负责自动销毁其所拥有的 GDI 资源对象, 而非托管类则把销毁 GDI 资源对象的任务交个程序员来完成. 例如, CFontT 类是 HFONT 资源对象的封装类, 并且它有一个 Boolean 型模版参数指定它是托管的还是非托管的. 这种做法提供了很大的灵活性.
( 译者注:在此托管类与非托管类的概念有别于C#托管代码的概念 )
//atlgdi.h
typedef CFontT<false> CFontHandle;
typedef CFontT<true> CFont;
template <bool t_bManaged>
class CFontT
{
public:
// Data members
HFONT m_hFont;
// Constructor/destructor/operators
CFontT(HFONT hFont = NULL) : m_hFont(hFont)
{ }
~CFontT()
{
if(t_bManaged && m_hFont != NULL)
DeleteObject();
}
CFontT<t_bManaged>& operator=(HFONT hFont)
{
m_hFont = hFont;
return *this;
}
…
};
我们注意到 CFontT 的析构函数在调用成员函数 DeleteObject 释放 GDI 资源之前检查模版参数 t_bManaged 确定是一个托管类. 两个版本的最终类型为 CFontHandle CFont, 分别是托管类和非托管类. 对其它 GDI 的封装类都是相似的.
typedef CFontT<false> CFontHandle; typedef CFontT<true> CFont;
其中最庞大的封装类, 必然是 CDCT, 封装了超过240个成员方法涵盖了 GDI 和 WGL 相关函数, 称为冠军它当之无愧. 从它派生了四个托管版本的 WTL 类:CPaintDC, CWindowDC, CClientDC, CEnhMetaFileDC. CPaintDC 类封装了 PAINTSTRUCT 结构并使用 BeginPaint/EndPaint 函数对获取/释放 DC. CClientDC 类针对窗口客户区, 并使用 GetWindowDC/ReleaseDC 获取/释放 整个窗口的 DC 资源. 最后, CEnhMetaFileDC 类封装了 HENHMETAFILE 结构并调用 CreateEnhMetaFile 和 DeleteEnhMetaFile 创建和销毁 Windows 元数据文件(meta file). 下面的 CPaintDC 类的定义显示了这几个类的工作方式.
//atlgdi.h
class CPaintDC : public CDC
{
public:
HWND m_hWnd;
PAINTSTRUCT m_ps;
CPaintDC(HWND hWnd)
{
m_hWnd = hWnd;
m_hDC = ::BeginPaint(hWnd, &m_ps);
}
~CPaintDC()
{
::EndPaint(m_hWnd, &m_ps);
Detach();
}
};
使用托管 GDI 封装类可以简化原生的 GDI 代码. 例如, 我们的位图视图类可以简化成如下形式:
class CBitmapView : public CWindowImpl<CBitmapView>
{
public:
CBitmapView()
{
m_bmp.LoadBitmap(MAKEINTRESOURCE(IDB_ATLWINDOWING));
}
BEGIN_MSG_MAP(CBitmapView)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
END_MSG_MAP()
LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&)
{
CPaintDC dc(m_hWnd);
RECT rect; GetClientRect(&rect);
CDC dcMem; dcMem.CreateCompatibleDC(dc);
CBitmap bmpOld = dcMem.SelectBitmap(m_bmp);
BITMAP bm; m_bmp.GetBitmap(&bm);
SIZE size = { bm.bmWidth, bm.bmHeight };
dc.BitBlt(rect.left, rect.top, size.cx, size.cy, dcMem,
0, 0, SRCCOPY);
// Cleanup
dcMem.SelectBitmap(bmpOld);
return 0;
}
private:
CBitmap m_bmp;
};
为了获取 GDI 绘图的更多支持, WTL 提供了一些辅助类, 它们都以 Atl 为前缀. 包括 AtlGetStockBrush, AtlGetStockFont, AtlGetStockPalette, AtlGetStockPen, AtlLoadAccelerators, AtlLoadBitmap, AtlLoadBitmapImage, AtlLoadCursor, AtlLoadString 等等.
WTL Helper Classes
To be continued...