OnPaint与OnDraw中的CPaintDc与CDC

今天在对话框上绘制图形时遇到了一个问题,直接上代码:

下面是对话框重载的OnPaint函数:

[cpp]  view plain copy
  1. CRect rect;  
  2. CDC *pDC = GetDC();  
  3. CDC memDC;  
  4. GetClientRect(&rect);  
  5. CBitmap memBitmap;  
  6. memDC.CreateCompatibleDC(NULL);  
  7. memBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());  
  8. memDC.SetBkMode(TRANSPARENT);  
  9. memDC.SelectObject(&memBitmap);  
  10. COLORREF bkColor = ::GetSysColor(COLOR_3DFACE);//得到系统颜色  
  11. memDC.FillSolidRect(rect.left, rect.top,rect.Width(), rect.Height(),bkColor);//绘制背景  
  12. memDC.FillSolidRect(rect.left, rect.bottom-40,rect.Width(), rect.Height(),RGB(80,80,80));  
  13. pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);  
  14.   
  15. CDialog::OnPaint();  

这段代码的本意是绘制一个矩形框,然后调用CDialog::Onpaint()把原来对话框上的控件也显示出来。

但出现的问题刚开始却让人摸不着头脑:点击“显示桌面”,最小化所有的窗口,再弹出该对话框时,绘制的矩形框会消失;但使对话框被屏幕遮挡,只显示其一部分,再把对话框拖回屏幕中间完整显示的时候,对话框上除矩形框之外的所有控件会消失。


然后再看看改动后正常的代码:

[cpp]  view plain copy
  1. CPaintDC    dc(this);  
  2. CRect rect;  
  3. CDC *pDC = &dc;  
  4. CDC memDC;  
  5. GetClientRect(&rect);  
  6. CBitmap memBitmap;  
  7. memDC.CreateCompatibleDC(NULL);  
  8. memBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());  
  9. memDC.SetBkMode(TRANSPARENT);  
  10. memDC.SelectObject(&memBitmap);  
  11. COLORREF bkColor = ::GetSysColor(COLOR_3DFACE);//得到系统颜色  
  12. memDC.FillSolidRect(rect.left, rect.top,rect.Width(), rect.Height(),bkColor);//绘制背景  
  13. memDC.FillSolidRect(rect.left, rect.bottom-40,rect.Width(), rect.Height(),RGB(80,80,80));  
  14.     pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);  
  15. ReleaseDC(pDC);  


改变的地方就是把获取DC的方式:CDC *pDC = GetDC()  改成了CpaintDC dc(this),然后取消调用Cdialog::Onpaint()函数,这是为什么呢?


CPaintDC的独到之处就在于,它在构造函数中调用了CWnd::BeginPaint在析构时调用了CWnd::EndPaint,而且它只能响应WM_ONPAINT消息。而这个BeginPaint会发送WM_ONERASEBKGND消息,因此,它只擦除指定的背景并重画,不影响对话框内的其他控件。值得注意的是,在这操作之后不要再调用CDialog::Onpaint函数。


而之前的方法之所以不成功是因为:

BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
GetDC()和ReleaseDC()并不删除也不能使无效区域有效,因此当程序跳出 WM_PAINT 时 ,无效区域仍然存在。系统就回不断发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。其中无效区域是指需要重画的区域,无效的意思是:当前内容是旧的,过时的。

只有当一个窗口消息空闲时,系统才会抽空检查一下这个窗口的无效区域是否为非空(WM_PAINT的优先级是最低的。这也就是为什么系统很忙时窗口和桌面往往会出现变白、刷新不了、留拖拽痕迹等现象的原因),如果非空,系统就发送WM_PAINT。所以一定要用BeginPaint、EndPaint把无效区域设为空,否则WM_PAINT将一直被发送。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值