Windows程序中DC的介绍
装置内容(简称为「DC」)实际上是GDI内部保存的资料结构。装置内容与特定的显示设备(如视讯显示器或印表机)相关。
对於视讯显示器,装置内容总是与显示器上的特定视窗相关。
装置内容中的有些值是图形「属性」,这些属性定义了GDI绘图函式工作的细节。例如,对於TextOut,装置内容的属性确定
了文字的颜色、文字的背景色、x座标和y座标映射到视窗的显示区域的方式,以及显示文字时Windows使用的字体。
MSDN的解释:
Device Contexts
A device context is a structure that defines a set of graphic objects and their associated attributes, as well as the graphic modes that affect
output. The graphic objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the
screen, a palette for defining the set of available colors, a region for clipping and other operations, and a path for painting and drawing
operations. The remainder of this section is divided into the following three areas.
About Device Contexts
Device independence is one of the chief features of Microsoft Windows. Applications can draw and print output on a variety of devices.
The software that supports this device independence is contained in two dynamic-link libraries. The first, Gdi.dll, is referred to as the
graphics device interface (GDI); the second is referred to as a device driver. The name of the second depends on the device where the
application draws output. For example, if the application draws output in the client area of its window on a VGA display, this library is
Vga.dll; if the application prints output on an Epson FX-80 printer, this library is Epson9.dll.
An application must inform GDI to load a particular device driver and, once the driver is loaded, to prepare the device for drawing
operations (such as selecting a line color and width, a brush pattern and color, a font typeface, a clipping region, and so on). These tasks
are accomplished by creating and maintaining a device context (DC). A DC is a structure that defines a set of graphic objects and their
associated attributes, and the graphic modes that affect output. The graphic objects include a pen for line drawing, a brush for painting and
filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colors, a region for clipping and other
operations, and a path for painting and drawing operations. Unlike most of the structures, an application never has direct access to the DC;
instead, it operates on the structure indirectly by calling various functions.
取得DC的各种方式
SDK's way:
1. BeginPaint
case WM_PAINT: HDC hdc = BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps); |
MSDN的解释:
The BeginPaint function automatically sets the clipping region of the device context to exclude any area outside the update region. The update
region is set by the InvalidateRect or InvalidateRgn function and by the system after sizing, moving, creating, scrolling, or any other operation
that affects the client area. If the update region is marked for erasing, BeginPaint sends a WM_ERASEBKGND message to the window.
An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call
to the EndPaint function.
其中给出了本次重绘的Clip Rectangle,所有在这个rectangle之外的绘制操作都不会显示。
这两个BeginPaint和EndPaint呼叫之间中没有任何叙述,仅仅使先前无效区域变为有效。
但以下方法是错误的:
case WM_PAINT: return 0 ; // WRONG !!!
|
Windows将一个WM_PAINT讯息放到讯息伫列中,是因为显示区域的一部分无效。如果不呼叫BeginPaint和EndPaint(或者
ValidateRect),则Windows不会使该区域变为有效。相反,Windows将发送另一个WM_PAINT讯息,且一直发送下去。
2. GetDC
MSDN的解释:
The GetDC function retrieves a handle to a display device context (DC) for the client area of a specified window or for the entire screen. You
can use the returned handle in subsequent GDI functions to draw in the DC.
与BeginPaint和EndPaint一样,GetDC和ReleaseDC函式必须成对地使用。如果在处理某讯息时呼叫GetDC,则必须在退出视窗讯息
处理程式之前呼叫ReleaseDC。不要在一个讯息中呼叫GetDC却在另一个讯息呼叫ReleaseDC。
与从BeginPaint传回装置内容代号不同,GetDC传回的装置内容代号具有一个剪取矩形,它等於整个显示区域。可以在显示区域的某
一部分绘图,而不只是在无效矩形上绘图(如果确实存在无效矩形)。与BeginPaint不同,GetDC不会使任何无效区域变为有效。如
果需要使整个显示区域有效,可以呼叫
ValidateRect (hwnd, NULL) ; |
一般可以呼叫GetDC和ReleaseDC来对键盘讯息(如在字处理程式中)和滑鼠讯息(如在画图程式中)作出反应。此时,程式可以
立刻根据使用者的键盘或滑鼠输入来更新显示区域,而不需要考虑为了视窗的无效区域而使用WM_PAINT讯息。不过,一旦确实收
到了WM_PAINT讯息,程式就必须要收集足够的资讯後才能更新显示。
与GetDC相似的函式是GetWindowDC。GetDC传回用於写入视窗显示区域的装置内容代号,而GetWindowDC传回写入整个视窗的
装置内容代号。例如,您的程式可以使用从GetWindowDC传回的装置内容代号在视窗的标题列上写入文字。然而,程式同样也应该
处理WM_NCPAINT (「非显示区域绘制」)讯息。
3. CreateDC
MSDN的解释:
HDC CreateDC( LPCTSTR lpszDriver, // driver name LPCTSTR lpszDevice, // device name LPCTSTR lpszOutput, // not used; should be NULL CONST DEVMODE* lpInitData // optional printer data ); |
MFC's way
1. CDC
对HDC的包装,类似CWnd对HWND的包装.在CDC的构造函数里面并没有对m_hDC进行初始化.
MSDN的解释:
class CDC : public CObject
Defines a class of device-context objects.
Remarks
The CDC object provides member functions for working with a device context, such as a display or printer, as well as members
for working with a display context associated with the client area of a window.
Do all drawing through the member functions of a CDC object. The class provides member functions for device-context operations,
working with drawing tools, type-safe graphics device interface (GDI) object selection, and working with colors and palettes. It also
provides member functions for getting and setting drawing attributes, mapping, working with the viewport, working with the window
extent, converting coordinates, working with regions, clipping, drawing lines, and drawing simple shapes, ellipses, and polygons.
Member functions are also provided for drawing text, working with fonts, using printer escapes, scrolling, and playing metafiles.
To use a CDC object, construct it, and then call its member functions that parallel Windows functions that use device contexts.
For specific uses, the Microsoft Foundation Class Library provides several classes derived from CDC . CPaintDC encapsulates calls to
BeginPaint and EndPaint. CClientDC manages a display context associated with a window's client area. CWindowDC manages a display
context associated with an entire window, including its frame and controls. CMetaFileDC associates a device context with a metafile.
MFC中的代码实现:
CDC::CDC() { m_hDC = NULL; m_hAttribDC = NULL; m_bPrinting = FALSE; } |
CDC::~CDC() { if (m_hDC != NULL) ::DeleteDC(Detach()); } |
BOOL CDC::Attach(HDC hDC) { ASSERT(m_hDC == NULL); // only attach once, detach on destroy ASSERT(m_hAttribDC == NULL); // only attach to an empty DC
if (hDC == NULL) return FALSE;
CHandleMap* pMap = afxMapHDC(TRUE); // create map if not exist ASSERT(pMap != NULL); pMap->SetPermanent(m_hDC = hDC, this);
SetAttribDC(m_hDC); // Default to same as output return TRUE; } |
HDC CDC::Detach() { HDC hDC = m_hDC; if (hDC != NULL) { CHandleMap* pMap = afxMapHDC(); // don't create if not exist if (pMap != NULL) pMap->RemoveHandle(m_hDC); }
ReleaseAttribDC(); m_hDC = NULL; return hDC; }
|
2. CPaintDC
对BeginPaint的包装
MSDN的解释:
class CPaintDC : public CDC
It performs a CWnd::BeginPaint at construction time and CWnd::EndPaint at destruction time.
A CPaintDC object can only be used when responding to a WM_PAINT message, usually in your OnPaint message-handler
member function.
MFC中的代码实现:
CPaintDC::CPaintDC(CWnd* pWnd) { ASSERT_VALID(pWnd); ASSERT(::IsWindow(pWnd->m_hWnd));
if (!Attach(::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps))) AfxThrowResourceException(); } |
CPaintDC::~CPaintDC() { ASSERT(m_hDC != NULL); ASSERT(::IsWindow(m_hWnd));
::EndPaint(m_hWnd, &m_ps); Detach(); } |
3. CClientDC
对GetDC的包装
MSDN的解释:
class CClientDC : public CDC
This means that the device context associated with a CClientDC object is the client area of a window.
MFC中的代码实现:
CClientDC::CClientDC(CWnd* pWnd) { ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd));
if (!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd()))) AfxThrowResourceException(); }
|
CClientDC::~CClientDC() { ASSERT(m_hDC != NULL); ::ReleaseDC(m_hWnd, Detach()); } |
4. CWindowDC
对GetWindowDC的包装
MSDN的解释:
Calls the Windows functions GetWindowDC at construction time and ReleaseDC at destruction time. This means that a
CWindowDC object accesses the entire screen area of a CWnd (both client and nonclient areas).
MFC中的代码实现:
CWindowDC::CWindowDC(CWnd* pWnd) { ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd));
if (!Attach(::GetWindowDC(m_hWnd = pWnd->GetSafeHwnd()))) AfxThrowResourceException(); } |
CWindowDC::~CWindowDC() { ASSERT(m_hDC != NULL); ::ReleaseDC(m_hWnd, Detach()); } |