CDC双缓冲绘图
一、双缓冲实现过程如下:
1、在内存中创建与画布一致的缓冲区
BufferBmp=new Graphics::TBitmap();
BufferBmp->Canvas->Handle=CreateCompatibleDC(Canvas->Handle);
BufferBmp->Width=Width;
BufferBmp->Height=Height;
2、在缓冲区画图
BufferBmp->Canvas->Brush->Color=clBtnFace;
BufferBmp->Canvas->FillRect(Rect(0,0,Width,Height));
BufferBmp->Canvas->MoveTo(…);
…………………………
3、将缓冲区位图拷贝到当前画布上
BitBlt(Canvas->Handle,0,0,Width,Height,BufferBmp->Canvas->Handle,0,0,SRCCOPY);
4、释放内存缓冲区
delete BufferBmp;
二、如何实现双缓冲
首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中:
CDC MemDC; //首先定义一个显示设备对象
CBitmap MemBitmap;//定义一个位图对象
//随后建立与屏幕显示兼容的内存显示设备
MemDC.CreateCompatibleDC(NULL);
//这时还不能绘图,因为没有地方画 ^_^
//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小
MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);
//将位图选入到内存显示设备中
//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
//先用背景色将位图清除干净,这里我用的是白色作为背景
//你也可以用自己应该用的颜色
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));
//绘图
MemDC.MoveTo(……);
MemDC.LineTo(……);
//将内存中的图拷贝到屏幕上进行显示
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);
//绘图完成后的清理
MemBitmap.DeleteObject();
MemDC.DeleteDC();
三、实例
(1)
CDC *pDC = this->GetWindowDC();
CDC* DCTemp = new CDC;
DCTemp->CreateCompatibleDC(pDC);
CBitmap* m_pTempImage = new CBitmap;
m_pTempImage->CreateCompatibleBitmap(pDC,240,320);
CBitmap* m_bitOldMap = DCTemp->SelectObject(m_pTempImage);
DCTemp->BitBlt(0,0,240,320,pDC,0,0,SRCCOPY);
pDC->BitBlt(0,0,240,320,DCTemp,0,0,SRCCOPY);
DCTemp->SelectObject(m_bitOldMap);
m_pTempImage->DeleteObject();
if (m_pTempImage)
{
delete m_pTempImage;
m_pTempImage = NULL;
}
DCTemp->DeleteDC();
ReleaseDC(pDC);
(2)
HDC hdc = ::GetDC(GetSafeHwnd());
//-------------------------------------------------
// 绘制区域背景
if (m_pImgTitle)
{
m_pImgTitle->Draw(hdc, CRect(110, 0, 240, 30), NULL);
}
//-------------------------------------------------
HFONT HFont;
InitHFont(HFont, 14);
int nMode = ::SetBkMode(hdc,TRANSPARENT);
HFONT oldHFont = (HFONT)::SelectObject(hdc, HFont);
::SetTextColor(hdc, RGB(255,255, 255));
CString strDrawText;
if (m_bIsChange && m_bWeatherIsShow)
{
strDrawText.Format(TEXT("%s %s %s"), m_cityName, m_weatherInfo, m_temperature);
}
else
{
//CTime time = CTime::GetCurrentTime();
//strDrawText = time.Format(TEXT("%H:%M:%S"));
SYSTEMTIME curTime;
GetLocalTime(&curTime);
strDrawText.Format(_T("%d:%.2d:%.2d"),curTime.wHour,curTime.wMinute,curTime.wSecond);
}
::DrawText(hdc, strDrawText, strDrawText.GetLength(), CRect(110, 0, 235, 30), DT_WORDBREAK | DT_RIGHT | DT_VCENTER);
::SetBkMode(hdc, nMode);
::SelectObject(hdc, oldHFont);
::DeleteObject(HFont);
::ReleaseDC(GetSafeHwnd(), hdc);
void InitHFont(HFONT& argFont, int argHeight)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
argFont = ::CreateFont(
argHeight, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("宋体"));
}
转自:http://panccp.blog.163.com/blog/static/265560442009415537120/
参考:http://wenku.baidu.com/view/22c68c8ca0116c175f0e4818.html
CImage显示位图与CDC双缓冲冲突,使用路径层解决.
2010年04月29日 星期四 20:35
位图闪的问题困扰我很久了,因为程序的需要,我显示位图的方式是CImage类.
如果从CImage转到CBitmap,之后使用Attach到是可以,但我发现这样之后CImage类的对象会无效.
无奈拖了很久程序一直都在闪,我的程序使用的是多文档多视图,昨天通过勾子解决了CHtmlView在子窗口中闪烁的问题,今天下决心把CScrollView使用CImage闪烁的问题也给解决.
我们知道
CImage显示位图的方式是
m_Image.Draw(pDC->m_hDC, 0, 0);
通过函数跟踪发现他也直接使用了内存绘制.
但如果我们添加使用自己的CDC比如绘制先字体,画刷等等使用内存显示的话也就是说有2个内存DC要显示.
因为不同步,存在色差所以闪烁.无奈CImage的资料太少,我也试过加载到自己定义的CDC中去,但都失败了.
我想如果我先绘制CImage,绘制后的CImage位图谁都不许动,有什么办法,那只能使用路径层.
(在设备描述表中还有一个路径层(path bracket)的概念,什么是路径层呢?路径层的概念就像当年军阀割据圈地那样,在地域上划定界线,界线之内的是各自的地盘,别人不能侵犯.)那样的话当自己的CDC绘制时就不会去动CImage已经绘制好的部分,闪烁也就解决了.
下面看代码.
void CNotesPrintView::OnDraw(CDC* pDC)
{
CNotesPrintDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rect = 0;
GetClientRect(rect);
CDC MemDC;
CBitmap MemBitmap;
MemDC.CreateCompatibleDC(pDC);
MemBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
MemDC.SelectObject(&MemBitmap);
MemDC.FillSolidRect(0,0,rect.right,rect.bottom,RGB(255,255,255));
// 上面的是一般的双缓存,大家查资料.
if (!pDoc->m_Image.IsNull())
{
pDoc->m_Image.Draw(pDC->m_hDC, 0, 0); // 绘制CImage位图
pDC->BeginPath(); // 打开路径层
pDC->Rectangle(0,0,pDoc->m_Image.GetWidth(),pDoc->m_Image.GetHeight()); // 设置路径层矩形区域
pDC->EndPath(); // 关闭路径层,关闭后谁都不能在去动这块区域了.
pDC->SelectClipPath(RGN_DIFF); // 设置裁剪模式
}
pDC->BitBlt(0,0,rect.right,rect.bottom,&MemDC,0,0,SRCCOPY); // 绘制自定定义的CDC
MemBitmap.DeleteObject();
MemDC.DeleteDC();
}
RGN_AND:新的剪切区包括当前剪切区域与当前路径的一个交集(重叠区域)。
RGN_COPY:新的剪切区域就是当前的路径。
RGN_DIFF:新的剪切区域包含除了当前路径外的当前剪切区域。
RGN_OR:新的剪切区域包含当前剪切区域与当前路径的并集。
RGN_XOR:新的剪切区域包含当前剪切区域与当前路径的并集但不包含重叠的区域。
转自:http://hi.baidu.com/250ez/blog/item/c1e5658f28698ff6503d921d.html