问题描述:
想要实现的效果是在屏幕出现一只飞舞的蝴蝶(带有透明色背景位图),使用了CMemory封装类
来实现,虽然可以使蝴蝶飞动,但最终蝴蝶图片的背景还是没有去除掉,
Memory.h头文件
#pragma once
#include "afxwin.h"
#ifndef __MEMDC_H__
#define __MEMDC_H__
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; }
void CMemoryDC::BitRgn(CRgn &rgn,/*目标区域*/COLORREF crTrans/*透明色*/)
{
//根据当前位图和透明色生成一个不规则区域
int i = 0, j = 0;
rgn.CreateRectRgn(0, 0, 0, 0);
while (i < m_size.cx)
{
j = 0;
while (j < m_size.cy)
{
if (GetPixel(i, j) - crTrans)
{
//如果不是透明色就在区域内增加一个点
CRgn r;
r.CreateRectRgn(i, j, i + 1, j + 1);
rgn.CombineRgn(&rgn, &r, RGN_OR);
}
++j;
}
++i;
}
}
};
\#endif //__MEMDC_H__
主对话框头文件:FlyRgnDlg.h
// FlyRgnDlg.h : header file
//
#pragma once
#include "MemDC.h"
// CFlyRgnDlg dialog
class CFlyRgnDlg : public CDialogEx
{
// Construction
public:
enum { FLY_CNT = 7 };
CMemoryDC m_dc[FLY_CNT];
CRgn m_rgn[FLY_CNT];
int m_nIndex; //当前帧数
CPoint m_pos; //当前位置
public:
CFlyRgnDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_FLYRGN_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnTimer(UINT_PTR nIDEvent);
void OnDraw(CDC* pDC);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnNcPaint();
};
主对话框cpp文件:FlyRgnDlg.cpp
// FlyRgnDlg.cpp : implementation file
//
#include "stdafx.h"
#include "FlyRgn.h"
#include "FlyRgnDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CFlyRgnDlg dialog
#define TRANSCOLOR RGB(0,0,0)
CFlyRgnDlg::CFlyRgnDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_FLYRGN_DIALOG, pParent)
{
m_nIndex = 0;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CFlyRgnDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CFlyRgnDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
ON_WM_ERASEBKGND()
ON_WM_NCPAINT()
END_MESSAGE_MAP()
// CFlyRgnDlg message handlers
BOOL CFlyRgnDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
int i = 0;
CString str;
while (i < FLY_CNT)
{
//加载多张动画图片并且每张图片根据透明色区域生成一个区域
str.Format(_TEXT("./flys/%03d.bmp"), i + 1);
m_dc[i].LoadBitmapW(str);
m_dc[i].BitRgn(m_rgn[i], TRANSCOLOR);
i++;
}
ModifyStyle(GetStyle(), 0);//去掉标题栏和边框
ModifyStyleEx(GetExStyle(), WS_EX_TOOLWINDOW);//不在任务栏显示
//创建一个屏幕随机坐标
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
srand(time(NULL));
m_pos.x = rand() % (cx - m_dc[0].Width());
m_pos.y = rand() % (cy - m_dc[0].Height());
CMemoryDC &mdc = m_dc[m_nIndex];//设置窗口位置并置顶
SetWindowPos(&wndTopMost, m_pos.x, m_pos.y, mdc.Width(), mdc.Height(), 0);
CRgn rgn; //选择一个帧区域复制后设置到窗口
rgn.CreateRectRgn(0, 0, 0, 0);
rgn.CopyRgn(&m_rgn[m_nIndex]);
SetWindowRgn(rgn, TRUE);
//启动定时器
SetTimer(0, 64, NULL);
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CFlyRgnDlg::OnPaint()
{
CPaintDC dc(this);
OnDraw(&dc);
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CFlyRgnDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CFlyRgnDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
/* CmemoryDC &mdc = m_dc[m_nIndex];
MoveWindow(m_pos.x, m_pos.y, mdc.GetWidth(), mdc.GetHeight());
CRgn rgn;
rgn.CreateRectRgn(0, 0, 0, 0);
rgn.CopyRgn(&m_rgn[m_nIndex]);
SetWindowRgn(rgn, TRUE);
CClientDC dc(this);
mdc.BitTrans(0, 0, mdc.GetWidth(), mdc.GetHeight(),
&dc, 0, 0, SRCCOPY);
static int cx = 5, cy = 5;
m_pos.Offset(cx, cy);
if (m_pos.x + mdc.GetWidth() > GetSystemMetrics(SM_CXSCREEN) || m_pos.x < 0)
cx *= -1;
if (m_pos.y + mdc.GetHeight() > GetSystemMetrics(SM_CYSCREEN) || m_pos.y < 0)
cy *= -1;
if (++m_nIndex >= FLY_CNT)
m_nIndex = 0;*/
CClientDC dc(this);
Invalidate(FALSE);
CDialogEx::OnTimer(nIDEvent);
}
void CFlyRgnDlg::OnDraw(CDC *pDC)
{
CMemoryDC &mdc = m_dc[m_nIndex];
MoveWindow(m_pos.x, m_pos.y, mdc.Width(), mdc.Height());
CRgn rgn;
rgn.CreateRectRgn(0, 0, 0, 0);
rgn.CopyRgn(&m_rgn[m_nIndex]);
SetWindowRgn(rgn, TRUE);
mdc.BitTrans(0, 0, mdc.Width(), mdc.Height(),
pDC, 0, 0, TRANSCOLOR);
static int cx = 5, cy = 5;
m_pos.Offset(cx, cy);
if (m_pos.x + mdc.Width() > GetSystemMetrics(SM_CXSCREEN) || m_pos.x < 0)
cx *= -1;
if (m_pos.y + mdc.Height() > GetSystemMetrics(SM_CYSCREEN) || m_pos.y < 0)
cy *= -1;
if (++m_nIndex >= FLY_CNT)
m_nIndex = 0;
}
BOOL CFlyRgnDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE;
// return CDialogEx::OnEraseBkgnd(pDC);
}
void CFlyRgnDlg::OnNcPaint()
{
// TODO: Add your message handler code here
// Do not call CDialogEx::OnNcPaint() for painting messages
}
可以试试用2张背景图