目录
2. CDC,CPaintDC, CClientDC, CWindowDC, CMetaFileDC
一. DC
1. 概念
设备上下文:通俗来说就是,我们在绘图时用来响应软,硬件消息的媒介。MFC为我们封装了CDC类,那我们就结合MSDN来学习,就显得不会那么乱了。
2. CDC,CPaintDC, CClientDC, CWindowDC, CMetaFileDC
CDC:DC的基类。
CPaintDC:跟进下源代码,发现本质上调用了BeginPaint()和EndPaint(),所以只能存在于WM_PAINT消息响应里,原因是它还需要帮忙清除消息列表里的WM_PAINT消息。原点坐标为客户区的左上角。
CClientDC:原点坐标在客户区左上角,在哪里使用就没有限制了。
CWindowDC:原点坐标在窗口的左上角,使用也没有限制。
CMetaFileDC:高精度绘制,如CAD,基本用不到。
3. 用法
(1) 使用实例
void CDlgDC::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect stRect;
GetClientRect(&stRect);
dc.FillSolidRect(&stRect, RGB(240, 255, 255));
dc.TextOut(0, 0, _T("PaintDC Draw"));
CClientDC objClientDC(this);
objClientDC.TextOut(100, 0, _T("ClientDC Draw"));
//获取窗口DC
CDC* pDC = CDC::FromHandle(::GetDC(this->m_hWnd));
pDC->TextOut(200, 0, _T("CDC draw"));
::ReleaseDC(GetSafeHwnd(), pDC->GetSafeHdc());
}
... ...
void CDlgDC::InitDraw()
{
//坐标原点为窗口的左上角(0,0),故可以在标题栏作画
CWindowDC objWindowDC(this);
objWindowDC.TextOut(0, 0, _T("WindowDC Draw"));
}
//为了作测试,窗口样式还是Dialog带标题栏,所以在这里重绘标题栏
void CDlgDC::OnNcPaint()
{
InitDraw();
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CDialogEx::OnNcPaint()
}
(2) 获取/释放窗口DC
//获取窗口DC
CDC* pDC = CDC::FromHandle(::GetDC(this->m_hWnd));
pDC->TextOut(200, 0, _T("CDC draw"));
::ReleaseDC(GetSafeHwnd(), pDC->GetSafeHdc());
4. 绘图流程
(1) 前面讲了一下DC的概念,查看一下MSDN的CDC类会发现函数太多,看得头晕,那我们就来梳理下。
(2) 先说下通用用法,绘图前一定选一块"画布"(DC), 再搞一种"画图工具"(gdi对象, 画笔,画刷等),然后开始绘制(绘图函数)。除了几个特殊函数,基本上都满足这个绘图流程。
(3) 那我们再细分下:与画线有关的用CPen;填充相关的用CBrush;字体与文本相关的CFont;与图片相关的CBitmap;路径相关(填充多边形)的BeginPath;裁剪窗体相关的CRgn;不常用的先不说,然后绘图时我们再将这些组合起来,就实现了绘图。后面针对每个gdi对象我们再详细聊聊。
//创建DC
CClientDC objDC(this);
//创建GDI对象
CPen objPen;
objPen.CreatePen(PS_SOLID, 4, (COLORREF)-1);
//将GDI象装进DC中
CPen* pOldPen = objDC.SelectObject(&objPen);
//绘制
objDC.Rectangle(CRect(0, 0, 100, 100));
//释放
objDC.SelectObject(pOldPen);
::DeleteObject(objPen);
(4) 最后我们再聊聊资源释放的问题, objDC.SelectObject(pOldPen);前面画刷被选入设备,如果不恢复缺省或系统画刷,::DeleteObject(objPen)就会失效,造成内存泄露,而且不会报错,只会一直累加,造成程序的崩溃。
二. CPen
1. 说明
创建画笔时要注意,部分画笔样式(PS_DOT等)只在限制的画笔宽度下才有有效。创建画笔的两种方式。
//方式1
CPen objPen;
objPen.CreatePen(PS_SOLID, 4, RGB(0, 245, 255));
//方式2
//LOGPEN stLogPen;
//stLogPen.lopnStyle = PS_SOLID;
//stLogPen.lopnWidth = CPoint(4, 4);
//stLogPen.lopnColor = RGB(0, 245, 255);
//objPen.CreatePenIndirect(&stLogPen);
2. 使用
void CDlgPen::InitDraw()
{
CClientDC objDC(this);
//获取客户端区域
CRect stRect;
GetClientRect(&stRect);
//画点
for (int iNum = 0; iNum < 10; iNum++)
{
objDC.SetPixel(0 + iNum * 10, 10, RGB(255, 0, 0));
}
//画笔
CPen objPen;
objPen.CreatePen(PS_SOLID, 4, RGB(0, 245, 255));
//CreatePenIndirect效果一样
//LOGPEN stLogPen;
//stLogPen.lopnStyle = PS_SOLID;
//stLogPen.lopnWidth = CPoint(4, 4);
//stLogPen.lopnColor = RGB(0, 245, 255);
//objPen.CreatePenIndirect(&stLogPen);
CPen* pOldPen = objDC.SelectObject(&objPen);
//画线
objDC.MoveTo(200, 20);
objDC.LineTo(700, 70);
//画弧
objDC.Arc(CRect(10, 10, 110, 110), CPoint(20, 20), CPoint(100, 100));
objDC.MoveTo(0, 120);
objDC.ArcTo(CRect(0, 120, 100, 220), CPoint(0, 120), CPoint(100, 220));
objDC.MoveTo(0, 350);
objDC.AngleArc(100, 350, 100, 0.0, 180.0);//圆点, 半径, 起始角度, 结束角度
//画矩形
objDC.Rectangle(CRect(0, 400, 120, 480));
//画圆角矩形
objDC.RoundRect(CRect(200, 100, 340, 200), CPoint(10, 10));
//画椭圆
objDC.Ellipse(CRect(220, 220, 360, 320));
//画饼图
objDC.Pie(CRect(220, 340, 360, 460), CPoint(220, 340), CPoint(360, 360));
//画封闭图形
CPoint aptData[] = {CPoint(500, 200), CPoint(600, 100), CPoint(700, 200), CPoint(630, 250), CPoint(550,