44 个解决方案
#2
这个用双CDC,闪烁的问题应该就可以解决
#5
这个才是问题的实质,只要能得到波形显示的数据,显示不是什么问题的
#6
求柱状图闪烁的解决之道
#7
在网上看到很多人推荐使用CMEMDC这个类,我用了还是一样的闪。CMEMDC操作的是OFF-SCREEN,那应该有个前后LCD BUFFER的交换啊?但在网上没看到他们是怎么交换的(SWAP)。
#8
闪烁的问题用双缓冲就能解决。
#9
双缓冲技术有几个CDC类?三个?
1。一个源CDC-----比如对话框显示----要操作的CDC
2。一个备用缓冲CDC---用来存储整个将来要显示的源CDC的内容
3。一个小图CDC-----不断地选入小图并COPY到备用缓冲CDC里面
最后就是把准备好(画好一个个小图)的备用缓冲CDC一次性BITBLT到源CDC显示------双缓冲技术的原理是不是这样的???
#10
双缓冲技术及其在VC的GDI环境下的实现
http://www.bigwww.com/info/html/edu/20071229/79251.html
双缓冲技术的例子程序下载
http://www.pudn.com/downloads115/sourcecode/embed/detail486704.html
http://www.bigwww.com/info/html/edu/20071229/79251.html
双缓冲技术的例子程序下载
http://www.pudn.com/downloads115/sourcecode/embed/detail486704.html
#11
最关键的是找个可靠的第三方控件。
试试vs2005添加NI公司(labview)显示柱状图控件
试试vs2005添加NI公司(labview)显示柱状图控件
#12
WINCE下这样的想法不现实!!!
#13
MFC制作双缓冲无闪烁的字幕滚动条
http://zjyzjy.blog.51cto.com/329429/67390
MFC双缓冲解决图象闪烁
http://www.diybl.com/course/3_program/c++/cppjs/200867/123361.html
C++技巧(VC++双缓冲实现方法)
http://www.china-b.com/kaoshi/kjsj/20090317/944145_1.html
http://zjyzjy.blog.51cto.com/329429/67390
MFC双缓冲解决图象闪烁
http://www.diybl.com/course/3_program/c++/cppjs/200867/123361.html
C++技巧(VC++双缓冲实现方法)
http://www.china-b.com/kaoshi/kjsj/20090317/944145_1.html
#14
我以为你是用vs2005做上位机显示界面 跟wince的下位机通讯
在wince下加NI控件肯定不行的 呵呵
在wince下加NI控件肯定不行的 呵呵
#15
LZ多少时间更新一次频谱呢?
我以前做的一秒更新一次,在CE5.0(CPU: <400MHz)上,使用双缓冲没有出现闪烁的问题。
我以前做的一秒更新一次,在CE5.0(CPU: <400MHz)上,使用双缓冲没有出现闪烁的问题。
#16
100ms更新一次
#17
这样不会太慢了?
#18
是慢一些,自己做来玩的,当时只要求波形正确就OK
#19
我觉得我已经用了双缓冲技术了,但还是闪烁!
#20
LZ就不能将这部分代码展示出来吗?
#21
我写的代码如下,大家帮我看看,那里有问题!
void CXXXDlg::OnPaint()
{
CPaintDC dc(this);
int i;
RECT rect;
CDC *mydc=CDC::FromHandle(dc.m_hDC);
CDC dcMemory;
dcMemory.CreateCompatibleDC(mydc);
CBitmap* pOldBitmap;
CBitmap* pBitmap=new CBitmap( );
CRect rect1;
GetClientRect(&rect1);
pBitmap->CreateCompatibleBitmap(mydc, rect1.Width( ), rect1.Height( ) ); //产生画布
pOldBitmap=dcMemory.SelectObject(pBitmap); //选进画布
for(i=0;i<10;i++) //10段频谱数据,mCurrentValue[i]为存储10段频谱数据的数组
{
rect.left=m_Equal_Rect[i].left;
rect.right=m_Equal_Rect[i].right;
rect.top=m_Equal_Rect[i].top+(210-mCurrentValue[i]); //按要求得到柱状图的RECT大小
rect.bottom=m_Equal_Rect[i].bottom;
dcMemory.FillRect(&rect,&CBrush( RGB(240,115,11) ) ); //对柱状图RECT区域填充颜色
}
//2009--6--8 XQH 进行一次性的BITBLT操作!!!
dc.BitBlt(115,10,685-115,220-10,&dcMemory,115,10,SRCCOPY); //只COPY画布上的部分内容去显示
dcMemory.SelectObject(pOldBitmap);
dcMemory.DeleteDC();
pBitmap->DeleteObject();
delete pBitmap;
pBitmap=NULL;
}
#22
顶起来一下,网上很多的例子都跟我的差不多啊!
#23
网上很多双缓存的帖子
有时候不是双缓存的问题,解决闪的问题的本质就是减少刷新的频率
双缓存也占资源
有时候不是双缓存的问题,解决闪的问题的本质就是减少刷新的频率
双缓存也占资源
#24
没看出什么问题
试试不要创建: CDC *mydc=CDC::FromHandle(dc.m_hDC);
直接使用dc
试试不要创建: CDC *mydc=CDC::FromHandle(dc.m_hDC);
直接使用dc
#25
直接用DC是黑白的!!!
#26
//请看这篇文章---------------
在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。
一、普通方法:
先按普通做图的方法进行编程。即在视类的OnDraw函数中添加绘图代码。在此我们绘制若干同心圆,代码如下:
CBCDoc pDoc = GetDocument();
ASSERT_VALID(pDoc);
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
for(int i=20;i0;i--)
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
pDC-Ellipse(ellipseRect);
}
编译运行程序,尝试改变窗口大小,可以发现闪烁现象。
二、双缓冲方法:
在双缓冲方法中,首先要做的是屏蔽背景刷新。背景刷新其实是在响应WM_ERASEBKGND消息。我们在视类中添加对这个消息的响应,可以看到缺省的代码如下:
BOOL CMYView::OnEraseBkgnd(CDC pDC)
{
return CView::OnEraseBkgnd(pDC);
}
是调用父类的OnEraseBkgnd函数,我们屏蔽此调用,只须直接return TRUE;即可。
下面是内存缓冲作图的步骤。
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
CDC dcMem; //用于缓冲作图的内存DC
CBitmap bmp; //内存中承载临时图象的位图
dcMem。CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC
bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());//创建兼容位图
dcMem。SelectObject(bmp); //将位图选择进内存DC
//按原来背景填充客户区,不然会是黑色
dcMem。FillSolidRect(rect,pDC-GetBkColor());
for(int i=20;i0;i--) //在内存DC上做同样的同心圆图象
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
dcMem。Ellipse(ellipseRect);
}
pDC-BitBlt(0,0,rect。Width(),rect。Height(),
dcMem,0,0,SRCCOPY);//将内存DC上的图象拷贝到前台
dcMem。DeleteDC(); //删除DC
bm。DeleteObject(); //删除位图
由于复杂的画图操作转入后台,我们看到的是速度很快的复制操作,自然也就消除了闪烁现象。
注意:bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());
这里面CreateCompatibleBitmap第一个参数不能用dcMem,这样的话创建的是黑白位图。考试大提示:如果你要创建彩色位图,需要用pDC,它用来创建了内存DC。 详细请见下面的MSDN:
When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it。 If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap。 To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:
HDC memDC = CreateCompatibleDC ( hDC );
HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
SelectObject ( memDC, memBM );
在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。
一、普通方法:
先按普通做图的方法进行编程。即在视类的OnDraw函数中添加绘图代码。在此我们绘制若干同心圆,代码如下:
CBCDoc pDoc = GetDocument();
ASSERT_VALID(pDoc);
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
for(int i=20;i0;i--)
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
pDC-Ellipse(ellipseRect);
}
编译运行程序,尝试改变窗口大小,可以发现闪烁现象。
二、双缓冲方法:
在双缓冲方法中,首先要做的是屏蔽背景刷新。背景刷新其实是在响应WM_ERASEBKGND消息。我们在视类中添加对这个消息的响应,可以看到缺省的代码如下:
BOOL CMYView::OnEraseBkgnd(CDC pDC)
{
return CView::OnEraseBkgnd(pDC);
}
是调用父类的OnEraseBkgnd函数,我们屏蔽此调用,只须直接return TRUE;即可。
下面是内存缓冲作图的步骤。
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
CDC dcMem; //用于缓冲作图的内存DC
CBitmap bmp; //内存中承载临时图象的位图
dcMem。CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC
bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());//创建兼容位图
dcMem。SelectObject(bmp); //将位图选择进内存DC
//按原来背景填充客户区,不然会是黑色
dcMem。FillSolidRect(rect,pDC-GetBkColor());
for(int i=20;i0;i--) //在内存DC上做同样的同心圆图象
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
dcMem。Ellipse(ellipseRect);
}
pDC-BitBlt(0,0,rect。Width(),rect。Height(),
dcMem,0,0,SRCCOPY);//将内存DC上的图象拷贝到前台
dcMem。DeleteDC(); //删除DC
bm。DeleteObject(); //删除位图
由于复杂的画图操作转入后台,我们看到的是速度很快的复制操作,自然也就消除了闪烁现象。
注意:bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());
这里面CreateCompatibleBitmap第一个参数不能用dcMem,这样的话创建的是黑白位图。考试大提示:如果你要创建彩色位图,需要用pDC,它用来创建了内存DC。 详细请见下面的MSDN:
When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it。 If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap。 To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:
HDC memDC = CreateCompatibleDC ( hDC );
HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
SelectObject ( memDC, memBM );
#27
也许23L是对的,LZ试着放慢刷新速度,看看是否闪?
这只是个验证,用来发现问题的原因。
这只是个验证,用来发现问题的原因。
#28
刷新速度设置为1S一次,闪烁的现象好很多,但就是太慢了,就没动态的感觉。
#29
双缓冲,搜搜
#30
这里面CreateCompatibleBitmap第一个参数不能用dcMem,这样的话创建的是黑白位图。
吃过这个亏。当时没想过什么
在wince,用api,以前做的时候,发现用api快了30ms
吃过这个亏。当时没想过什么
在wince,用api,以前做的时候,发现用api快了30ms
#31
有意思
#32
用API比用MFC快了30MS?
#33
顶起来一下
#34
关注
还没有解决啊
还没有解决啊
#35
是啊,会闪啊!
#36
你是不是刷了背景?
#37
我在WM-ERASEBKGND里面先贴了张底图做显示的背景。
#38
在WM-ERASEBKGND里面直接返回TRUE?
#39
没用双缓冲画过。。还是用API的好,移植起来太舒服了。
#40
WM_ERASEBKGND 一定要处理,否则你那堆代码都是没用的
#41
移植了一个不错的柱形图到WINCE上。
http://www.evccode.com/ch/ProductView.asp?ID=23
http://www.evccode.com/ch/ProductView.asp?ID=23
#43
有时间好好看看,多谢!
#44
请楼主加一个我的Q:812306014。
需要请教一下!
需要请教一下!
#1
在vc2005中做柱状图!
http://topic.csdn.net/t/20060206/09/4541153.html
http://topic.csdn.net/t/20060206/09/4541153.html
#2
这个用双CDC,闪烁的问题应该就可以解决
#3
#4
#5
这个才是问题的实质,只要能得到波形显示的数据,显示不是什么问题的
#6
求柱状图闪烁的解决之道
#7
在网上看到很多人推荐使用CMEMDC这个类,我用了还是一样的闪。CMEMDC操作的是OFF-SCREEN,那应该有个前后LCD BUFFER的交换啊?但在网上没看到他们是怎么交换的(SWAP)。
#8
闪烁的问题用双缓冲就能解决。
#9
双缓冲技术有几个CDC类?三个?
1。一个源CDC-----比如对话框显示----要操作的CDC
2。一个备用缓冲CDC---用来存储整个将来要显示的源CDC的内容
3。一个小图CDC-----不断地选入小图并COPY到备用缓冲CDC里面
最后就是把准备好(画好一个个小图)的备用缓冲CDC一次性BITBLT到源CDC显示------双缓冲技术的原理是不是这样的???
#10
双缓冲技术及其在VC的GDI环境下的实现
http://www.bigwww.com/info/html/edu/20071229/79251.html
双缓冲技术的例子程序下载
http://www.pudn.com/downloads115/sourcecode/embed/detail486704.html
http://www.bigwww.com/info/html/edu/20071229/79251.html
双缓冲技术的例子程序下载
http://www.pudn.com/downloads115/sourcecode/embed/detail486704.html
#11
最关键的是找个可靠的第三方控件。
试试vs2005添加NI公司(labview)显示柱状图控件
试试vs2005添加NI公司(labview)显示柱状图控件
#12
WINCE下这样的想法不现实!!!
#13
MFC制作双缓冲无闪烁的字幕滚动条
http://zjyzjy.blog.51cto.com/329429/67390
MFC双缓冲解决图象闪烁
http://www.diybl.com/course/3_program/c++/cppjs/200867/123361.html
C++技巧(VC++双缓冲实现方法)
http://www.china-b.com/kaoshi/kjsj/20090317/944145_1.html
http://zjyzjy.blog.51cto.com/329429/67390
MFC双缓冲解决图象闪烁
http://www.diybl.com/course/3_program/c++/cppjs/200867/123361.html
C++技巧(VC++双缓冲实现方法)
http://www.china-b.com/kaoshi/kjsj/20090317/944145_1.html
#14
我以为你是用vs2005做上位机显示界面 跟wince的下位机通讯
在wince下加NI控件肯定不行的 呵呵
在wince下加NI控件肯定不行的 呵呵
#15
LZ多少时间更新一次频谱呢?
我以前做的一秒更新一次,在CE5.0(CPU: <400MHz)上,使用双缓冲没有出现闪烁的问题。
我以前做的一秒更新一次,在CE5.0(CPU: <400MHz)上,使用双缓冲没有出现闪烁的问题。
#16
100ms更新一次
#17
这样不会太慢了?
#18
是慢一些,自己做来玩的,当时只要求波形正确就OK
#19
我觉得我已经用了双缓冲技术了,但还是闪烁!
#20
LZ就不能将这部分代码展示出来吗?
#21
我写的代码如下,大家帮我看看,那里有问题!
void CXXXDlg::OnPaint()
{
CPaintDC dc(this);
int i;
RECT rect;
CDC *mydc=CDC::FromHandle(dc.m_hDC);
CDC dcMemory;
dcMemory.CreateCompatibleDC(mydc);
CBitmap* pOldBitmap;
CBitmap* pBitmap=new CBitmap( );
CRect rect1;
GetClientRect(&rect1);
pBitmap->CreateCompatibleBitmap(mydc, rect1.Width( ), rect1.Height( ) ); //产生画布
pOldBitmap=dcMemory.SelectObject(pBitmap); //选进画布
for(i=0;i<10;i++) //10段频谱数据,mCurrentValue[i]为存储10段频谱数据的数组
{
rect.left=m_Equal_Rect[i].left;
rect.right=m_Equal_Rect[i].right;
rect.top=m_Equal_Rect[i].top+(210-mCurrentValue[i]); //按要求得到柱状图的RECT大小
rect.bottom=m_Equal_Rect[i].bottom;
dcMemory.FillRect(&rect,&CBrush( RGB(240,115,11) ) ); //对柱状图RECT区域填充颜色
}
//2009--6--8 XQH 进行一次性的BITBLT操作!!!
dc.BitBlt(115,10,685-115,220-10,&dcMemory,115,10,SRCCOPY); //只COPY画布上的部分内容去显示
dcMemory.SelectObject(pOldBitmap);
dcMemory.DeleteDC();
pBitmap->DeleteObject();
delete pBitmap;
pBitmap=NULL;
}
#22
顶起来一下,网上很多的例子都跟我的差不多啊!
#23
网上很多双缓存的帖子
有时候不是双缓存的问题,解决闪的问题的本质就是减少刷新的频率
双缓存也占资源
有时候不是双缓存的问题,解决闪的问题的本质就是减少刷新的频率
双缓存也占资源
#24
没看出什么问题
试试不要创建: CDC *mydc=CDC::FromHandle(dc.m_hDC);
直接使用dc
试试不要创建: CDC *mydc=CDC::FromHandle(dc.m_hDC);
直接使用dc
#25
直接用DC是黑白的!!!
#26
//请看这篇文章---------------
在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。
一、普通方法:
先按普通做图的方法进行编程。即在视类的OnDraw函数中添加绘图代码。在此我们绘制若干同心圆,代码如下:
CBCDoc pDoc = GetDocument();
ASSERT_VALID(pDoc);
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
for(int i=20;i0;i--)
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
pDC-Ellipse(ellipseRect);
}
编译运行程序,尝试改变窗口大小,可以发现闪烁现象。
二、双缓冲方法:
在双缓冲方法中,首先要做的是屏蔽背景刷新。背景刷新其实是在响应WM_ERASEBKGND消息。我们在视类中添加对这个消息的响应,可以看到缺省的代码如下:
BOOL CMYView::OnEraseBkgnd(CDC pDC)
{
return CView::OnEraseBkgnd(pDC);
}
是调用父类的OnEraseBkgnd函数,我们屏蔽此调用,只须直接return TRUE;即可。
下面是内存缓冲作图的步骤。
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
CDC dcMem; //用于缓冲作图的内存DC
CBitmap bmp; //内存中承载临时图象的位图
dcMem。CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC
bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());//创建兼容位图
dcMem。SelectObject(bmp); //将位图选择进内存DC
//按原来背景填充客户区,不然会是黑色
dcMem。FillSolidRect(rect,pDC-GetBkColor());
for(int i=20;i0;i--) //在内存DC上做同样的同心圆图象
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
dcMem。Ellipse(ellipseRect);
}
pDC-BitBlt(0,0,rect。Width(),rect。Height(),
dcMem,0,0,SRCCOPY);//将内存DC上的图象拷贝到前台
dcMem。DeleteDC(); //删除DC
bm。DeleteObject(); //删除位图
由于复杂的画图操作转入后台,我们看到的是速度很快的复制操作,自然也就消除了闪烁现象。
注意:bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());
这里面CreateCompatibleBitmap第一个参数不能用dcMem,这样的话创建的是黑白位图。考试大提示:如果你要创建彩色位图,需要用pDC,它用来创建了内存DC。 详细请见下面的MSDN:
When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it。 If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap。 To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:
HDC memDC = CreateCompatibleDC ( hDC );
HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
SelectObject ( memDC, memBM );
在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。
一、普通方法:
先按普通做图的方法进行编程。即在视类的OnDraw函数中添加绘图代码。在此我们绘制若干同心圆,代码如下:
CBCDoc pDoc = GetDocument();
ASSERT_VALID(pDoc);
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
for(int i=20;i0;i--)
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
pDC-Ellipse(ellipseRect);
}
编译运行程序,尝试改变窗口大小,可以发现闪烁现象。
二、双缓冲方法:
在双缓冲方法中,首先要做的是屏蔽背景刷新。背景刷新其实是在响应WM_ERASEBKGND消息。我们在视类中添加对这个消息的响应,可以看到缺省的代码如下:
BOOL CMYView::OnEraseBkgnd(CDC pDC)
{
return CView::OnEraseBkgnd(pDC);
}
是调用父类的OnEraseBkgnd函数,我们屏蔽此调用,只须直接return TRUE;即可。
下面是内存缓冲作图的步骤。
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(rect);
ptCenter = rect。CenterPoint();
CDC dcMem; //用于缓冲作图的内存DC
CBitmap bmp; //内存中承载临时图象的位图
dcMem。CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC
bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());//创建兼容位图
dcMem。SelectObject(bmp); //将位图选择进内存DC
//按原来背景填充客户区,不然会是黑色
dcMem。FillSolidRect(rect,pDC-GetBkColor());
for(int i=20;i0;i--) //在内存DC上做同样的同心圆图象
{
ellipseRect。SetRect(ptCenter,ptCenter);
ellipseRect。InflateRect(i10,i10);
dcMem。Ellipse(ellipseRect);
}
pDC-BitBlt(0,0,rect。Width(),rect。Height(),
dcMem,0,0,SRCCOPY);//将内存DC上的图象拷贝到前台
dcMem。DeleteDC(); //删除DC
bm。DeleteObject(); //删除位图
由于复杂的画图操作转入后台,我们看到的是速度很快的复制操作,自然也就消除了闪烁现象。
注意:bmp。CreateCompatibleBitmap(pDC,rect。Width(),rect。Height());
这里面CreateCompatibleBitmap第一个参数不能用dcMem,这样的话创建的是黑白位图。考试大提示:如果你要创建彩色位图,需要用pDC,它用来创建了内存DC。 详细请见下面的MSDN:
When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it。 If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap。 To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:
HDC memDC = CreateCompatibleDC ( hDC );
HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
SelectObject ( memDC, memBM );
#27
也许23L是对的,LZ试着放慢刷新速度,看看是否闪?
这只是个验证,用来发现问题的原因。
这只是个验证,用来发现问题的原因。
#28
刷新速度设置为1S一次,闪烁的现象好很多,但就是太慢了,就没动态的感觉。
#29
双缓冲,搜搜
#30
这里面CreateCompatibleBitmap第一个参数不能用dcMem,这样的话创建的是黑白位图。
吃过这个亏。当时没想过什么
在wince,用api,以前做的时候,发现用api快了30ms
吃过这个亏。当时没想过什么
在wince,用api,以前做的时候,发现用api快了30ms
#31
有意思
#32
用API比用MFC快了30MS?
#33
顶起来一下
#34
关注
还没有解决啊
还没有解决啊
#35
是啊,会闪啊!
#36
你是不是刷了背景?
#37
我在WM-ERASEBKGND里面先贴了张底图做显示的背景。
#38
在WM-ERASEBKGND里面直接返回TRUE?
#39
没用双缓冲画过。。还是用API的好,移植起来太舒服了。
#40
WM_ERASEBKGND 一定要处理,否则你那堆代码都是没用的
#41
移植了一个不错的柱形图到WINCE上。
http://www.evccode.com/ch/ProductView.asp?ID=23
http://www.evccode.com/ch/ProductView.asp?ID=23
#42
#43
有时间好好看看,多谢!
#44
请楼主加一个我的Q:812306014。
需要请教一下!
需要请教一下!