在GDI中,DC(Device context)是一个非常重要的概念。
有的书中,将DC翻译为设备描述表(《Windows 程序设计 第五版》作者Charles Petzold),
也有的书将DC翻译为设备上下文。
到底什么是DC?
用现实中的例子来理解可能更容易些。
如果你喜欢画画,你得先准备了画布,画笔,颜料……
画画的环境搭建好了,你就可以画画了。
这个画画的环境,就是DC。
在图形环境下,一切都是画出来的,所以,你要准备好一个DC,才能在屏幕上画画。——写字也是画画。
在画画的环境中,有哪些对象呢?
画布——GDI对象之一:区域
画笔——GDI对象之一:画笔
颜料盒——GDI对象之一:调色板
如果要在画笔上写字的话,写什么样的字体呢?方正字体?徐静蕾字体?——字体也是GDI对象之一。
有的画笔比较粗,专用来刷大面积背景色的,这是刷子——GDI对象之一:刷子
如果你不想画了,只想把别人画好的画,贴到你的画布上,这也是可以的。——GDI对象之一:位图。
所以,这里就有6种GDI对象可以用于DC。
现在开始画画了,你拿起了一只笔。——在Windows环境里,这叫选择了一个画笔对象:使用SelectOBject函数。当然,如果你没带笔也没关系,Windows为你准备了几只画笔,你可以这样申请系统提供的缺省画笔:hPen = GetStockObject(WHITE_PEN);
如果你画着画着,觉得手中的笔用着不爽,可以换一只啊,没关系的。——依旧是SelectObject()换笔。
当然,如果你走出了画室,别完了把你的画笔清除掉,要不画室里全是笔啊,刷子啊,太乱了。——DeleteObject()
测试例子:
void CEX03aView::OnDraw(CDC* pDC)
{
CEX03aDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->SelectStockObject(GRAY_BRUSH);
pDC->Ellipse(CRect(300,320,400,420));
CBrush brush1;
brush1.CreateSolidBrush(RGB(0,0,255));
/*同上*/CBrush brush(RGB(0,255,0));
/*函数功能:该函数创建一个具有指定颜色的逻辑刷子。
函数原理:HBRUSH CreateSolidBrush(COLORREF crColor);
参数: crColor:指定刷子的颜色。
返回值:如果该函数执行成功,那么返回值标识一个逻辑实心刷子;如果函数失败,那么返回值为NULL。
*/
CBrush* pTempBrush = NULL;
CRect rc;
GetClientRect(&rc);
/*在Win32 SDK, 该API函数原型为 BOOL GetClientRect( HWND hWnd, // 窗口句柄 LPRECT lpRect // 客户区坐标 );
在MFC中,该函数的原型为void GetClientRect(LPRECT lpRect) const;
GetClientRect(&rc); 获取的是 client 相对 client 的区域.所以是0,0,..
GetWindowRect(&rc); 获取的是 window 相对 screen 的区域.窗口的 left 和 top 肯定在 client 的"外侧",所以 ScreenToClient 之后变成-2,-2..(-2,-2是client和window之间的间隔差--border)
*/
ScreenToClient(&rc);
pTempBrush = (CBrush*)pDC-> SelectObject(&brush1); // Save original brush.
// Paint upper left corner with blue brush.
pDC-> Rectangle(0, 0, rc.Width()/ 2, rc.Height() / 2);
pDC->SelectObject(&brush);
pDC->Ellipse(CRect(0,20,100,120));
}
void CMy10View::OnDraw(CDC* pDC)
{
pDC->MoveTo (10,10);
pDC->LineTo (110,10);
CPen newPen(PS_DASHDOTDOT,10,(COLORREF) 192); //红色的笔宽度为10
CPen * pOldPen=pDC->SelectObject (&newPen);
//在将新对象选进设备环境的同时返回指向前一次被选对象的指针。作用保存原来的对象,以便完成任务时恢复它。
。。。
pDC->SelectObject (pOldPen);//把原来的对象恢复
}
由于SelectObject函数返回的GDI C++对象指针具有临时性,当程序的空闲处理阶段或者控制函数返回时应用程序框架会将临时的C++对象删除,我们不能简单的把这一指针保存在类的数据成员中,而应该借助GetSafeHdc函数将它转化为Windows的句柄,以便持久的保存GDI的标识。
通过句柄保存gdi对象
void CMy10View::OnDraw(CDC* pDC)
{
HPEN m_hPen; //一个指向CPen对象的指针
pDC->MoveTo (10,10);
pDC->LineTo (110,10);
CPen newPen(PS_DASHDOTDOT,10,(COLORREF) 192); //红色的笔宽度为10
CPen * pOldPen=pDC->SelectObject (&newPen); //在将新对象选进设备环境的同时返回指向前一次被选对象的指针。作用保存原来的对象,以便完成任务时恢复它。
m_hPen=(HPEN)pOldPen->GetSafeHandle ();//获得并保存原来对象的句柄
pDC->MoveTo (10,20);
pDC->LineTo (110,20);
pDC->SelectObject (CPen::FromHandle (m_hPen));//把原来的对象恢复,和前面例子不同的是通过句柄
pDC->MoveTo (10,30);
pDC->LineTo (110,30);
}
恢复gdi对象句柄是为了以后的操作仍然使用原来的gdi对象。