2013-04-18 16:58:57|  分类: GDI |  标签:cclientdc与cpaintdc  dc释放  dc  |字号 订阅

CClientDC dc(this);

CPaintDC dc(this);

从前面我们可以得出,这两个语句就是新建dc变量并把当前的CWnd或其派生类的句柄得到当前窗体的作画区域放在dc这个变量中。

它们都是在函数中调用,当函数结束的时候调用他们俩的析构函数。

区别在于CPaintDC在构造函数中封装了BeginPaint函数,析构函数封装了EndPaint,并由BeginPaint返回DC,因此CPaintDC在构造DC时会清空WM_PAINT事件,所以当CPaintDC析构的时候不会再触发WM_PAINT。也就是说在OnPaint函数中必须用CPaintDC函数否则每当OnPaint函数结束的时候就会再触发OnPaint,会不停循环下去。

另外, CPaintDC只能在WM_PAINT消息中使用, 用于有重画消息发出时才使用的内存设备环境, 否则它的bitblt函数是不起作用的,原因不明。

简单的说:CClientDC是我们可以随意使用的。而CPaintDC则是WM_PAINT消息专用的重绘。

在重绘时最靠谱的作法就是使用CPaintDC提供的dc进行重绘,因为这样会保证每次处理一次WM_PAINT消息之后会清空WM_PAINT,这样会适当避免闪烁的显像。例如:
void CVVr2WorkDlg::OnPaint(){    CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码    DrawPatientInfor(&dc, name, id,sex, part);    DrawVideoBoundary(&dc);   // 不为绘图消息调用 CDialogEx::OnPaint()}

void CVVr2WorkDlg::DrawPatientInfor(CPaintDC *pDC, CString &sName, CString &sID, CString &sSex,                                    CString &sPart){    CString sPatientName(_T("姓名:"));    sPatientName += sName;

    CString sPatientID(_T("ID:"));  sPatientID += sID;

    CString sPatientSex(_T("性别:")); sPatientSex += sSex;

  CString sPatientPart(_T("部位:"));    sPatientPart += sPart;

    int uiStartW = 6;    int uiStartH = WORKWNDHEIGHT-130;

  pDC->SetBkMode(TRANSPARENT);

 pDC->TextOut(uiStartW, uiStartH, sPatientName);    pDC->TextOut(uiStartW, uiStartH+20, sPatientID);  pDC->TextOut(uiStartW, uiStartH+40, sPatientSex); pDC->TextOut(uiStartW, uiStartH+60, sPatientPart);}

void CVVr2WorkDlg::DrawVideoBoundary(CPaintDC *pDC){   CRect rect;   CBrush brush(GetSysColor(COLOR_BTNFACE)); CPen pen(PS_SOLID, 2, RGB(160, 160, 160));

  GetClientRect(&rect); rect.left = rect.left + 120;

    CBrush * pOldBrush= pDC->SelectObject(&brush);  CPen * pOldPen= pDC->SelectObject(&pen);    pDC->Rectangle(rect);    pDC->SelectObject(pOldBrush);  pDC->SelectObject(pOldPen);}

------------------------------------------------------------------------------------------------------------

CDC,CPaintDC,CClientDC,CWindowDC区别

————————————————————————

1、首先,对DC进行解释一下:

Windows应用程序通过为指定设备(屏幕,打印机等)创建一个设备描述表(Device Context, DC)在DC表示的逻辑意义的“画布”上进行图形的绘制。DC是一种包含设备信息的数据结构,它包含了物理设备所需的各种状态信息。Win32程序在绘制图形之前需要获取DC的句柄HDC,并在不继续使用时释放掉。

2、然后,理顺CDC的派生类关系:

CObject 
public |------CDC 
public |------|------CClientDC 
public |------|------CPaintDC 
public |------|------CWindowDC 
public |------|------CMetaFileDC 
(注意: 除CMetaFileDC以外的三个派生类用于图形绘制.)

3 、具体的区别,在下面:

CDC是Windows绘图设备的基类
CClientDC:
(1)(客户区设备上下文)用于客户区的输出,与特定窗口关联,可以让开发者访问目标窗口中客户区,其构造函数中包含了GetDC,析构函数中包含了ReleaseDC

CPaintDC:
(1)用于响应窗口重绘消息(WM_PAINT)是的绘图输出。
(2)CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在析构函数中调用EndPaint()释放设备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。
(3)CPaintDC也只能用在WM_PAINT消息处理之中。

CWindowDC:
(1)可在非客户区绘制图形,而CClientDC,CPaintDC只能在客户区绘制图形。
(2)坐标原点是在屏幕的左上角,CClientDC,CPaintDC下坐标原点是在客户区的左上角。
(3)关联一特定窗口,允许开发者在目标窗口的任何一部分进行绘图,包含边界与标题,这种DC同WM_NCPAINT消息一起发送

说明:在绘图时推荐使用CClientDC,CPaintDC和CWindowDC对象,而不推荐直接使用CDC对象。

实例:
CClientDC *pDC = new CClientDC(this);
CWindowDC dc(this);

总结:在这些DC中只有CPaintDC具有重绘的功能(因为其封装了BeginPaint和EndPaint)!

————————————————————————

DC资源释放

这部分也很关键,笔者不知大家是否还一直使用Release模式编译VC/MFC代码,但是经常使用Debug方式的同学会经常出现一些ASSERT断言错误,这错误已发生就会强制终止程序运行。

而在使用DC时这类错误很容易发生,多数都是没有正确的使用DC,而更易出错的地方就在于DC资源的释放。下面简单介绍些笔者所知道的一些DC释放规则(粗浅用过MFC,接触面很窄!!):

ReleaseDC和DeleteDC的区别

对于Create生成的的dc应该予以DeleteDC释放,而对于GetDC的应予以ReleaseDC释放。
      例如下面这段代码:

 void CDCDemoDlg::OnGetdcApinull(){   HDC hDC=::GetDC(NULL);   ::MoveToEx(hDC,0,0,NULL); LineTo(hDC,200,20);

 ::ReleaseDC(NULL,hDC); }  
GetDC产生的DC应使用ReleaseDC释放。又如:
void CDCDemoDlg::OnGetdcCwnd(){    CDC *pDC=GetDC();    pDC->MoveTo(0,0);  pDC->LineTo(200,100);

 ReleaseDC(pDC); }   
再来个综合实例:
void ShowPic(){   HDC hdc=GetDC(hwnd);//: GetDC方式  HDC hmemdc=CreateCompatibleDC(hdc);//: Create方式  HBITMAP hbc=CreateCompatibleBitmap(hdc,480,580); SelectObject(hmemdc,hbc); BitBlt(hdc,0,0,480,580,hmemdc,0,0,SRCCOPY);   DeleteObject(hbc);    DeleteDC(hmemdc); //换成ReleaseDC(hwnd,hmemdc);将出现内存泄漏,将导致图片停止移动   ReleaseDC(hwnd,hdc);} 
然而,对于CClientDC产生的DC其实就是使用GetDC式获得的(但是CClientDC为什么具有DeleteDC成员而没有ReleaseDC,不知道为什么),但是使用中一般无需我们手动释放DC,因为,CClientDC析构函数会自动释放DC资源。所以使用CClientDC只需放心使用即可:
CClientDC dc(this);

dc.MoveTo(0,0);dc.LineTo(200,100);

//dc.DeleteDC();//会出错!!
 
如果你这里手动加入了dc.DeleteDC();在Debug下面上述代码会产生一个ASSERT错误,这是因为,CClientDC析构函数中为(大概是这样子,有点忘了):
所以,如果在析构之前已经释放了DC(调用了dc.DeleteDC(),为什么是DeleteDC呢?按理说应该是ReleaseDC啊),那么这里的断言不成立,机会出错!
 
总结:
----------------------------------------------
对于释放DC,请记住:
----------------------------------------------
GetDC之后要ReleaseDC,CreateCompatibleDC之后需要DeleteDC

CClientDC dc(this);类会自动回收的 不用进行删除。
CClientDC::~CClientDC()
{
  ASSERT(m_hDC != NULL);
 
  ::ReleseDC(m_hWnd, m_hDC);
} 

Good Luck !

VC++ - 各种DC及DC资源释放相关推荐

  1. 【Multisim仿真】TL494电路仿真 DC转DC 5V 1A输出

    [Multisim仿真]TL494电路仿真 DC转DC 5V 1A输出 Multisim仿真截图 仿真资源 本实验基于Multisim14平台 链接:https://pan.baidu.com/s/1 ...

  2. 数字IC设计之DC篇:DC流程介绍

    数字IC设计之DC篇:DC流程介绍 综合概念 综合是使用软件的方法来设计硬件, 然后将门级电路实现与优化的工作留给综合工具的 一种设计方法.它是根据一个系统逻辑功能与性能的要求,在一个包含众多结构.功 ...

  3. Java8 新的 try-with-resources 语句,自动资源释放

    读取文件后需要释放资源,对于占用内存比较大的,非常重要: (1)读取文件内存占用较多的优化方式: 一次读取部分处理完继续读取,可以有效的减少内存的占用: 使用RandomAccessFile可以从文件 ...

  4. 基于 Android NDK 的学习之旅-----资源释放

    基于 Android NDK 的学习之旅-----资源释放 做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概 ...

  5. C#资源释放及Dispose、Close和析构方法

    C#资源释放及Dispose.Close和析构方法   备注:此文的部分观点有误,之所以仍旧保留本文,是需要在后期给出一个勘误版.正确的版本在这里"C#中标准Dispose模式的实现&quo ...

  6. rhcs做HA时的资源释放脚本实现

    场景: CentOS6.3的二次封装版本,安装hortonworks的hadoop发行版,并按照其官方文档实现高可用,但无fence设备支持,因此导致断网和断电测试时,备用HA节点无法得到资源释放的通 ...

  7. C#中的非托管资源释放(FinalizeDispose)

    在了解Finalize和Dispose之前,我们需要了解两个概念,一个是托管资源,一个非委托资源. a.其中托管资源一般是指被CLR控制的内存资源,这些资源的管理可以由CLR来控制,例如程序中分配的对 ...

  8. c#中的非托管资源释放 (Finalize和Dispose)

    c#中的非托管资源释放 (Finalize和Dispose) 收藏 在了解Finalize和Dispose之前,我们需要了解两个概念,一个是托管资源,一个非委托资源. a.其中托管资源一般是指被CLR ...

  9. C#内存泄露与资源释放 经验总结

    本文链接:http://blog.csdn.net/yokeqi/article/details/41083939 C#相比其他语言,拥有强大的垃圾回收机制,但并不是这样,你就可以对内存管理放任不管, ...

最新文章

  1. python页面调用接口_python调用接口——requests模块
  2. matlab从工作区读取一维数组和结构体
  3. word 常用快捷键
  4. javascript数组查重方法总结
  5. jzoj2136-(GDKOI2004)汉诺塔【找规律,模拟】
  6. [2018.03.29 T2] 公交旅行
  7. Chorme 模拟分辨率设置
  8. SpringCloud Netflix—微服务架构
  9. 企业微信第三方应用开发
  10. 关于rand()和srand()
  11. WAIC | 九章云极方磊:Hypernets——自动化机器学习的基础框架
  12. 这个企业邮箱登陆入口更快捷
  13. 十秒钟刷完云班课的一节视频
  14. 国产linux凝思4.2系统多网卡指定路由配置
  15. 饿了么美团外卖cps返利系统外卖返利公众号搭建cps系统小程序SaaS源码
  16. 我看到了一个真实的日本
  17. 华为云高校开发者青年班第七期——DevCloud的托马斯商城部署——知识点总结
  18. Unsupported major.minor version 51.0 (unable to load class
  19. Docker下安装MCR windows镜像安装Matlab 静默安装MCR silent install 无交互安装 无Gui安装 控制台安装
  20. 《阿凡达》的元宇宙帝国多久抵达现实?

热门文章

  1. 电商 静态页面(详细讲解)
  2. Debugging other STM32 chips with STLink on Nucleo-64 development board使用Nucleo板载STLink调试烧录外部STM32应用
  3. 针对JSON的一些初级理解
  4. 如何在Mendix中发布一个REST Service
  5. Cubietruck---25.android蓝牙分析3_search分析 2
  6. 截至目前最新的选择器以及权重
  7. python将子进程的输出抛向黑洞
  8. Android在TQ2440开发板上的移植(转)
  9. 《水晶石精粹:3ds max ZBrush三维数字静帧艺术》
  10. 三菱FX指令控制步进电机定位启动