文章目录
- CRgn类简介与开发
- CRgn类简介
- CRgn类区域管理开发
- CRgn类区域管理与不规则形状的选取
- 封装CMemoryDC类并应用开发
- CMemoryDC.h
- 封装CMemoryDC开发游戏透明动画
- CFlashDlg.h
- CFlashDlg.cpp
- 封装CMemoryDC开发游戏动画
- 附录
- 四大窗口CDC派生类
CRgn类简介与开发
CRgn类简介
CRgn类是MFC(Microsoft Foundation Classes)中的一个图形区域类。该类用于创建和操作图形区域,可以表示各种形状的区域,如矩形、椭圆、多边形等。
class CRgn : public CGdiObject
{
public:
static CRgn* PASCAL FromHandle(HRGN hRgn);
operator HRGN() const;
// 封装的特点是没有使用Overload重载函数,结构体就是XXXIndirect
CRgn();
//创建矩形区域
BOOL CreateRectRgn(int x1, int y1, int x2, int y2);
BOOL CreateRectRgnIndirect(LPCRECT lpRect);
//创建圆形区域
BOOL CreateEllipticRgn(int x1, int y1, int x2, int y2);
BOOL CreateEllipticRgnIndirect(LPCRECT lpRect);
//多边形
BOOL CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode);
BOOL CreatePolyPolygonRgn(LPPOINT lpPoints, LPINT lpPolyCounts,
int nCount, int nPolyFillMode);
//圆角矩形
BOOL CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3);
//
BOOL CreateFromPath(CDC* pDC);
BOOL CreateFromData(const XFORM* lpXForm, int nCount,
const RGNDATA* pRgnData);
// 修改矩形
void SetRectRgn(int x1, int y1, int x2, int y2);
void SetRectRgn(LPCRECT lpRect);
//混合
int CombineRgn(const CRgn* pRgn1, const CRgn* pRgn2, int nCombineMode);
int CopyRgn(const CRgn* pRgnSrc);
//判断区域完全一样
BOOL EqualRgn(const CRgn* pRgn) const;
//判断一个点是否在区域内
BOOL PtInRegion(int x, int y) const;
BOOL PtInRegion(POINT point) const;
//保持形状不变偏移
int OffsetRgn(int x, int y);
int OffsetRgn(POINT point);
//框图
int GetRgnBox(LPRECT lpRect) const;
BOOL RectInRegion(LPCRECT lpRect) const;
int GetRegionData(LPRGNDATA lpRgnData, int nCount) const;
// Implementation
virtual ~CRgn();
};
CRgn类的混合功能:
int CombineRgn( CRgn* pRgn1, CRgn* pRgn2, int nCombineMode );
RGN_AND 交集
RGN_COPY 拷贝
RGN_DIFF 不同
RGN_OR 并集
RGN_XOR 异或
CRgn类区域管理开发
CRgnDlg.h
#pragma once
class CCRgnDlg : public CDialogEx
{
// 构造
CDC m_dc;
CRect m_rect;
}
CRgnDlg.cpp
BOOL CCRgnDlg::OnInitDialog(){
CDialogEx::OnInitDialog();
CBitmap bmp;
bmp.LoadBitmap(IDB_LOGO);
BITMAP bm;
bmp.GetBitmap(&bm);
m_rect.SetRect(0,0, bm.bmWidth,bm.bmHeight );
m_dc.CreateCompatibleDC(NULL);
m_dc.SelectObject(&bmp);
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
//透明 一个去掉不要的区域进行显示 透明度(半透明)
void CCRgnDlg::OnPaint(){
CPaintDC dc(this); // 用于绘制的设备上下文
CRgn rgn; //输出区域管理
dc.FillSolidRect(CRect(10, 10, 700, 400), RGB(0, 255, 0)); //填充了一块背景区域
CRect rect;
rect = m_rect;
rect.OffsetRect(50, 0);
//rgn.CreateEllipticRgn(0, 0, m_rect.right, m_rect.bottom); //圆形区域管理
rgn.CreateEllipticRgn(rect.left,rect.top, rect.right, rect.bottom);
dc.SelectObject(&rgn);
//dc.BitBlt(0, 0, m_rect.right, m_rect.bottom, &m_dc, 0, 0, SRCCOPY); //对图片的空白区域操作
dc.BitBlt(50, 0, m_rect.Width(), m_rect.Height(), &m_dc, 0, 0, SRCCOPY);
}
CircleRgnDlg.h
#pragma once
class CCircleRgnDlg : public CDialogEx
{
// 构造
CDC m_dc;
CRect m_rect;
public:
afx_msg LRESULT OnNcHitTest(CPoint point);
};
CircleRgnDlg.cpp
BOOL CCircleRgnDlg::OnInitDialog(){
CDialogEx::OnInitDialog();
CBitmap bmp;
bmp.LoadBitmap(IDB_LOGO);
BITMAP bm;
bmp.GetBitmap(&bm);
m_rect.SetRect(0, 0, bm.bmWidth, bm.bmHeight);
SetWindowPos(NULL, 0, 0, m_rect.Width(), m_rect.Height(), SWP_NOMOVE | SWP_NOZORDER);
m_dc.CreateCompatibleDC(NULL);
m_dc.SelectObject(&bmp);
CRgn rgn;
rgn.CreateEllipticRgnIndirect(m_rect);
SetWindowRgn(rgn, FALSE);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CCircleRgnDlg::OnPaint()
{
CPaintDC dc(this); // 用于绘制的设备上下文
dc.BitBlt(0, 0, m_rect.right, m_rect.bottom, &m_dc, 0, 0, SRCCOPY);
}
LRESULT CCircleRgnDlg::OnNcHitTest(CPoint point)
{
return HTCAPTION;
}
CRgn类区域管理与不规则形状的选取
CCircleRgnDlg.h
class CCircleRgnDlg : public CDialogEx
{
// 构造
CDC m_dc;
CRect m_rect;
public:
afx_msg LRESULT OnNcHitTest(CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
CCircleRgnDlg.cpp
BOOL CCircleRgnDlg::OnInitDialog(){
CDialogEx::OnInitDialog();
CBitmap bmp;
bmp.LoadBitmap(IDB_LOGO);
BITMAP bm;
bmp.GetBitmap(&bm);
m_rect.SetRect(0, 0, bm.bmWidth, bm.bmHeight);
SetWindowPos(NULL, 0, 0, m_rect.Width(), m_rect.Height(), SWP_NOMOVE | SWP_NOZORDER);
m_dc.CreateCompatibleDC(NULL);
m_dc.SelectObject(&bmp);
/*CRgn rgn;
rgn.CreateEllipticRgnIndirect(m_rect);
SetWindowRgn(rgn, FALSE);*/
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
//CRgn r, r1, r2;
//r.CreateEllipticRgn(20, 20, 500, 400);
//dc.SelectObject(&r);
//dc.BitBlt(0, 0, m_rect.right, m_rect.bottom, &m_dc, 0, 0, SRCCOPY);
//
//POINT pts[] = { {482,192},{568,302},{322,538},{123,357},{251,192},{360,320} };
//r1.CreatePolygonRgn(pts, _countof(pts), ALTERNATE);
//
//r2.CreateRectRgn(0, 0, 0, 0);
//
//r2.CombineRgn(&r, &r1, RGN_AND);
//r2.CombineRgn(&r, &r1, RGN_XOR);
//dc.SelectObject(&r2);
//dc.BitBlt(0, 0, m_rect.right, m_rect.bottom, &m_dc, 0, 0, SRCCOPY);
void CCircleRgnDlg::OnPaint()
{
CPaintDC dc(this); // 用于绘制的设备上下文
CRgn r,r1;
r.CreateEllipticRgn(20, 20, 500, 400);
POINT pts[] = {{482,192},{568,302},{322,538},{123,357},{251,192},{360,320}};
r1.CreatePolygonRgn(pts, _countof(pts), ALTERNATE);
r.CombineRgn(&r, &r1, RGN_XOR);
dc.SelectObject(&r);
CRect rect;
r.GetRgnBox(rect);//框图要考虑如何恢复到之前图
dc.BitBlt(0, 0, m_rect.right, m_rect.bottom, &m_dc, 0, 0, SRCCOPY);
BITMAP bm;
dc.GetCurrentBitmap()->GetBitmap(&bm); //获取当前选中的位图对象,并将其信息存储在bm结构中。
r.DeleteObject();
r.CreateRectRgn(0, 0, bm.bmWidth, bm.bmHeight);
dc.SelectObject(&r);
dc.SelectStockObject(NULL_BRUSH); //绘制图形时使用的画刷对象设置为无画刷,即不填充图形
dc.Rectangle(rect);
}
void CCircleRgnDlg::OnLButtonDown(UINT nFlags, CPoint point){
CRgn r, r1, r2;
r.CreateEllipticRgn(20, 20, 500, 400);
POINT pts[] = { {482,192},{568,302},{322,538},{123,357},{251,192},{360,320} };
r1.CreatePolygonRgn(pts, _countof(pts), ALTERNATE);
r.CombineRgn(&r, &r1, RGN_XOR);
if (r.PtInRegion(point))
{
AfxMessageBox(_T("你选择了"));
}
CDialogEx::OnLButtonDown(nFlags, point);
}
封装CMemoryDC类并应用开发
CMemoryDC.h
/* 内存DC类简介:
1、BOOL LoadBitmap(UINT nBitmapID,CDC* pDC = NULL) 从资源中按照,按位图ID加载位图
2、BOOL LoadFile(LPCTSTR sFile, CDC* pDC = NULL) 从exe外部加载图片(调用LoadImage)
3、BOOL Create(int cx, int cy, CDC* pDC = NULL) 创建空白位图(默认是全黑)
4、总共有4种构造函数,包含以上3种还有空构造:
CMemoryDC(UINT nBitmapID)//从资源按照位图编号来加载
CMemoryDC(LPCTSTR sFile, CDC* pDC = NULL)//从exe外部加载
CMemoryDC(int cx, int cy, CDC* pDC=NULL)//指定高宽创建空白位图
5、void MakeRgn(CRgn& r,COLORREF col) 生成透明区域
6、int GetWidth() const int GetHeight() const 方便地获取图片高宽:
7、透明显示:BitTrans和StrecthTrans */
#pragma once
#include "resource.h"
class CMemoryDC :public CDC{
CSize m_size;
public:
CMemoryDC();
int GetWidth() const{
return m_size.cx;
}
int GetHeight() const{
return m_size.cy;
}
CSize GetSize() const {
return m_size;
}
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);
}
BOOL Create(int cx, int cy, CDC* pDc = NULL){ //创建空位图
if (!CreateCompatibleDC(NULL))
return FALSE;
CBitmap bmp;
if (pDc) {
if (!bmp.CreateCompatibleBitmap(pDc, cx, cy)) {
DeleteDC();
return FALSE; }}
else{
if (!bmp.CreateCompatibleBitmap(&CClientDC(NULL), cx, cy)){
DeleteDC();
return FALSE; }}
this->SelectObject(&bmp);
m_size.SetSize(cx, cy);
return TRUE; }
BOOL LoadFile(LPCTSTR sFile, CDC* pDC = NULL){ //加载一张exe外部位图
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, sFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hBitmap)
return FALSE;
if (!CreateCompatibleDC(NULL)){
DeleteObject(hBitmap);
return FALSE;
}
SelectObject(hBitmap);
BITMAP bm;
GetObject(hBitmap, sizeof(bm), &bm);
m_size.SetSize(bm.bmWidth, bm.bmHeight);
DeleteObject(hBitmap);
return TRUE;
}
BOOL LoadBitmap(UINT nBitmapID, CDC* pDC = NULL) //加载一张资源位图
{
if (!CreateCompatibleDC(NULL))
return FALSE;
CBitmap bmp;
if (!bmp.LoadBitmap(nBitmapID)){
DeleteDC();
return FALSE;
}
SelectObject(&bmp);
BITMAP bm;
bmp.GetBitmap(&bm);
m_size.SetSize(bm.bmWidth, bm.bmHeight);
return TRUE;
}
CMemoryDC(UINT nBitmapID)
{
LoadBitmap(nBitmapID);
}
CMemoryDC(LPCTSTR sFile,CDC* pDC = NULL)
{
LoadFile(sFile, pDC);
}
CMemoryDC(int cx,int cy,CDC* pDC=NULL)
{
Create(cx, cy, pDC);
}
void MakeRgn(CRgn& r, COLORREF col){
r.CreateRectRgn(0, 0, 0, 0);
int i = -1, cx = m_size.cx;
int j = -1, cy = m_size.cy;
while (++j<cy) {
i = -1;
while (++i<cx){
if (GetPixel(i, j) != col) {
CRgn r1;
r1.CreateRectRgn(i, j, i + 1, j + 1); //1*1像素
r.CombineRgn(&r, &r1, RGN_OR);
}
}
}
}};
封装CMemoryDC开发游戏透明动画
CFlashDlg.h
#pragma once
#include "CMemoryDC.h"
class CCFlashDlg : public CDialogEx{
//二维动画 不停的切换7张图, x y方向不断地移动
int m_nIndex{}; //第几张图片
CPoint m_pos{}, m_dir{ 5,5 };//m_pos偏移位置 m_dir每次运动5,5
enum {Fly_nCount =7}; //图片总数
CMemoryDC m_dcBack{_T("./res/back.bmp")}; //背景图片
CMemoryDC m_dcFlys[Fly_nCount]; //蝴蝶
CRgn m_rs[Fly_nCount]; //取出背景颜色
void LoadPictures();
public:
afx_msg void OnTimer(UINT_PTR nIDEvent);
};
CFlashDlg.cpp
#include "pch.h"
#include "framework.h"
#include "CFlash.h"
#include "CFlashDlg.h"
#include "afxdialogex.h"
void CCFlashDlg::LoadPictures(){
int i = -1;
CString str;
while (++i<_countof(m_dcFlys))
{
str.Format(_T("./res/%03d.bmp"), i + 1);
m_dcFlys[i].LoadFile(str);
m_dcFlys[i].MakeRgn(m_rs[i],0x00ff00ff);
}
}
BOOL CCFlashDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(NULL, 0, 0, cx/2, cy/2, SWP_NOZORDER);
LoadPictures();
SetTimer(1, 16, NULL);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CCFlashDlg::OnPaint()
{
CPaintDC dc(this); // 用于绘制的设备上下文
CRect rect;
GetClientRect(rect);
dc.SetStretchBltMode(STRETCH_HALFTONE);
dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &m_dcBack, 0, 0, m_dcBack.GetWidth(), m_dcBack.GetHeight(), SRCCOPY);
CMemoryDC mdc(200,180); //创建默认的黑色
if (mdc.GetSafeHdc())
dc.BitBlt(200, 150, 200, 180, &mdc, 0, 0, SRCCOPY);
//CRgn r;
//r.CreateRectRgn(0, 0, 0, 0); //基址
//r.CopyRgn(m_rs+m_nIndex); //往那个跑先复制出来 不要破坏它 形状
//r.OffsetRgn(m_pos); //你要输出到那个位置
//dc.SelectObject(&r);
//dc.BitBlt(m_pos.x, m_pos.y, m_dcFlys->GetWidth(),m_dcFlys->GetHeight(), m_dcFlys + m_nIndex, 0, 0,SRCCOPY);
auto pDC = m_dcFlys + m_nIndex; //等价于 :&m_dcFlys[m_nIndex]
pDC->BitTrans(m_pos.x, m_pos.y, pDC->GetWidth(), pDC->GetHeight(), &dc, 0, 0, 0xff00ff);
if (++m_nIndex >= Fly_nCount)
m_nIndex = 0 ;
if (m_pos.x + m_dcFlys->GetWidth() > rect.right || m_pos.x < 0)
m_dir.x *= -1;
if (m_pos.y + m_dcFlys->GetHeight() > rect.bottom || m_pos.y < 0)
m_dir.y *= -1;
}
void CCFlashDlg::OnTimer(UINT_PTR nIDEvent)
{
m_pos.Offset(m_dir);
Invalidate(FALSE);
CDialogEx::OnTimer(nIDEvent);
}
封装CMemoryDC开发游戏动画
QQDlg.h
#pragma once
#include "CMemoryDC.h"
class CQQDlg : public CDialogEx
{
CPoint m_pos{}, m_dir{ 5,5 };
enum { Fly_nCount = 7 }; //图片总数
CMemoryDC m_dcFlys[Fly_nCount]; //蝴蝶
CRgn m_rs[Fly_nCount];
int m_nIndex{ 0 };
public:
afx_msg void OnTimer(UINT_PTR nIDEvent);
};
QQDlg.cpp
BOOL CQQDlg::OnInitDialog(){
CDialogEx::OnInitDialog();
int i = -1;
while (++i < _countof(m_dcFlys)){
m_dcFlys[i].LoadBitmap(IDB_FLY1 + i);
m_dcFlys[i].MakeRgn(m_rs[i], 0xff00ff);
}
SetTimer(1, 16, NULL);
CRgn r;
r.CreateRectRgn(0, 0, 0, 0);
r.CopyRgn(&m_rs[m_nIndex]);
SetWindowRgn(r, FALSE);
SetWindowPos(NULL, m_pos.x, m_pos.y, m_dcFlys->GetWidth(), m_dcFlys->GetHeight(), SWP_NOZORDER);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CQQDlg::OnPaint()
{
CPaintDC dc(this); // 用于绘制的设备上下文
int cx = m_dcFlys->GetWidth();
int cy = m_dcFlys->GetHeight();
dc.BitBlt(0, 0, cx, cy, &m_dcFlys[m_nIndex], 0, 0, SRCCOPY);
if (++m_nIndex >= _countof(m_dcFlys))
{
m_nIndex = 0;
}
}
void CQQDlg::OnTimer(UINT_PTR nIDEvent){
CDialogEx::OnTimer(nIDEvent);
CRgn r;
r.CreateRectRgn(0, 0, 0, 0);
r.CopyRgn(&m_rs[m_nIndex]);
SetWindowRgn(r,FALSE); //不这样的话到第七帧的时候就会出来阴影
Invalidate(FALSE);
SetWindowPos(NULL, m_pos.x, m_pos.y,0,0, SWP_NOZORDER | SWP_NOSIZE);
m_pos.Offset(m_dir);
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
if (m_pos.x + m_dcFlys->GetWidth() > cx || m_pos.x < 0)
m_dir.x *= -1;
if (m_pos.y + m_dcFlys->GetHeight() > cy || m_pos.y < 0)
m_dir.y *= -1; }
附录
四大窗口CDC派生类
CPaintDC,CClientDC,CWindowDC,CMemoryDC类
CBitmap对象创建后,默认所有像素都是黑色,0x00000000四个字节一个像素。