天天看點

【MFC系列-第23天】CMemoryDC的封裝過程23.1 LoadImage API23.2 解決閃爍問題:23.3 CMemoryDC類23.4 采用CMemoryDC類實作圖檔旋轉23.5 采用CMemoryDC類實作蝴蝶動畫

CDC(HDC)繪圖類:

五大GDI對象類:

CPen,CBrush,CFont,CBitmap,CRgn

23.1 LoadImage API

HANDLE LoadImage(
  HINSTANCE hinst,
  LPCTSTR lpszName, 
  UINT uType, 
  int cxDesired,
  int cyDesired,
  UINT fuLoad 
);
           

uType參數填寫以下三種:

IMAGE_BITMAP Loads a bitmap.
 
IMAGE_CURSOR Loads a cursor.
 
IMAGE_ICON Loads an icon
           

從HINSTANCE内部加載

void CTestImageDlg::OnBnClickedButton1()
{
	static HICON hIcon = (HICON)::LoadImage(theApp.m_hInstance, (LPCTSTR)IDI_TEST, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
	SetIcon(hIcon, TRUE);
	SetIcon(hIcon, FALSE);
	//*.cur
}


m_hBitmap = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1),
	IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);

m_hBitmap = ::LoadBitmap(theApp.m_hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
           

從檔案中直接加載

m_hBitmap =  (HBITMAP)::LoadImage(NULL, _T("./ban.bmp"),
	IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);

HICON hIcon = (HICON)::LoadImage(NULL, _T("DfIcon.ico"),
		IMAGE_BITMAP, 0, 0,  LR_LOADFROMFILE| LR_DEFAULTSIZE);
	SetIcon(hIcon, TRUE);
	SetIcon(hIcon, FALSE);
           

顯示

//CDC mdc;
//BITMAP bm;
//::GetObject(m_hBitmap, sizeof(bm), &bm);
//mdc.CreateCompatibleDC(&dc);
//mdc.SelectObject(m_hBitmap);
dc.BitBlt(10, 40, m_mdc.GetWidth(), mdc.GetHeight(), &m_mdc, 0, 0, SRCCOPY);
           

23.2 解決閃爍問題:

1、禁用非客戶區輸出,讓非客戶區

WM_NCPAINT

産生空輸出。

2、禁用客戶區背景輸出:

WM_ERASEBKGRAND

消息是

Invalidate(TRUE)

要調用的背景輸出。

3、調用Invalidate函數時,盡量使用

FALSE

4、當有多層次輸出時,使用雙緩沖技術,在記憶體中做好多次輸出的草稿。

23.3 CMemoryDC類

#ifndef __MEMDC_H__
#define __MEMDC_H__
//Author:www.baojy.com

class CMemoryDC :public CDC
{
	CSize m_size;
public:
	void BitTrans(
		int nXDest,		// 目标起點X
        int nYDest,		// 目标起點Y
        int nWidthDest,	// 目标寬度
        int nHeightDest,// 目标高度
		CDC* pDC,		// 目标DC
        int nXSrc,		// 來源起點X
        int nYSrc,		// 來源起點Y
        COLORREF crTrans// 透明色
        )
	{
		CMemoryDC dcImage(nWidthDest, nHeightDest,pDC);//臨時DC
		CBitmap bmpMask;
		bmpMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL);            // 建立單色掩碼位圖
		CDC dcMask;//掩碼DC 
		dcMask.CreateCompatibleDC(pDC);
		dcMask.SelectObject(bmpMask);
		//将載入位圖的記憶體DC中的位圖,拷貝到臨時DC中
		dcImage.BitBlt( 0, 0, nWidthDest, nHeightDest, this, nXSrc, nYSrc, SRCCOPY);
		
		// 設定臨時DC的透明色
		dcImage.SetBkColor(crTrans);
		//掩碼DC的透明區域為白色其它區域為黑色
		dcMask.BitBlt(0, 0, nWidthDest, nHeightDest, &dcImage, 0, 0, SRCCOPY);
		
		//臨時DC透明區域為黑色,其它區域保持不變
		dcImage.SetBkColor(RGB(0,0,0));
		dcImage.SetTextColor(RGB(255,255,255));
		dcImage.BitBlt( 0, 0, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
		
		// 目标DC透明部分保持螢幕不變,其它部分變成黑色
		pDC ->SetBkColor(RGB(255,255,255));
		pDC ->SetTextColor(RGB(0,0,0));
		pDC ->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
		pDC ->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcImage, 0, 0, SRCPAINT);
	} 
	void StretchTrans(
		int nXDest,			// 目标起點X
		int nYDest,			// 目标起點Y
		int nWidthDest,     // 目标寬度
		int nHeightDest,    // 目标高度
		CDC* pDC,			// 目标DC
		int nXSrc,			// 來源起點X
		int nYSrc,			// 來源起點Y
		int nWidthSrc,		// 來源寬度
		int nHeightSrc,		// 來源高度
		COLORREF crTrans	// 透明色
		)
	{
		CMemoryDC dcImage(nWidthDest, nHeightDest,pDC);//臨時DC
		CBitmap bmpMask;
		// 建立單色掩碼位圖
		bmpMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL);
		CDC dcMask;
		dcMask.CreateCompatibleDC(pDC);
		dcMask.SelectObject(bmpMask);
	
		// 将載入位圖的記憶體DC中的位圖,拷貝到臨時DC中
		if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
			dcImage.BitBlt(0, 0, nWidthDest, nHeightDest, this, nXSrc, nYSrc, SRCCOPY);
		else
			dcImage.StretchBlt(0, 0, nWidthDest, nHeightDest, 
				this, nXSrc, nYSrc, nWidthSrc, nHeightSrc, SRCCOPY);
		
		// 設定臨時DC的透明色
		dcImage.SetBkColor( crTrans);
		//掩碼DC的透明區域為白色其它區域為黑色
		dcMask.BitBlt(0,0,nWidthDest, nHeightDest,&dcImage,0,0,SRCCOPY);
		
		//臨時DC透明區域為黑色,其它區域保持不變
		dcImage.SetBkColor(RGB(0,0,0));
		dcImage.SetTextColor(RGB(255,255,255));
		dcImage.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
		
		// 目标DC透明部分保持螢幕不變,其它部分變成黑色
		pDC ->SetBkColor(RGB(255,255,255));
		pDC ->SetTextColor(RGB(0,0,0));
		pDC ->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
		pDC ->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcImage, 0, 0, SRCPAINT);
	}	
	CMemoryDC()
	{
		m_size.cx = m_size.cy = 0;
	}
	//從資源中加載位圖
	BOOL LoadBitmap(UINT nBitmapID,CDC* pDC=NULL)
	{
		CBitmap bitmap;
		bitmap.LoadBitmap(nBitmapID);
		BITMAP bm;
		bitmap.GetBitmap(&bm);
		m_size.cx = bm.bmWidth;
		m_size.cy = bm.bmHeight;
		CreateCompatibleDC(pDC);
		SelectObject(bitmap);
		return TRUE;
	}
	CMemoryDC(UINT nBitmapID,CDC* pDC=NULL)
	{
		LoadBitmap(nBitmapID,pDC);
	}
	//從.bmp檔案中加載位圖
	BOOL LoadBitmap(LPCTSTR szBitmapFile,CDC* pDC=NULL)
	{
		HBITMAP hBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle(),
			szBitmapFile,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
		BITMAP bm;
		GetObject(hBitmap,sizeof(bm),&bm);
		m_size.cx = bm.bmWidth;
		m_size.cy = bm.bmHeight;
		CreateCompatibleDC(pDC);
		SelectObject(hBitmap);		
		return TRUE;
	}
	CMemoryDC(LPCTSTR szBitmapFile,CDC* pDC=NULL)
	{
		LoadBitmap(szBitmapFile,pDC);
	}
	//建立一張空白記憶體畫布
	BOOL Create(int cx,int cy,CDC* pDC = NULL)
	{
		CreateCompatibleDC(pDC);
		CBitmap bitmap;
		if(pDC)
			bitmap.CreateCompatibleBitmap(pDC,cx,cy);
		else
			bitmap.CreateCompatibleBitmap(&CClientDC(NULL),cx,cy);
		m_size.cx = cx;
		m_size.cy = cy;
		SelectObject(bitmap);
		return TRUE;
	}
	CMemoryDC(int cx,int cy,CDC* pDC = NULL)
	{
		Create(cx,cy,pDC);
	}
	//摧毀
	BOOL DeleteDC()
	{
		if(!GetSafeHdc())
			return TRUE;
		CBitmap * pBitmap = GetCurrentBitmap();
		pBitmap ->DeleteObject();
		return CDC::DeleteDC();
	}
	~CMemoryDC()
	{
		DeleteDC();
	}
	inline int Width(){return m_size.cx;}
	inline int Height(){return m_size.cy;}
};
#endif //__MEMDC_H__
           

