MFC和GDI+制作雪花飞舞小程序

基于CWnd对话框,利用GDI+和PNG素材实现雪花飞舞唯美场景小程序。程序技术简单,仅供新手参考学习使用。

先看疗效:
这里写图片描述


下面来说说程序原理吧:
工程:VS2005,MFC(对话框)工程。
窗口:主窗口宽高为0,主要接收菜单传来的消息。绘图窗口宽高为屏幕的宽高,主要绘制雪花。
元素:雪花种类共12种,GDI+绘制不同的资源图片到窗口上。
动作:动作有3种,左移动、右移动、下移动。
动作原理:绘图窗口有一个定时器Timer,定时器根据时间来判断是否需要加入新的雪花图片,图片随机。
程绘图原理
1.获取窗口DC。
2.创建位图、画刷。
3.随着TIMER,随机产生图像,同时定义好图像坐标与大小。
4.绘制图像到画刷中。
5.更新位图到窗口上。


用到的技术点:

窗口透明
WS_EX_TOPMOST(顶层)
WS_EX_LAYERED(透明异形)
WS_EX_TRANSPARENT(消息穿透)
窗口绘图
UpdateLayeredWindow();
GDI+:graphics.DrawImage、CDC 等。
托盘:Shell_NotifyIcon
菜单:TrackPopupMenu


关键代码与实现:

注册窗口类

    WNDCLASS wndcls;
    memset(&wndcls, 0, sizeof(WNDCLASS));
    wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
    wndcls.lpfnWndProc = ::DefWindowProc;
    wndcls.hInstance = AfxGetInstanceHandle();
    wndcls.hIcon = NULL;
    wndcls.hCursor = ::LoadCursor(NULL,IDC_ARROW);
    wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wndcls.lpszMenuName = NULL;
    wndcls.lpszClassName = lpszClassName;
    if(!AfxRegisterClass(&wndcls))
    {
        return FALSE;
    }

窗口透明异形

    int nWidth = GetSystemMetrics (SM_CXSCREEN);
    int nHeight =  GetSystemMetrics (SM_CYSCREEN);
    DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT;
    DWORD dwStyle = WS_POPUP | WS_VISIBLE | WS_SYSMENU;
    m_pSnowWnd = new CSnowWnd;
    BOOL bRes = m_pSnowWnd->CreateEx(dwExStyle, _T("CSnowWnd"), _T("Snow"), dwStyle, 0, 0, nWidth, nHeight, m_hWnd, NULL);
    m_pSnowWnd->ShowWindow(SW_SHOW);

创建画刷

void CSnowWnd::MakeBkgndDC()
{
    CDC *pDC = GetDC();

    CBitmap hBackground;
    hBackground.CreateCompatibleBitmap(pDC, m_rcWnd.Width(), m_rcWnd.Height());
    if(m_dcBack.m_hDC == NULL)
        m_dcBack.CreateCompatibleDC(pDC);

    CBitmap *pOldBmp = m_dcBack.SelectObject(&hBackground);
    pOldBmp->DeleteObject();

    hBackground.DeleteObject();
    ReleaseDC(pDC);
}

雪花位置、大小、移动数据的产生

void CSnowWnd::DownSnow()
{
    DWORD dwRes = 0;
    for(int i = m_nImgCount - 1; i >= 0; i--)
    {
        PIMG pImage = m_ImgDrawSto[i];
        pImage->Y+= pImage->nSpeed;//下移
        if(pImage->Y > m_rcWnd.Height())//超出
        {
            m_ImgDrawSto.RemoveAt(i);//移除
            delete pImage;
            continue;
        }

        if(dwRes == 0)
            dwRes = GetTickCount() - pImage->dwTickCount;

        //横向移动 
        if (pImage->Init)
        {
            pImage->Init = FALSE;
            pImage->StepTpye = GetRand(1, 3);
        }
        switch (pImage->StepTpye)
        {
        case 1:
            pImage->X--;
            break;
        case 2:
            pImage->X++;
            break;
        }
    }

    m_nImgCount = m_ImgDrawSto.GetCount();
    if(dwRes > 1800)//增加雪花时间控制
        AddSnow(GetRand(0, m_nRowMaxCount));

    DrawWnd();
}

绘图

void CSnowWnd::DrawWnd()
{
    MakeBkgndDC();
    CDC * pDC = GetDC();
    Graphics g(m_dcBack.GetSafeHdc());

    for(int i=0;i<m_nImgCount;i++)
    {
        PIMG pImage = m_ImgDrawSto[i];
        g.DrawImage(pImage->pImage, pImage->X, pImage->Y, pImage->Width, pImage->Height);
    }

    CPoint DestPt(0,0);
    CSize psize(m_rcWnd.Width(),m_rcWnd.Height());
    BLENDFUNCTION blend;
    blend.AlphaFormat = AC_SRC_ALPHA;
    blend.BlendFlags = 0;
    blend.BlendOp = AC_SRC_OVER;
    blend.SourceConstantAlpha = 255;
    UpdateLayeredWindow(pDC, NULL, &psize, &m_dcBack, &DestPt, 0, &blend, ULW_ALPHA);
    ReleaseDC(pDC);
}

好了,主要的代码已经贴出来,如有疑问可以留言。
源程序下载链接:
http://download.csdn.net/detail/xinsuiyishunjian/9587916

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值