最近在做一个物体移动的程序,使用的CDC贴图这些原始手段来完成了,结果很不理想,物体移动很迟缓不流畅;在一个测试中发现,本该3秒钟内完成的速成,最后用了24秒,经过多方查找,最后发现慢在Bitblt这个函数上,因为我其它地方都不变,仅将Bitblt函数屏蔽掉,程序就正好在3秒钟内完成,这才发现Bitblt这个函数效率根本就跟不上快速高频的物体移动处理上,如果,我想在一秒钟内完成物体100次移动,用Bitblt这个函数根本无法实现。
还是先来看下我的代码:
void CPeopleMove::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect rcWnd;
CWnd::GetClientRect(rcWnd);
//创建内存(兼容)DC
CDC m_bkMemDC;
m_bkMemDC.CreateCompatibleDC(&dc); //创建兼容位图
CBitmap btScreen;
btScreen.CreateCompatibleBitmap(&dc, rcWnd.Width(), rcWnd.Height()); //将该位图加入到内存DC中
m_bkMemDC.SelectObject(&btScreen);
btScreen.DeleteObject();
//OnDrawing(&m_bkMemDC, rcWnd); dc.BitBlt(rcWnd.left,rcWnd.top,rcWnd.Width(),rcWnd.Height(),&m_bkMemDC,0,0,SRCCOPY);
m_bkMemDC.DeleteDC(); // Do not call CWnd::OnPaint() for painting messages
} 程序设计上是用3秒钟对上面OnPaint函数进行三千次执行完成移动绘制,但事实上却用了24秒钟,后来我将OnPaint中dc.BitBlt语句屏蔽掉,三千次OnPaint执行正好费时3秒,所以问题出现在BitBlt函数上,BitBlt函数占用了大量执行时间。使得绘制频率低,人物移动慢。现在不知道用什么办法才好。
面对这样的问题,不知道大家有什么好的解决办法,是不是MFC的CDC类无法完成这样的快速移动绘制,难道要用其它什么技术?希望有熟悉这方面的朋友给与指点,感激!
还是先来看下我的代码:
void CPeopleMove::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect rcWnd;
CWnd::GetClientRect(rcWnd);
//创建内存(兼容)DC
CDC m_bkMemDC;
m_bkMemDC.CreateCompatibleDC(&dc); //创建兼容位图
CBitmap btScreen;
btScreen.CreateCompatibleBitmap(&dc, rcWnd.Width(), rcWnd.Height()); //将该位图加入到内存DC中
m_bkMemDC.SelectObject(&btScreen);
btScreen.DeleteObject();
//OnDrawing(&m_bkMemDC, rcWnd); dc.BitBlt(rcWnd.left,rcWnd.top,rcWnd.Width(),rcWnd.Height(),&m_bkMemDC,0,0,SRCCOPY);
m_bkMemDC.DeleteDC(); // Do not call CWnd::OnPaint() for painting messages
} 程序设计上是用3秒钟对上面OnPaint函数进行三千次执行完成移动绘制,但事实上却用了24秒钟,后来我将OnPaint中dc.BitBlt语句屏蔽掉,三千次OnPaint执行正好费时3秒,所以问题出现在BitBlt函数上,BitBlt函数占用了大量执行时间。使得绘制频率低,人物移动慢。现在不知道用什么办法才好。
面对这样的问题,不知道大家有什么好的解决办法,是不是MFC的CDC类无法完成这样的快速移动绘制,难道要用其它什么技术?希望有熟悉这方面的朋友给与指点,感激!
上D3D吧,终极方案。 :)
=========================================================
1000次/秒,人眼根本无法识别,可变相减少更新次数不必要的重复操作可简化
Bitblt是CDI中最快的了
如果还没能接受恐怕要想其他方法了
第一,我也不是一定要一千次,只是保证我画面流畅就行,没法实现。
第二,我的rcWnd并不每次都变,我也不想每次都在Onpaint中创建兼容位图,但是我不这样做又该怎样做呢?
第三,创建一个兼容位图btScreen是为了准备一个内存m_bkMemDC,我将所有的绘制都在m_bkMemDC上完成,最后再将m_bkMemDC上的内容贴到桌面DC上,所以在准备好m_bkMemDC后,我就将btScreen删除了,后面bitblt的是m_bkMemDC上的内容。 还有,为了难证你的观点,我将
//创建兼容位图
// CBitmap btScreen;
// btScreen.CreateCompatibleBitmap(&dc, rcWnd.Width(), rcWnd.Height()); //将该位图加入到内存DC中
// m_bkMemDC.SelectObject(&btScreen);
// btScreen.DeleteObject();
这四位语句全屏蔽后,程序绘制不出任何东西,一片白色,但是时间到准确了,只用了3秒钟;
三楼的说法很正确,你有双缓冲的思想,但是根本就没发挥出来,因为你的内存DC是在onPaint才创建的,这样效率会大降,真正的双缓冲OnPaint(),里面应该只要 BitBlt就行了,你试着把那段代码移出去,自己创建计时器然后重绘。
CDC *pDC = this->GetDC();;
CBitmap bitmap;
dc.CreateCompatibleDC(pDC);
GetClientRect(rClient); // 初始化的时候得到客户区大小,然后在改变的时候再获取客户区大小
bitmap.CreateCompatibleBitmap(pDC, rClient.Width(), rClient.Height());
....
void *******::OnTimer()
{
if (nIDEvent == 1)
{
...
pDC->BitBlt(0, 0, rClient.Width(), rClient.Height()-25, &dc, 0, 0, SRCCOPY);
}
}void *******::OnDestroy()
{
CDialog::OnDestroy(); ReleaseDC(&dc);
ReleaseDC(pDC);
}适当调整,具体什么时候创建DC,什么时候绘制
不就是10毫秒贴一次了吗。。哈哈
而且我还发现两个问题:
第一,就是程序运行时,我将鼠标在绘图显示窗口上不停移动时,明显感觉人物移动快很多。感觉鼠标移动好象提搞了程序进程级别一样,程序运行速度明显提高,所以绘图也变得更快了,由原来的24秒提高到10秒内完成。不知道为何?
第二,dc.BitBlt(rcWnd.left,rcWnd.top,rcWnd.Width(),rcWnd.Height(),&m_bkMemDC,0,0,SRCCOPY);
中,我将rcWnd大小手动设置的越来越小时,程序运行的也越来越快,感觉还是bitblt存在效率问题。