MFC透明动画实例

最终实现效果:
这里写图片描述

过程:
一:从网上搜索一套带透明背景的位图(要做动画帧用),或者使用附件里的Fly紫文件夹里的透明位图,如果需要更换位图,需要修改相关代码
二:使用vc6.0新建一个基于对话框的MFC程序,直接打开资源文件中的对话框界面,将对话框BORDER属性设为NONE
三:将已经封装好的MemDC.h(MemdDC.h要想在vs2016中使用,需要更改里面的类名,会与MFC的类名冲突,其他版本不清楚)文件导入工程,添加相关头文件,主要使用到MemDC里的BitTrans()函数和LoadBitmap()函数,前者用于将不透明位图输出为透明位图,后者用来加载位图
四:修改对话框头文件和CPP文件

MemDC.h

#ifndef __MEM_DC__H__
#define __MEM_DC__H__
//防止重复编译
class CMemDC : public CDC
{
    CSize m_size;
public:
    ~CMemDC()
    {
        DeleteDC();
    }
    CMemDC()
    {
        m_size.cx = m_size.cy=0;
    }
    CMemDC(UINT nBitmap,CDC* pDC=NULL)
    {
        LoadBitmap(nBitmap,pDC);
    }
    CMemDC(LPCSTR szFile,CDC* pDC=NULL)
    {
        LoadBitmap(szFile,pDC);
    }
    CMemDC(int cx,int cy,CDC* pDC=NULL)
    {
        Create(cx,cy,pDC);
    }
    BOOL DeleteDC()
    {
        if(!GetSafeHdc())
            return FALSE;
        CBitmap* pBitmap = GetCurrentBitmap();
        if(pBitmap)
            pBitmap ->DeleteObject();
        return CDC::DeleteDC();
    }
    int GetWidth(){return m_size.cx;}
    int GetHeight(){return m_size.cy;}
    BOOL Create(int cx,int cy,CDC* pDC=NULL)
    {//创建空白位图
        CBitmap bmp;
        if(!bmp.CreateCompatibleBitmap(pDC,cx,cy))
            return FALSE;
        m_size.cx = cx;
        m_size.cy = cy;
        CreateCompatibleDC(pDC);
        SelectObject(&bmp);

        return TRUE;
    }
    BOOL LoadBitmap(UINT nBitmap,CDC* pDC=NULL)
    {//进程内位图资源加载
        CBitmap bmp;
        if(!bmp.LoadBitmap(nBitmap))
            return FALSE;
        BITMAP bm;
        bmp.GetBitmap(&bm);
        m_size.cx = bm.bmWidth;
        m_size.cy = bm.bmHeight;
        CreateCompatibleDC(pDC);
        SelectObject(&bmp); 
        return TRUE;
    }
    BOOL LoadBitmap(LPCSTR szFile,CDC* pDC=NULL)
    {//进程外位图图片文件加载
        HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,szFile,IMAGE_BITMAP,
            0,0,LR_LOADFROMFILE);
        if(!hBitmap)
            return FALSE;
        BITMAP bm;
        GetObject(hBitmap,sizeof(bm),&bm);
        m_size.cx = bm.bmWidth;
        m_size.cy = bm.bmHeight;
        CreateCompatibleDC(pDC);
        SelectObject(hBitmap);  
        return TRUE;
    }

    void BitTrans(
        int nXDest,     // 目标起点X
        int nYDest,     // 目标起点Y
        int nWidthDest, // 目标宽度
        int nHeightDest,// 目标高度
        CDC* pDC,       // 目标DC
        int nXSrc,      // 来源起点X
        int nYSrc,      // 来源起点Y
        COLORREF crTrans// 透明色
        )
    {
        CMemDC 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    // 透明色
        )
    {
        CMemDC 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);
    }   
};


#endif

主对话框头文件FlyDlg.h实现

// FlyDlg.h : header file
//

#if !defined(AFX_FLYDLG_H__B92F35C6_0BDF_4DB7_BDDE_ED28D1CBBEF4__INCLUDED_)
#define AFX_FLYDLG_H__B92F35C6_0BDF_4DB7_BDDE_ED28D1CBBEF4__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CFlyDlg dialog
#include "MemDC.h"
class CFlyDlg : public CDialog
{
    enum{COUNT=7};
    CMemDC m_dcBack;//
    CMemDC m_dc[COUNT];
    int m_nIndex;
    CPoint m_pos;
public:
    void OnDraw(CDC* pDC);
    CFlyDlg(CWnd* pParent = NULL);  // standard constructor

// Dialog Data
    //{{AFX_DATA(CFlyDlg)
    enum { IDD = IDD_FLY_DIALOG };
        // NOTE: the ClassWizard will add data members here
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CFlyDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:
    HICON m_hIcon;

    // Generated message map functions
    //{{AFX_MSG(CFlyDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnNcPaint();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_FLYDLG_H__B92F35C6_0BDF_4DB7_BDDE_ED28D1CBBEF4__INCLUDED_)

主对话框CPP文件实现FlyDlg.cpp

// FlyDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Fly.h"
#include "FlyDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFlyDlg dialog

#define TRANSCOLOR RGB(0,0,255)//透明色为紫色

CFlyDlg::CFlyDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CFlyDlg::IDD, pParent)
{
    m_nIndex=0;
    m_pos.x = m_pos.y=0;
    //{{AFX_DATA_INIT(CFlyDlg)
        // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFlyDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CFlyDlg)
        // NOTE: the ClassWizard will add DDX and DDV calls here
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CFlyDlg, CDialog)
    //{{AFX_MSG_MAP(CFlyDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_TIMER()
    ON_WM_ERASEBKGND()
    ON_WM_NCPAINT()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFlyDlg message handlers

