设备上下文

设备上下文即Device Context,简称DC。通过使用设备上下文,编程人员可以不必关心输出设备的具体特性,直接绘制最终的结果,而剩余的与具体显示硬件打交道的工作交给系统来完成。 

首先捋一下他们的关系:

HDC是句柄(句柄是Windows系统中的一种数据类型),是设备描述句柄;CDC是MFC封装的Windows设备相关的一个类,封装了几乎所有关于HDC的操作;CClientDC,CWindowDC,CPaintDC是CDC的衍生类。CClientDC,CWindowDC 区别不大, 可以说 CWindowDC包含了CClientDC 就拿记事本来说:CClientDC 就只是白白的我们可以编辑文字的那个区域,是客户区;CWindowDC 除了上面说的白白区域, 还包括菜单栏和工具栏等。也可以这样说,HDC定义的变量指向一块内存,这块内存用来描述一个设备的相关的内容,所以也可以认为HDC定义的是一个指针;而CDC类定义一个对象,这个对象拥有HDC定义的一个设备描述表,同时也包含与HDC相关的操作的函数。这与HPEN和CPen,POINT与CPoint之间的差别是一样的。

然后看一下HDC与CDC之间的转换


方法一: 此方法在设备结束时不会销毁原来的资源(即:hDC,hBitmap)
CDC *pDC = CDC::FromHandle(hDC);// FromHandle 是通过HDC来创建了一个CDC对象,以方便操作,这时
                                // 释放CDC会造成隐患。

方法二: 此方法在设备结束时会销毁原来的资源(即:hDC,hBitmap)
CDC dc;
dc.Attach(hDC);
//通过PDC获得HDC
HDC hDC;
hDC=GetSafeHDC(pDC);

补充:FromHandle用于创建一个临时对象(类),没有独占性,MSDN上的说法是“临时的瞬态对象,不应在外部存储使用”,这种方法消耗小,通常用于临时绘制并且不改变DC属性的情况下。
Attach是一个独占的强制方法,创建一个长期使用的对象,通过Map的SetPermanent函数,完成了对象和句柄的捆绑,在释放前不能再次Attach,使用后必须通过Detach释放。这种方法安全但消耗大,通常用于安全的DC操作和对DC属性修改的操作。
 

一:

     HDC hdc=::GetDC(m_hWnd);//m_hWnd == this->m_hWnd 即当前窗口句柄
     MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
     LineTo(hdc,point.x,point.y);
    ::ReleaseDC(m_hWnd,hdc);//必须和GetDC配对
可以看到HDC的使用较麻烦, 而且如果::GetDC和::ReleaseDC不配对的话,会造成错误

二:

    CDC *pdc=GetDC();
    ReleaseDC(pdc);

必须要释放,每个进程的GDI句柄数是有上限的(MSDN: The number of DCs is limited only by available memory. ),超过上限后,进程再GetDC就会失败

CDC * ppDC = GetDC();
ppDC->TextOut(0,0,"zhaonan");

 

 

三:

    CClientDC dc(this);不需要我们去释放,自己会去释放;

CClientDC dc(this);
dc.TextOut(0,0,"zhaonan");

四:

    CWindowDC dc(this);也不需要我们去释放,好处是可以访问整个屏幕区域;

CWindowDC dc(this);
dc.TextOut(0,0,"zhaonan");

 

实验二三四结果怎么是一样的呢? 

五:

CPaintDC(),只能用在响应 WM_PAINT 事件,只在OnPaint中使用,那么OnPaint和OnDraw的关系呢?

OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中。

关于 WM_PAINT 事件
系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时,等等,这些动作都是由系统管理的,应用只是被动地接收该消息,在消息处理函数中进行绘制操作;大多数的时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect和InvalidateRgn函数来完成的。

MFC中OnDraw与OnPaint的区别 - xiexievv的专栏 - CSDN博客  https://blog.csdn.net/xiexievv/article/details/6271153

 

 

GetDC():最常见的取得DC的用法,如果是API的话,给它一个窗口句柄,它返回给你这个窗口的DC,这样取得的DC 必须 手动用ReleaseDC()来释放,否则……嘿嘿
举例: HDC dc = GetDC(NULL); // 如果窗口句柄设为NULL,取得整个屏幕的DC

CClientDC()和CWindowDC():更好用的取得DC的用法,前面一个取得当前窗口的客户区的DC,后面那个取得整个窗口的DC,这样得到的DC用完就完了,它会自己处理后事,包括释放
举例: CClientDC dc;

CPaintDC():专用于OnPaint(),它构造的时候会调用CWnd::BeginPaint(),析构的时候调用CWnd::EndPaint()
举例: CPaintDC dc;

1)API函数方法用HDC
 
HDC hdc;
hdc=::GetDC(m_hWnd);
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);//必须成对使用
这里获得GetDC()函数需要跟ReleaseDC()函数成对使用
 
2)用CDC类成员函数。此时别忘记ReleaseDC
 
CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);//必须成对使用
同样需要成对使用手动释放DC
 
3)用CClientDC
 
CClientDC dc(this);
//CClientDC dc(GetParent());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);//此处不需要ReleaseDC,因为CClientDC会自动释放DC
CClientDC构造函数传递一个窗口类的对象。其在用完后自动释放DC,不需要显式的调用ReleaseDC()
 
4)用CWindowDC,用它甚至可以整个屏幕区域画线
 
CWindowDC dc(this);
//CWindowDC dc(GetParent());
/*CWindowDC dc(GetDesktopWindow());//此时可以在整个屏幕上画线。
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);*/
CPen pen(PS_DOT,1,RGB(0,255,0));
CClientDC dc(this);
CPen *pOldPen=dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen);
同样CWindowDC构造函数也需要传递一个窗口类的对象。与CClientDC的区别是该对象可以访问整个窗口区域,包括框架窗口(菜单栏,工具栏)。而CClientDC只能访问的是客户区。
 
这里同时可以初步了解一下
 
CPen *pOldPen=dc.SelectObject(&pen);函数,同时注意一下其返回值!
 
这是GDI画图的特点,当给dc执行一次SelectObject,它将返回前一次SelectObject的内容,绘图完毕,执行dc.SelectObject(pOldPen)。
就相当于你在画布上画图,你手里本来默认拿着一只白色的画笔,现在你要画蓝色线条,所以你选了一个蓝色画笔,画图完毕,你还要恢复你手里默认拿着的白色画笔。

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值