设备上下文DC是一个Windows数据结构,它包含了某个设备的绘制属性。通常,绘制调用都是借助于上下文对象,而这些设备上下文对象封装了用于画线、形状、文本等的Windows API。设备上下文是设备无关的,所以它既可以用于绘制屏幕,也可以用于绘制打印机甚至元文件。设备上下文在内存中创建,而内存经常受到扰动,所以它的地址是不固定的。因此,一个设备上下文句柄不是直接指向设备上下文对象,而是指向另外一个跟踪设备上下文地址的指针。
设备上下文可分为4种:
1)显示设备上下文
主要用于显示设备上的绘制操作,当应用绘制客户区时,它需要调用BeginPaint、GetDC或GetDCEx函数获取显示设备上下文。绘制结束后,需要调用EndPaint或ReleaseDC函数释放它。
2)打印机设备上下文
应用程序以合适的参数(如打印机驱动名、打印机名等)调用函数CreateDC,完成打印任务后,就会调用DeleteDC,以删除打印机设备上下文。
3)内存设备上下文
主要为特定的设备存储位图,它支持在位图上进行绘制操作。通常通过调用CreateCompatibleDC来获取内存设备上下文,当系统处理这个调用时,它将在内存中创建一个和原始设备颜色格式兼容的位图。
内存设备上下文将系统内存用作显示表面,通常使用内存设备上下文预先在系统内存中绘制复杂的图形,然后再快速地将其复制到实际的设备上下文的显示表面上,而绘制图形的结果仍保存在内存设备上下文的DDB中。
4)信息设备上下文
主要用于获取默认设备的数据。如调用函数CreateIC,以便为打印机的特定模型创建信息设备上下文,然后调用函数GetCurrentObject和GetObject来获取默认的画笔和画刷的属性。在使用完信息设备上下文之后,需调用DeleteDC以删除设备上下文。
MFC中,CDC类封装了绘图所需要的所有成员函数,以及各种类型的Windows设备上下文的全部功能。
CDC类有两个成员变量:m_hDC和m_hAttribDC,它们都是Windows设备上下文句柄。在创建CDC对象时,它们指向同一个设备。CDC设备使用m_hDC对其所有的成员函数作输出调用;而使用m_hAttribDC对其所有成员函数作属性调用。一般情况下,这两个成员变量的值是一样的,如果需要的话,可以将它们初始化为不同的设备句柄,如在使用CMetaFileDC类时(CMetaFileDC从物理设备上获取设备信息,而输出却在元文件上,所以m_hDC和m_hAttribDC是不同的)。
构造函数如下:
CDC::CDC()
{
m_hDC = NULL;
m_hAttribDC = NULL;
m_bPrinting = FALSE;
}
在实践中,CDC不像派生类那样使用::GetDC()等函数来获取一个设备上下文,而是创建一个设备上下文,如CDC::CreateCompatibleDC等。
析构函数:
CDC::~CDC()
{
if(m_hDC != NULL)
::DeleteDC(Detach());
}
具体使用时,MFC提供了以下四个CDC派生类:
1)CPaintDC—封装了对BeginPaint和EndPaint的调用
在Windows应用程序中,通常在绘制图像之前调用BeginPaint,然后在设备上下文中进行一系列绘制操作,最后调用EndPaint函数结束绘制。类CPaintDC正是封装了该过程:在构造CPaintDC对象时,其构造函数自动调用BeginPaint函数;在销毁CPaintDC对象时,其析构函数自动调用EndPaint函数。
在基于框架的应用中,一般在视图类的OnDraw成员函数中处理有关重绘的操作。通过OnPrepareDC成员函数,框架自动向OnDraw成员函数传递一个类型为CPaintDC的设备上下文对象,并且在此对象上进行绘制,而对象的构造和销毁则由框架自动完成。
CPaintDC的构造函数:
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();
}
2)CClientDC—管理窗口客户区对应的显示设备上下文
在CClientDC构造函数中,通过调用GetDC函数而非BeginPaint来获取设备上下文;在析构函数中调用ReleaseDC而非EndPaint:
CClientDC::CClientDC(CWnd* pWnd)
{
ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd));
//Attach用于将设备上下文句柄和设备上下文类绑定
if(!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd())))
AfxThrowResourceException();
}
CClientDC::~CClientDC()
{
ASSERT(m_hDC != NULL);
::ReleaseDC(m_hWnd, Detach());//先解除设备上下文资源与C++类对象的绑定
}
3)CWindowDC—管理与整个窗口对应的显示设备上下文,包括它的框架和控件
构造函数如下:
CWindowDC::CWindowDC(CWnd* pWnd)
{
ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd));
if(!Attach(::GetWindowDC(m_hWnd = pWnd->GetSafeHwnd())))
AfxThrowResourceException();
}
释放设备上下文使用的是ReleaseDC,析构函数和CClientDC完全一样。此类对象主要用于窗口的非客户区,如在响应消息WM_NCPAINT时,就可以在非客户区上进行绘制,不过一般很少使用该类。
4)CMetaFileDC—与带有元文件的设备上下文相关联
在设备上下文中可以完成如下操作:枚举现有的图形对象、选入新的图形对象、删除现存的图形对象、保存当前的图形对象以及它们的属性、恢复先前保存的图形对象以及它们的属性以及其他操作等。