双缓冲绘图和窗口控件的绘制——ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 .
双缓冲绘图和窗口控件的绘制
---ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误
cheungmine
我们通常使用ATL COM组件,生成一个带窗口的ActiveX控件,然后希望在这个窗口中绘制我们的图像、图形等数据,然而ATL向导生成的代码中包含很多错误,下面是其自动向导生成的代码:
HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
// 将剪辑区域设置为 di.prcBounds 指定的矩形
HRGN hRgnOld = NULL;
if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
hRgnOld = NULL;
bool bSelectOldRgn = false;
HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
if (hRgnNew != NULL)
{
bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
}
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("ATL 8.0 : Canvas");
#ifndef _WIN32_WCE
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
#else
ExtTextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
ETO_OPAQUE,
NULL,
pszText,
ATL::lstrlen(pszText),
NULL);
#endif
if (bSelectOldRgn)
SelectClipRgn(di.hdcDraw, hRgnOld);
return S_OK;
}
请注意这里面包含一个错误,改正之后的代码(红色字体):
HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
// 将剪辑区域设置为 di.prcBounds 指定的矩形
HRGN hRgnOld = NULL;
if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
hRgnOld = NULL;
bool bSelectOldRgn = false;
HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
if (hRgnNew != NULL)
{
bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
}
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("ATL 8.0 : Canvas");
#ifndef _WIN32_WCE
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
#else
ExtTextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
ETO_OPAQUE,
NULL,
pszText,
ATL::lstrlen(pszText),
NULL);
#endif
if (bSelectOldRgn)
SelectClipRgn(di.hdcDraw, hRgnOld);
// 删除剪辑区域
::DeleteObject(hRgnNew); // Add by cheungmine. MUST!!
return S_OK;
}
注意其中绿色的代码,你应该完全注释掉这种绘制的逻辑,而采用双缓冲。因此,ATL自动生成的OnDraw代码是不适合实际的绘图控件的。下面的代码是我更改之后的,增加了双缓冲机制:
void MyDrawCode (HDC hdc, RECT &rc)
{
Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("ATL 8.0 : Canvas");
#ifndef _WIN32_WCE
TextOut(hdc,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
#else
ExtTextOut(hdc,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
ETO_OPAQUE,
NULL,
pszText,
ATL::lstrlen(pszText),
NULL);
#endif
}
void DbBufferDraw(HDC hdcDraw, RECT &rcClip)
{
HDC hMemDC = ::CreateCompatibleDC(hdcDraw);
ATLASSERT(hMemDC);
HBITMAP hBmpNew = ::CreateCompatibleBitmap(hdcDraw, WidthRect(rcClip), HeightRect(rcClip));
ATLASSERT(hBmpNew);
HBITMAP hBmpOld = (HBITMAP) ::SelectObject(hMemDC, hBmpNew);
// 添加自己的绘制代码
MyDrawCode(hMemDC, rcClip);
if (IsWindow()) {
::BitBlt ( hdcDraw,
rcClip.left,
rcClip.top,
WidthRect(rcClip), HeightRect(rcClip),
hMemDC,
rcClip.left,
rcClip.top,
SRCCOPY );
}
else {
::BitBlt ( hdcDraw,
rcClip.left + m_rcPos.left,
rcClip.top + m_rcPos.top,
WidthRect(rcClip), HeightRect(rcClip),
hMemDC,
rcClip.left,
rcClip.top,
SRCCOPY );
}
// 释放 hMemDC
::SelectObject(hMemDC, hBmpOld);
::DeleteObject(hBmpNew);
::DeleteDC(hMemDC);
}
HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
// 将剪辑区域设置为 di.prcBounds 指定的矩形
HRGN hRgnOld = NULL;
if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
hRgnOld = NULL;
bool bSelectOldRgn = false;
HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
if (hRgnNew != NULL)
{
bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
}
// 双缓冲
DbBufferDraw(di.hdcDraw, rc);
if (bSelectOldRgn)
SelectClipRgn(di.hdcDraw, hRgnOld);
// 删除剪辑区域
::DeleteObject(hRgnNew); // Add by cheungmine. MUST!!
return S_OK;
}
按上面的修改,烦人的闪烁没了。另外,在OnDarw中,没必要把全部绘制代码放入 MyDrawCode 中。因为 MyDrawCode 如果执行时间较长,则 OnDraw会显得很慢。因此,光是双缓冲还不够,因为OnDraw被调用的时候,都是系统激发的,我们只需要把原来保存的绘制图片直接绘制到hMemDC中即可,也就是, MyDrawCode中不可以如本例所示的那样,放置实际绘制的代码,而是只把图片重新拷贝到hdc上即可,如:
void MyDrawCode (HDC hdc, RECT &rc)
{
m_BkgndMap.CopyTo(hdc, rc);
}
m_BkgndMap 可以是自己实现的Image或CImage等图像类。
因此,在一个基本的绘图系统中,至少需要3个缓冲层次:
第一层:控件窗口HDC(无窗口控件也是存在HDC的)
第二层:控件窗口HDC的兼容MemDC,即:HDC hMemDC = ::CreateCompatibleDC(hdcDraw);
第三层:后台图片HDC包装类: m_BkgndMap
关于如何创建这样的ActiveX 窗口控,请看我的相关文章:
http://blog.csdn.net/cheungmine/archive/2007/10/10/1818913.aspx
from:http://blog.csdn.net/ubuntu64fan/article/details/5917979
双缓冲绘图和窗口控件的绘制——ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 .的更多相关文章
- C#-gdi绘图,双缓冲绘图,Paint事件的触发
一. 画面闪烁问题与双缓冲技术 1.1 导致画面闪烁的关键原因分析: 1 绘制窗口由于大小位置状态改变进行重绘操作时 绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面 ...
- GDI双缓冲绘图
一.简介 在进行复杂图形绘制时,若直接在屏幕DC上进行绘制,则会出现明显的闪烁.闪烁产生的原因是当绘制的图形较为 复杂时,图形绘制过程中就被刷新到屏幕上,导致结果断断续续地显示出来.双缓冲绘图的原理是 ...
- MFC双缓冲绘图实例
本人之前一直了解双缓冲绘图的基本原理,但是在研究很久之后才大概知道具体的使用过程,本文将详细介绍本人在实际项目中使用双缓冲绘图的案例. 实现功能:主界面显示某张包含人脸的图片,通过dlib detec ...
- mfc双缓冲绘图
1.要求 在界面加载本地图片并显示,每过100ms改变一张图片显示 2.现象 通过定时器控制CImage,Load,Draw,Destroy,会非常的卡顿.因为Load图片时,会是非常大的数据[所有C ...
- MFC双缓冲绘图(2015.09.24)
问题引入: 最近在尝试编写贪吃蛇游戏时遇到这么一个问题:当系统以较快频率向窗口发送WM_PAINT消息时,调用OnPaint()函数在窗口中绘制图形就会发生闪烁现象. 问题分析: 当我们把绘图过程放在 ...
- 陈灯WGF双缓冲绘图框架
“木丸子童屋”,专售各类儿童玩具,价格优惠,请大家多多支持:http://shop65552598.taobao.com/ WGF(windows graphic foundation)为window ...
- 【MFC】MFC绘制动态曲线,用双缓冲绘图技术防闪烁
摘自:http://zhy1987819.blog.163.com/blog/static/841427882011614103454335/ MFC绘制动态曲线,用双缓冲绘图技术防闪烁 2011 ...
- MFC--自己优化滚动条的双缓冲绘图方法
2010-01-09 18:45 MFC--自己优化的双缓冲绘图方法 自己通过尝试,用修改视图坐标的方法, 优化了双缓冲绘图,实现起来并不复杂. 在介绍这个方法前,重新介绍一下窗口和视口的概念 ...
- [Qt2D绘图]-06QPainter的复合模式&&双缓冲绘图&&绘图中的其他问题
本篇读书笔记主要记录QPainter的复合模式&&双缓冲绘图&&绘图中的其他问题 大纲: 复合模式 双缓冲绘图 绘图中的其他问题 ...
随机推荐
- STL之list(双向链表)
一,概述 List将元素按顺序储存在链表中. 与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢. list 不仅是一个双向链表,而且是一个环状双向链表 二,使用 #incl ...
- [C++参考]私有成员变量的理解
私有成员变量的概念,在脑海中的现象是,以private关键字声明,是类的实现部分,不对外公开,不能在对象外部访问对象的私有成员变量. 然而,在实现拷贝构造函数和赋值符函数时,在函数里利用对象直接访问了 ...
- PHP学习笔记9-生成图片
用PHP代码在网页上生成图片 <?php /** * Created by PhpStorm. * User: Administrator * Date: 2015/6/29 * Time: 2 ...
- QT学习 之 三维饼图绘制
QT里没有相应统计图形的绘制组件 只有手工自己画 效果如图 void aaq::paintEvent( QPaintEvent* ev ) { QPainter painter(this); // 去 ...
- Nginx Rewrite规则初探(转)
Nginx rewrite(nginx url地址重写)Rewrite 主要的功能就是实现URL的重写,Nginx的Rewrite规则采用Pcre,perl兼容正则表达式的语法规则匹配,如果需要Ng ...
- LINUX下使用crontab进行RMAN备份实验
之前写了脚本,手动执行可以,使用crontab总是无法运行成功,今天下午花了两个小时实验,完成如下: 注意事项:脚本完成首先手动执行,确定可以正常执行. 在crontab中使用,要注意以下几点: 1. ...
- setuptools,easy_install使用
当需要安装第三方python包时,可能会用到easy_install命令.easy_install是由PEAK(Python Enterprise Application Kit)开发的setupto ...
- 【操作系统】:Main features of the X86-64
The combination of the new hardware supplied by Intel and AMD ,and the new versions of GCC targeting ...
- fstream,ifstream,ofstream 详解与用法
fstream,istream,ofstream 三个类之间的继承关系 fstream :(fstream继承自istream和ofstream)1.typedef basic_fstream< ...
- 高级爬虫工程师(Spider)-美团网-拉勾网-最专业的互联网招聘平台
高级爬虫工程师(Spider)-美团网-拉勾网-最专业的互联网招聘平台 高级爬虫工程师(Spider)