23.4 采用CMemoryDC類實作圖檔旋轉

//1、加載資源位圖
//2、加載外部位圖
//3、建立空白位圖(黑色:指定高寬)
//4、顯示透明和伸縮透明圖檔
           
m_dcBack.LoadBitmap(IDB_BITMAP1); // 初始化

void CPageDlg::OnPaint()
{
	CPaintDC dc(this); // 用于繪制的裝置上下文
	CRect rect;
	GetClientRect(rect);
	CMemoryDC mdc(rect.Width(), rect.Height(),&dc);//緩沖DC:黑色
	mdc.FillSolidRect(rect, GetSysColor(COLOR_3DFACE)); // 緩沖DC:灰色
	mdc.StretchBlt(m_nLeft, 0, rect.Width() - m_nLeft * 2, rect.Height(),
		&m_dcBack, 0, 0, rect.Width(), rect.Height(), SRCCOPY); // 繪圖輸出到緩沖DC中

	dc.BitBlt(0, 0, rect.Width(),rect.Height(), &mdc, 0, 0, SRCCOPY);//一次性對界面(dc)輸出
}
           

23.5 采用CMemoryDC類實作蝴蝶動畫

#include "MemoryDC.h"
#pragma once

// CfsDlg 對話框
class CfsDlg : public CDialogEx
{
	CMemoryDC m_dc;//緩沖
	enum { PAGE_COUNT =7};
	CMemoryDC m_dcBack;
	CMemoryDC m_dcFly[PAGE_COUNT];
	struct SData
	{
		CPoint pos;
		CPoint dir;//5,5    -5,5       5,-5    -5,-5
		int nIndex;
	};
	CArray<SData> m_arr;//動态數組
public:
	CfsDlg(CWnd* pParent = NULL);	// 标準構造函數
protected:
	HICON m_hIcon;
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnNcPaint();
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnTimer(UINT_PTR nIDEvent);
};

