背景
并不是所有的gif图片显示都必须采用双缓冲,据本人实践的结果,透明背景的gif图片显示,需要双缓冲实现,而非透明背景的gif显示可能并不一定需要双缓冲,要了解如何不采用双缓冲实现gif图片的显示,可以参考我之前的文档,也可以在网上搜索一下就可以找到很多方法,从中选取适合自己的就好了。
问题来了,为什么透明背景的gif图片显示需要双缓冲呢?
这个问题涉及到透明背景图片的显示,透明背景的图片其实是显示在父窗口上的,如果在显示透明背景的图片时没有刷新父窗口,则会产生重影,但是刷新父窗口问题又来了,图片在刷新的时候会产生明显的闪烁。根据经验,遇到图片闪烁的问题,试着用双缓冲技术,问题可能会得到解决。
双缓冲原理
采用双缓冲技术,绘图时所有的操作都在缓存上进行,缓存可以看做是一块虚拟的屏幕,当在缓存上完成绘图时,再一次性复制到屏幕上,这样就看不到屏幕闪烁的现象了。
内存DC
内存DC是在内存中申请的一块内存,用于存放待绘制的图像,它只是一个单色的长宽各一个像素的显示面,必须与位图句柄建立联系才能使用。
HDC hMemDC = CreateCompatibleDC(hdc);
根据目标DC建立位图
根据MSDN,一个内存DC建立后是不能绘图的,必须给它选择一个与它高宽对应的位图,位图是多色的,这样就让内存DC成为多色的DC了。
HBITMAP hMemBmp = CreateCompatibleBitmap(hdc, wndWidth, wndHeight);
关联内存DC和位图句柄
HBITMAP hOldMem = (HBITMAP)SelectObject(hMemDC, hMemBmp);
完整代码
void _cdecl showimage(HWND hWnd)
{
HDC hdc = GetDC(hWnd);
HDC hMemDC = CreateCompatibleDC(hdc);
HBITMAP hMemBmp = CreateCompatibleBitmap(hdc, 100, 100);
HBITMAP hOldMem = (HBITMAP)SelectObject(hMemDC, hMemBmp);
Image *image = new Image(L"timg.gif");
if (image == NULL)
return;
UINT count = image->GetFrameDimensionsCount();
GUID *pDimensionIDs = (GUID*)new GUID[count];
image->GetFrameDimensionsList(pDimensionIDs, count);
WCHAR strGuid[39];
StringFromGUID2(pDimensionIDs[0], strGuid, 39);
UINT frameCount = image->GetFrameCount(&pDimensionIDs[0]);
delete[]pDimensionIDs;
int size = image->GetPropertyItemSize(PropertyTagFrameDelay);
static PropertyItem* pItem = (PropertyItem*)malloc(size);
image->GetPropertyItem(PropertyTagFrameDelay, size, pItem);
UINT fcount = 0;
GUID Guid = FrameDimensionTime;
Graphics graphics(hMemDC);
while (true)
{
// Clear hMemDC with window background color
RECT fillRc{0, 0, kInstallInterfaceWidth , kInstallInterfaceHeight };
LOGBRUSH lb;
lb.lbColor = RGB(251, 255, 242);
lb.lbStyle = BS_SOLID;
lb.lbHatch = 0;
HBRUSH brush = CreateBrushIndirect(&lb);
FillRect(hMemDC, &fillRc, brush);
graphics.DrawImage(image, 0, 0, image->GetWidth(), image->GetHeight());
//StretchBlt(hdc, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, hMemDC, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, SRCCOPY);
BitBlt(hdc, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, hMemDC, 0, 0, SRCCOPY);
image->SelectActiveFrame(&Guid, fcount++);
if (fcount == frameCount)
fcount = 0;
//long lPause = ((long*)pItem->value)[fcount] * 10;
long lPause = 100;
Sleep(lPause);
}
SelectObject(hMemDC, hOldMem);
::DeleteObject(hMemBmp);
::DeleteObject(hMemDC);
ReleaseDC(hWnd, hdc);
}
版权声明:本文为zhuiyuanqingya原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。