双缓冲技术(基于GDI+实现)
http://blog.csdn.net/woaisia/article/details/46788965
http://blog.csdn.net/woaisia/article/details/46788965
设置对话框背景色
SetBackgroundColor(RGB(0,0,255));
SetBackgroundColor(RGB(0,0,255));
一、GDI+初始化
(1)、引用stdafx.h
#include <GdiPlus.h>
using namespace Gdiplus;
#pragma comment( lib, "Gdiplus.lib")
(2)、public CWinApp头文件定义两个全局变量
GdiplusStartupinput m_Gdiplus
ULONG_PTR m_pGdiToken
(3)、在应用程序或对话框初始化时加载GDI+(InitInstance)
GdiplusStartup(&m_pGdiToken,&m_Gdiplus,NULL)
(4)、在应用程序结束时卸载GDI+(ExitInstance)
GdiplusShutdown(m_pGdiToken)
二、简单的GDI+双缓冲的分析与实现
1.在内存中建立一块“虚拟画布”:
//获取窗口客区宽高
RECT r;
GetClientRect(m_hWnd,&r);
m_bufW=r.right; m_bufH=r.bottom;
//在内存中建立一个Image的派生类Bitma对象做为"画布"
Bitmap memBitmap(m_bufW,m_bufH);
2.获取这块内存画布的Graphics引用:
Graphics memGr(&memBitmap);
3.在这块内存画布上绘图:
//这里可以通过memGr在memBitmap上绘制多个图元
//我只举例绘制了一张图片
Image* pimage=NULL;
pimage=new Image(L"res//图片1.png");
int w=pimage->GetWidth();
int h=pimage->GetHeight();
memGr.DrawImage(pimage,0,0,0,0,w,h,UnitPixel);
delete pimage;
pimage=NULL;
4、将内存画布画到窗口中
m_hDC = GetDC(m_hWnd);
Graphics gr(m_hDC);
gr.DrawImage(&memBitmap,0,0);
ReleaseDC(m_hWnd,m_hDC);
三、背景透明
//1///
CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
CMyListCtrl *pParent = (CMyListCtrl*)GetParent();
CWnd *pParent = GetParent();
CRect rc;
GetWindowRect(rc);
pParent->ScreenToClient(rc);
pParent->InvalidateRect(rc,false);
pParent->UpdateWindow();
CDC *dcParent = pParent->GetDC();
pDC->BitBlt(0,0,rc.Width(),rc.Height(),dcParent,rc.left,rc.top,SRCCOPY);
pParent->ReleaseDC(dcParent);
return true;
}
/2
::OnEraseBkgnd(CDC* pDC)
{
if (m_Bmp.GetSafeHandle() == NULL)
{
CRect Rect;
GetWindowRect(&Rect);
CWnd *pParent = GetParent();
ASSERT(pParent);
pParent->ScreenToClient(&Rect); //convert our corrdinates to our parents
//copy what's on the parents at this point
CDC *pDC = pParent->GetDC();
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
m_Bmp.CreateCompatibleBitmap(pDC,Rect.Width(),Rect.Height());
CBitmap *pOldBmp = MemDC.SelectObject(&m_Bmp);
MemDC.BitBlt(0,0,Rect.Width(),Rect.Height(),pDC,Rect.left,Rect.top,SRCCOPY);
MemDC.SelectObject(pOldBmp);
pParent->ReleaseDC(pDC);
}
else //copy what we copied off the parent the first time back onto the parent
{
CRect Rect;
GetClientRect(Rect);
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap *pOldBmp = MemDC.SelectObject(&m_Bmp);
pDC->BitBlt(0,0,Rect.Width(),Rect.Height(),&MemDC,0,0,SRCCOPY);
MemDC.SelectObject(pOldBmp);
}
return TRUE;
}
3//
HBRUSH CMFCDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
//这种情况除非背景是纯色才行
/* if(nCtlColor == CTLCOLOR_BTN)
{
pDC->SetBkMode(TRANSPARENT);
hbr = (HBRUSH) ::GetStockObject(NULL_BRUSH);
} */
//没办法,搞一个万能的。很奇怪,在背景是图片的情况下,nCtlColor都不等于CTLCOLOR_BTN了,但经过断点可以肯定,
//每个控件都会进入这个消息
UINT id = pWnd->GetDlgCtrlID();
if(id == IDC_RADIO1 || id == IDC_CHECK1|| id== IDC_LIST1)
{
pDC->SetBkMode(TRANSPARENT);
CRect rc;
pWnd->GetWindowRect(&rc);
ScreenToClient(&rc);
CDC* dc = GetDC();
pDC->BitBlt(0,0,rc.Width(),rc.Height(),dc,rc.left,rc.top,SRCCOPY); //把父窗口背景图片先画到按钮上
ReleaseDC(dc);
hbr = (HBRUSH) ::GetStockObject(NULL_BRUSH);
}
return hbr;
}
四、GDI+双缓冲
方案1
CDC dcMemory;
dcMemory.CreateCompatibleDC(&dc);
CBitmap bmp;
bmp.CreateCompatibleBitmap(&dc,1024,768);
dcMemory.SelectObject(&bmp);
Graphics _Graphics(dcMemory.m_hDC);
Gdiplus::Image image(_T("res//asus.png"));
_Graphics.DrawImage(&image,0,0,1024,768);
//这是在GDI+中的写法。
dc.BitBlt(0,0,1024,768,&dcMemory,0,0,SRCCOPY);
_Graphics.ReleaseHDC(dcMemory.m_hDC);
dcMemory.DeleteDC();
bmp.DeleteObject();
方案2(不可取)
(1)在内存中新建画布
Bitmap bmp=new Bitmap(600,600);
(2)获取这块内存画布的Graphics引用
Graphics g=Graphics.FromImage(bmp);
(3)在这块内存画布上绘图
g.FillEllipse(brush,10,10,10,10);
(4)将内存画布画到窗口
Graphics graphice(dc.m_hDC);
graphics.DrawImage(&bmp,rect.left,rect.top,rect.right,rect.bottom);
五、 资源加载方法
CGdiPlusBitmapResource* pBitmap = new CGdiPlusBitmapResource;
if (pBitmap->Load(IDB_LOGO, _T("PNG")))
{
CClientDC dc(this);
Gdiplus::Graphics graphics(dc);
graphics.DrawImage(*pBitmap, 0, 0);
}
else
{
//AfxMessageBox("Failure loading image");
}
delete pBitmap;
*/
/
//picture控件 type=Owner Draw
/*
//第一种,显示实际png图片,与控件大小无关
//CPaintDC *pDC = new CPaintDC(GetDlgItem(IDC_STATIC_PIC));也可以
CClientDC *pDC = new CClientDC(GetDlgItem(IDC_STATIC_PIC));
CRect rect;
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
Graphics graphics(pDC->m_hDC); // Create a GDI+ graphics object
Image image(_T("1.png")); // Construct an image
graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());
delete pDC;
*/
//
/*
//第二种,铺满控件
Image image(_T("1.png")); //载入指定路径的图像文件
CWnd* pwnd = GetDlgItem(IDC_STATIC_PIC);//IDC_PIC 为图像控件的 ID
CDC* dc = pwnd->GetDC(); //获取图像控件的设备上下文
CRect rect;
pwnd->GetClientRect(&rect); //获取客户区域的信息
Graphics graph(dc->GetSafeHdc());
graph.DrawImage(&image, 0, 0, rect.Width(), rect.Height()); //在指定图像控件的区域中绘制图像
ReleaseDC(dc); //释放资源
*/
///
/*方法二
CBrush m_brBk;
CPaintDC dc(this);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);//这个IDB_BITMAP1要自己添加;
m_brBk.CreatePatternBrush(&bitmap);
CBrush* pOldBrush= dc.SelectObject(&m_brBk);
dc.Rectangle(0, 0, 200, 200);// 这些参数可以调整图片添加位置和大小 dc.SelectObject(pOldBrush);
*/
/*方法三
CPaintDC dc(this);
CBitmap m_bmpBK;
m_bmpBK.LoadBitmap(IDB_BITMAP1);
CRect rect;
GetClientRect(&rect);//获得目标尺寸即窗口客户区的坐标
BITMAP bitMap;//位图结构体
m_bmpBK.GetBitmap(&bitMap);//获得原图片尺寸
CDC dcMem; //目标DC
dcMem.CreateCompatibleDC(&dc); //创建与dc兼容的内存DC
dcMem.SelectObject(&m_bmpBK);//将位图对象m_bmpBK选入内存DC
dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 0, 0, bitMap.bmWidth, bitMap.bmHeight, SRCCOPY);
*/
/*方法四
HANDLE m_hBmp;
CPaintDC dc(this); // 用于绘制的设备上下文
m_hBmp = LoadImage(NULL, _T("Demo.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
CBitmap bmp;//定义位图对象
bmp.Attach(m_hBmp);//将位图关联到位图句柄
CDC memDC;//定义一个设备上下文
memDC.CreateCompatibleDC(&dc);//创建兼容性的设备上下文
memDC.SelectObject(&bmp);//选中位图对象
BITMAP BitInfo; //定义位图结构
bmp.GetBitmap(&BitInfo);//获取位图信息 //获取位图信息
int x = BitInfo.bmWidth; //获取位图宽度
int y = BitInfo.bmHeight; //获取位图高度
dc.BitBlt(0, 0, x, y, &memDC, 0, 0, SRCCOPY);//绘制位图
bmp.Detach();//分离位图句柄
memDC.DeleteDC();//释放设备上下文
bmp.DeleteObject();//释放位图对象
*/