前言:GDI+很好用,但要将所有图像混合,必须要用到UpdateLayeredWindow,但UpdateLayeredWindow注定每次刷新都要刷新整个窗体,也就是说,哪怕我们只是改变的只是一个像素,也都要重新绘制整个窗体,就没有像GDI中那样有区域裁剪的功能,真无语了,搜遍整个网络也没找到UpdateLayeredWindow的局部刷新方案,最后想到在MFC中是可以使用GDI+的,而MFC中的刷新方案就是局部刷新的,这说明,利用GDI的函数bitblt或alphaBlend是可以整合GDI+的,最后尝试了一下,成功了,下面分享给大家。
本文摘要:这个工程是在第一篇《WIN32界面开发之一:初试加载背景界面》的基础上讲解的,所有请大家先看看第一篇,这篇内容实现的效果是,建立一个背景图案,在图案上模拟一个按钮,按钮原是红色块,当点击按钮的时候,变成绿色色块,鼠标弹起时,还原为红色色块。
思想:首先,在第一次创建工程时,我们在在兼容DC绘图,并把这个DC保存起来,当下次重绘时,重新创建一个兼容DC,用AlphaBlend将我们保存的原兼容DC上的内容复制到当前的兼容DC上,然后再在要更新的区域重新画图就是了,这里我们只需要更新按钮的区域。
一、几个全局变量
HDC hdcBKMemory=NULL;//兼容DC HBITMAP hBKBitmap=NULL;//兼容DC上的画布 HGDIOBJ hBKBitmapOld=NULL;//被选出的原兼容DC上的默认画布二、背景兼容DC的初次创建与释放
我们先看创建的代码:
HDC hDC = ::GetDC(m_hWnd); if (hdcBKMemory==NULL) { hdcBKMemory = CreateCompatibleDC(hDC); //创建背景画布 BITMAPINFOHEADER stBmpInfoHeader = { 0 }; int nBytesPerLine = ((sizeWindow.cx * 32 + 31) & (~31)) >> 3; stBmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); stBmpInfoHeader.biWidth = sizeWindow.cx; stBmpInfoHeader.biHeight = sizeWindow.cy; stBmpInfoHeader.biPlanes = 1; stBmpInfoHeader.biBitCount = 32; stBmpInfoHeader.biCompression = BI_RGB; stBmpInfoHeader.biClrUsed = 0; stBmpInfoHeader.biSizeImage = nBytesPerLine * sizeWindow.cy; PVOID pvBits = NULL; hBKBitmap = ::CreateDIBSection(NULL, (PBITMAPINFO)&stBmpInfoHeader, DIB_RGB_COLORS, &pvBits, NULL, 0); assert(hBKBitmap != NULL); hBKBitmapOld = ::SelectObject( hdcBKMemory, hBKBitmap); //gdi+画图 Gdiplus::Graphics graph(hdcBKMemory); graph.SetSmoothingMode(Gdiplus::SmoothingModeNone); graph.DrawImage(pImage, 0, 0, sizeWindow.cx, sizeWindow.cy); graph.FillRectangle(&SolidBrush(Color::Green),10,10,25,25); graph.FillRectangle(&SolidBrush(Color::Red),100,50,30,30);//模拟按钮 graph.ReleaseHDC(hdcBKMemory); }讲解:上面的代码比较简单,首先是用CreateDIBSection创建一个设备相关位置(DDB),然后将位图选入到背景兼容DC(hdcBKMemory)中,后面就是用GDI+在这个DC上画图。
case WM_DESTROY: PostQuitMessage(100); delete pImage; ::SelectObject( hdcBKMemory, hBKBitmapOld); //不要把默认的位图选回来,如果选回来的话,我们新建的位图就被替换掉了,当然我们上面画的东东也就没有了 ::DeleteObject(hBKBitmapOld); ::DeleteObject(hBKBitmap); ::DeleteDC(hdcBKMemory); break;三、新建一个兼容DC与画布,将背景复制到上面,并且在当前画布上画上按钮正常状态
HDC hdcEnd = CreateCompatibleDC(hDC);//新建兼容DC BITMAPINFOHEADER stBmpInfoHeader2 = { 0 }; int nBytesPerLine2 = ((sizeWindow.cx * 32 + 31) & (~31)) >> 3; stBmpInfoHeader2.biSize = sizeof(BITMAPINFOHEADER); stBmpInfoHeader2.biWidth = sizeWindow.cx; stBmpInfoHeader2.biHeight = sizeWindow.cy; stBmpInfoHeader2.biPlanes = 1; stBmpInfoHeader2.biBitCount = 32; stBmpInfoHeader2.biCompression = BI_RGB; stBmpInfoHeader2.biClrUsed = 0; stBmpInfoHeader2.biSizeImage = nBytesPerLine2 * sizeWindow.cy; PVOID pvBits2 = NULL; HBITMAP hbmpMem2 = ::CreateDIBSection(NULL, (PBITMAPINFO)&stBmpInfoHeader2, DIB_RGB_COLORS, &pvBits2, NULL, 0);//新建画布 HGDIOBJ hEndBitmapOld=SelectObject(hdcEnd,hbmpMem2); POINT ptSrc = { 0, 0}; BLENDFUNCTION blendFunc; blendFunc.BlendOp = 0; blendFunc.BlendFlags = 0; blendFunc.AlphaFormat = 1; blendFunc.SourceConstantAlpha = 255;//AC_SRC_ALPHA ::AlphaBlend(hdcEnd,0,0,sizeWindow.cx,sizeWindow.cy,hdcBKMemory,0,0,sizeWindow.cx,sizeWindow.cy,blendFunc);//将背景复制到新画布上 Graphics graph2(hdcEnd); if (inBtnRect)//这个变量下面讲解 { graph2.FillRectangle(&SolidBrush(Color::Green),100,50,30,30);//按钮按下状态 }else{ graph2.FillRectangle(&SolidBrush(Color::Red),100,50,30,30);//按钮正常状态 } POINT ptWinPos = { rcWindow.left, rcWindow.top }; //UpdateLayeredWindow HMODULE hFuncInst = LoadLibrary(_T("User32.DLL")); typedef BOOL (WINAPI *MYFUNC)(HWND, HDC, POINT*, SIZE*, HDC, POINT*, COLORREF, BLENDFUNCTION*, DWORD); MYFUNC UpdateLayeredWindow; UpdateLayeredWindow = (MYFUNC)::GetProcAddress(hFuncInst, "UpdateLayeredWindow"); //不会发送 WM_SIZE和WM_MOVE消息 if(!UpdateLayeredWindow(m_hWnd, hDC, &ptWinPos, &sizeWindow, hdcEnd, &ptSrc, 0, &blendFunc, ULW_ALPHA)) { assert(L"UpdateLayeredWindow 调用失败"); TCHAR tmp[255] = {_T('\0')}; }//使用UpdateLayeredWindow更新到当前窗体上 //释放资源 graph2.ReleaseHDC(hdcEnd); SelectObject(hdcEnd,hEndBitmapOld); ::DeleteObject(hFuncInst); ::DeleteObject(hEndBitmapOld); ::DeleteObject(hbmpMem2); ::DeleteDC(hdcEnd); ::DeleteDC(hDC);
讲解:这段代码看起来比较长,但主要是这么个流程:
1、创建新的兼容DC
2、创建画布并将此画布选到当前的兼容DC中,准备做画
3、应用AlphaBlend将原背景复制到当前画布中,这时当前的兼容DC就具有了背景图案
4、在原背景图案上画上按钮
5、最后利用UpdateLayeredWindow将最终的图案复制到当前的窗体上
运行后的软件图案是这样的:
4、添加按钮及响应
1、添加当前按钮状态的变量(全局变量)
bool inBtnRect=false;//存储当前按钮是否是被按下,FALSE是没被按下,TRUE是按下2、在WM_LBUTTONDOWN中添加以下代码
case WM_LBUTTONDOWN: { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; RectF btnRectf(100,50,30,30); if (btnRectf.Contains(pt.x,pt.y)) { inBtnRect=true; SendMessage(hwnd,WM_PAINT,NULL,NULL); SetCapture(hwnd); } } break;讲解:
case WM_LBUTTONUP: { if (inBtnRect) { ReleaseCapture(); inBtnRect=false; SendMessage(hwnd,WM_PAINT,NULL,NULL); } } break;讲解:主要是释放焦点,把inBtnRect设置成FALE,并且重绘窗体;
与往常一样,源码地址:http://download.csdn.net/detail/harvic880925/5770565
转载请标明出处哦:http://blog.csdn.net/harvic880925/article/details/9355741
声明:软件所用图片来于网络,感谢金山影音漂亮的界面图片