MFC透明动画实例

来源:互联网 发布:淘宝登录验证怎么解除 编辑:程序博客网 时间:2024/06/15 20:28

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

过程:
一:从网上搜索一套带透明背景的位图(要做动画帧用),或者使用附件里的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// Implementationprotected:    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_FILEstatic 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_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CFlyDlg message handlersBOOL 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.htmHCURSOR 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