BOOL CfsDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	srand(time(NULL));
	m_dcBack.LoadBitmap(_T("./images/back.bmp"));
	
	int cx = GetSystemMetrics(SM_CXSCREEN);
	int cy = GetSystemMetrics(SM_CYSCREEN);

	SetWindowPos(NULL, 0, 0, cx, cy, 0);
	m_dc.Create(cx, cy);
	int i = -1;
	CString str;
	while (++i<_countof(m_dcFly))
	{
		str.Format(_T("./images/%03d.bmp"), i + 1);
		m_dcFly[i].LoadBitmap(str);
	}
	
	SetTimer(1, 20, NULL);
	SetIcon(m_hIcon, TRUE);			// 設定大圖示
	SetIcon(m_hIcon, FALSE);		// 設定小圖示
	return TRUE;  // 除非将焦點設定到控件,否則傳回 TRUE
}

void CfsDlg::OnPaint()
{
		CPaintDC dc(this); //界面dc

		CRect rect;
		GetClientRect(rect);
		//dc.BitBlt(0, 0, m_dcBack.GetWidth(), m_dcBack.GetHeight(), &m_dcBack, 0, 0, SRCCOPY);
		m_dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &m_dcBack, 0, 0, m_dcBack.GetWidth(), m_dcBack.GetHeight(), SRCCOPY);
		int i = 0,nSize = m_arr.GetSize();
		while (i < nSize)
		{
			SData& d = m_arr[i];
		m_dcFly[d.nIndex].BitTrans(d.pos.x,d.pos.y ,m_dcFly->GetWidth(),m_dcFly->GetHeight(),&m_dc,0,0,0);
			if (++d.nIndex > 6)
				d.nIndex = 0;
			d.pos.Offset(d.dir);
			GetClientRect(rect);
			if (d.pos.x >= rect.right - m_dcFly->GetWidth() || d.pos.x <= 0)
				d.dir.x *= -1;
			if (d.pos.y >= rect.bottom - m_dcFly->GetHeight() || d.pos.y <= 0)
				d.dir.y *= -1;	
			++i;
		}
		dc.BitBlt(0, 0, rect.Width(), rect.Height(), &m_dc, 0, 0, SRCCOPY);
}

BOOL CfsDlg::OnEraseBkgnd(CDC* pDC)
{
	return TRUE;
}

void CfsDlg::OnNcPaint()
{

}

void CfsDlg::OnLButtonDown(UINT nFlags, CPoint point)
{//無限增長的蝴蝶個數
	SData data = { point,{5,5},0 };
	if(rand()%2) //893253%2 
		data.dir.x *= -1;
	if (rand() % 2) //547547%2 
		data.dir.y *= -1;

	m_arr.Add(data);
	CDialogEx::OnLButtonDown(nFlags, point);
}

void CfsDlg::OnTimer(UINT_PTR nIDEvent)
{
	Invalidate(FALSE);

	CDialogEx::OnTimer(nIDEvent);
}
           

繼續閱讀