BOOL CFlyDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    m_dcBack.LoadBitmap("./Flys_紫/Back.bmp");
    int i=0;
    CString str;
    while(i<COUNT)
    {
        str.Format("./Flys_紫/%03d.bmp",i+1);
        m_dc[i].LoadBitmap(str);
        ++i;
    }
    SetTimer(1,64,NULL);
    MoveWindow(0,0,m_dcBack.GetWidth(),m_dcBack.GetHeight());

    // 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

    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 CFlyDlg::OnPaint() 
{
    CPaintDC dc(this);
    OnDraw(&dc);
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.http://www.fodizi.com/fofa/list/248.htm
HCURSOR CFlyDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

//为什么画面上方会产生秘密文字???

void CFlyDlg::OnTimer(UINT nIDEvent) 
{
    //如果使用注释掉的这一部分,则是没有采用双缓冲,需要注释掉OnPaint函数里的OnDraw()函数和这里的Invalideate()函数
    //如果使用OnDraw函数,则是采用了双缓冲技术,OnDraw()在OnPaint()中调用,所以要使用Invalidate()函数来刷新界面
    /*
    static int i=0;

    CClientDC dc(this);
    //显示背景
    dc.BitBlt(0,0,m_dcBack.GetWidth(),m_dcBack.GetHeight(),
        &m_dcBack,0,0,SRCCOPY);

    static int cx=m_dc[m_nIndex].GetWidth();//离开函数数值不丢失
    static int cy=m_dc[m_nIndex].GetHeight();
    static dx=5,dy=5;//运动方向


    //显示蝴蝶
    m_dc[m_nIndex].BitTrans(m_pos.x,m_pos.y,cx,cy,&dc,0,0,TRANSCOLOR);

    //控制蝴蝶位置
    m_pos.Offset(dx,dy);
    if(m_pos.x + cx> m_dcBack.GetWidth() || m_pos.x <0)
        dx*=-1;
    if(m_pos.y + cy> m_dcBack.GetHeight() || m_pos.y < 0)
        dy *=-1;
    if(++m_nIndex>=COUNT)
        m_nIndex=0;
*/


    Invalidate(FALSE);
}

//使用双缓冲技术
void CFlyDlg::OnDraw(CDC *pDC)
{
    CRect rect;
    GetClientRect(rect);

    CMemDC mdc(rect.Width(),rect.Height(),pDC);
    //如果不用背景图去覆盖掉上一次的蝴蝶,可以用FillSolidRect这一句去覆盖(必须要有东西来覆盖掉上一次的蝴蝶),
    //但如果在用绿色覆盖后又再用背景图覆盖,如果没有使用双缓冲技术,会发生闪烁
//  mdc.FillSolidRect(0,0,rect.right,rect.Height(),RGB(255,0,0));

    //既可以拉伸,也可以直接输入到缓冲内存中
    //如果TRANSCOLOR为黑色并且把FillSolidRect()的注释去掉,会有神秘文字出现,改成其他颜色不会,这种现象与图本身有关
//  m_dcBack.StretchTrans(0,0,rect.right,rect.bottom,&mdc,0,0,m_dcBack.GetWidth(),
//      m_dcBack.GetHeight(),TRANSCOLOR);   
    m_dcBack.BitTrans(0,0,rect.right,rect.bottom,&mdc,0,0,RGB(0,0,0));
//  dc.BitBlt(0,0,m_dcBack.GetWidth(),m_dcBack.GetHeight(),&m_dcBack,0,0,SRCCOPY);
    static int cx = m_dc[m_nIndex].GetWidth();//static变量第一次进入函数式初始化
    static int cy = m_dc[m_nIndex].GetHeight();//离开函数数值不丢失

    static dx=5,dy=5;//运动方向

    m_dc[m_nIndex].BitTrans(m_pos.x,m_pos.y,cx,cy,&mdc,0,0,TRANSCOLOR);

    pDC ->BitBlt(0,0,mdc.GetWidth(),mdc.GetHeight(),&mdc,0,0,SRCCOPY);

    m_pos.Offset(dx,dy);
    if(m_pos.x + cx> rect.right || m_pos.x <0)
        dx*=-1;
    if(m_pos.y + cy> rect.bottom || m_pos.y < 0)
        dy *=-1;
    if(++m_nIndex>=COUNT)
        m_nIndex=0;
}

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

void CFlyDlg::OnNcPaint() 
{
}

程序遗留问题:
如果带有透明背景的位图的透明色为黑色的话,在运行的时候蝴蝶图片的背景仍然不会被去除掉,原因暂时未弄明白,如果有网友看了这份代码,并且
明白了这个问题的原因的话,如果能在评论里或写信指导一下本人,本人将感激不尽!!

附件下载:

=工程文件

参考:

http://study.163.com/course/courseLearn.htm?courseId=613004#/learn/video?lessonId=783001&courseId=613004

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值