WTL的内存DC






4.17/5 (5投票s)
2002年3月11日
3分钟阅读

117350

2159
一篇详细介绍 WTL 简单基于内存的设备上下文的文章,用于需要无闪烁双缓冲绘图的情况
摘要
WTL 内存设备上下文的简单实现。
目标
ATL 和 WTL 缺少其他库和框架中存在的一些高级绘图工具。本文和随附的源代码提供了一种此类高级工具:内存设备上下文。
讨论
开发人员很快就会了解到,直接在窗口的客户端区域上绘图会导致闪烁。大多数专业的应用程序都使用一种称为“双缓冲绘图”的技术。所有绘图操作都在用户不可见的平面上执行。当场景已在隐藏平面上完全渲染后,其内容将一次性复制到用户可见的平面。
WTL 目前不支持双缓冲绘图。但是,它非常容易实现。头文件“AtlGdi.h”包含一个实现 Windows 设备上下文的类。有几个 CDC
对象的子类可用于各种情况。但是,WTL 中不包含“内存设备上下文”。本文档介绍了如何使用 Win32 SDK 执行双缓冲,并演示了基于 CDC 类的 WTL 实现。
使用 SDK 进行双缓冲
虽然没有必要了解如何在 SDK 中执行双缓冲,但了解它如何与本文描述的 CMemDC
相关是很有意义的。
虽然内存 DC 的初始化代码可以位于它将使用的窗口的 WM_CREATE
消息处理程序中,但这在子类化现有窗口时不起作用。这是因为窗口必须在子类化之前创建,因此子类永远看不到 WM_CREATE
消息。因此,通常希望将该代码添加到 WM_PAINT
消息处理程序,并检查是否已经发生初始化。创建和使用内存 DC 的示例
int WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
static HDC hMemDC = 0;
static HBITMAP hBitmap = 0;
int width, height;
HDC hDC;
PAINTSTRUCT ps;
switch( msg )
{
case WM_PAINT:
{
/* Initialize the memory DC */
if( ! hMemDC )
{
width = GetSystemMetrics( SM_CXSCREEN );
height = GetSystemMetrics( SM_CYSCREEN );
hDC = GetDC( hWnd );
hMemDC = CreateCompatibleDC( hDC );
hBitmap = CreateCompatibleBitmap( hDC, width, height );
SelectBitmap( hMemDC, hBitmap );
ReleaseDC( hWnd, hDC );
}
/* Do all painting using hMemDC */
...
/* Display the memory DC */
BeginPaint( hWnd, &ps );
BitBlt( ps.hdc,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top,
hMemDC,
ps.rcPaint.left,
ps.rcPaint.top,
SRCCOPY );
EndPaint( hWnd, &ps );
}
case WM_DESTROY:
{
DeleteDC( hMemDC );
PostQuitMessage( 0 );
}
}
}
使用 WTL 进行双缓冲
本文提供的类实际上使用了相同的代码,但基于 WTL CDC
类。应用程序中的 WM_PAINT
处理程序使用窗口句柄作为参数创建 CMemDC
的实例
void OnPaint( HDC )
{
if( ! m_memDC )
{
m_memDC = new CMemDC( *this );
}
...
}
CMemDC
构造函数在内部创建内存 DC 和位图
CMemDC( HWND hWnd )
: CDC( )
, m_bitmap( 0 )
, m_hWnd( 0 )
{
ATLASSERT( hWnd );
m_hWnd = hWnd;
int width = ::GetSystemMetrics( SM_CXSCREEN );
int height = ::GetSystemMetrics( SM_CYSCREEN );
CClientDC dc( hWnd );
CreateCompatibleDC( dc );
m_bitmap.CreateCompatibleBitmap( dc, width, height );
SelectBitmap( m_bitmap );
}
应用程序只需要引用内存 DC 对象,而不是在 WM_PAINT
处理程序中创建 CPaintDC
void OnPaint( HDC )
{
...
RECT cRect;
GetClientRect( &cRect );
m_memDC->FillSolidRect( &cRect, GetSysColor( COLOR_BTNFACE ) );
m_memDC->DrawEdge( &cRect, EDGE_ETCHED, BF_ADJUST | BF_RECT );
m_memDC->DrawText( _T( "I'm custom drawn."), 17, &cRect,
DT_CENTER | DT_SINGLELINE | DT_VCENTER );
...
}
然后,当不可见的内存 DC 已完全绘制后,只需调用其 Paint
函数即可将其内容复制到可见窗口
void OnPaint( HDC )
{
...
m_memDC->Paint( );
}
还提供了一个 Repaint
函数,可用于在处理其他消息时刷新可见窗口。
结论
虽然内存设备上下文类的实现非常简单,但它可能是程序员工具箱中最有用的类之一。如果没有这个类或类似的东西,就没有办法在屏幕上绘图而不会产生大量的闪烁。
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。