65.9K
CodeProject 正在变化。 阅读更多。
Home

桌面上的飘雪!

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (51投票s)

2006年12月20日

2分钟阅读

viewsIcon

194321

downloadIcon

3799

本文档解释了如何创建一个在桌面飘雪的应用程序。

FallingSnow

引言

每当圣诞节到来时,我都会想为我的桌面制作一些有趣的玩具。

在互联网上搜索,很容易找到许多适用于任何场合(包括圣诞节)的精彩桌面礼物。不幸的是,我找不到任何此类桌面动画的源代码或开源示例。

因此,我决定创建自己的应用程序,让桌面上的其他窗口飘雪。正如我在互联网上看到的,许多作者使用不同的方法来显示桌面上的雪花飘落。我试图尽可能简单地创建我的应用程序,并决定开发一个系统托盘应用程序,其中包含许多子雪花窗口。我认为,这种方法最简单,但对于内存和视频使用方面有一些限制。

通用步骤

  1. 创建主窗口。

    我们需要创建一个隐藏的框架窗口,并防止同时打开多个“Snow”窗口。以下代码片段展示了如何操作

    BOOL CSnowApp::InitInstance()
    {
        HWND hWnd = ::FindWindow("SnowParentWindow","Snow");
        if(hWnd) 
           return FALSE;
    
        CMainFrame* pFrame = new CMainFrame;
        m_pMainWnd = pFrame;
    
        pFrame->LoadFrame(IDR_TRAYMENU, 
                WS_OVERLAPPEDWINDOW, NULL, NULL);
    
        pFrame->ShowWindow(SW_HIDE);
    ...
    
    BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
    {
    ...
        if(cs.hInstance)
        {
            static const TCHAR szClassName[] = 
                        _T("SnowParentWindow");
            WNDCLASS wc;
            GetClassInfo(cs.hInstance, cs.lpszClass, &wc);
            wc.lpszClassName = szClassName;
            AfxRegisterClass(&wc);
            cs.lpszClass = szClassName;
        }
    ...
  2. 安装系统托盘图标。
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    ...
        SetTrayIcon(NIM_ADD, m_hIcon, "Desktop Snow");
    ...
    
    BOOL CMainFrame::SetTrayIcon(DWORD dwMessage, 
                     HICON hIcon, PSTR pszTip)
    {
        BOOL bResult = FALSE;
    
        NOTIFYICONDATA tnd;
    
        tnd.cbSize = sizeof(NOTIFYICONDATA);
        tnd.hWnd = m_hWnd;
        tnd.uID = NULL;
        tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
        tnd.uCallbackMessage = WM_NOTIFYTRAY;
        tnd.hIcon = hIcon; 
    
        if(pszTip) 
           lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip));
        else
           tnd.szTip[0] = '\0'; 
    
        bResult = Shell_NotifyIcon(dwMessage, &tnd); 
    
        return bResult;
    }
    
  3. 创建雪花数组。

    在这个应用程序中,每个雪花都被创建为一个非模式对话框窗口,并具有自己基于计时器的移动函数。

    CRect rcWorkArea;
    SystemParametersInfo(SPI_GETWORKAREA,0,(LPVOID)&rcWorkArea,0);
    int nScreenWidth = rcWorkArea.Width();
    
    int nTimer = 5;
    int nPosX = 0;
    
    srand((unsigned)time(NULL));
    for(int i=0;i<10;i++) // 10 snow flakes
    {
        nTimer = abs(rand()*50/RAND_MAX);
        nPosX = abs(rand()*nScreenWidth/RAND_MAX);
        CFlakeDlg* fd = new CFlakeDlg(nTimer,nPosX,this);
        if(fd->Create(IDD_FLAKE,this))
        m_arSnowFlakes.Add(fd);
    }
  4. 从位图中创建雪花形状。

    在运行窗口之前,我们需要创建一个雪花区域,将窗口显示为真正的雪花。我使用了 Jean-Edouard Lachand-Robert 在 这里发布的文章中的 'BitmapToRegion' 函数。

  5. 最后一步:启动计时器并享受。

    最后要做的事情是启动计时器并查看雪花如何移动。我使用了下面一个非常简单的算法,但足以显示桌面上的雪花移动。

    void CFlakeDlg::OnTimer(UINT nIDEvent) 
    {
        if(nIDEvent == 1)
        {
            KillTimer(1);
    
            m_nCurrentY += 5;
            m_nCounter++;
    
            if(m_nCounter == 15)
            {
                if(((rand()*10/RAND_MAX)-5)>0) m_nIncrement = 1;
                else m_nIncrement = -1;
    
                m_nCounter = 0;
            }
    
            m_nCurrentX += m_nIncrement;
    
            if(m_nCurrentY>m_nScreenHeight)
            {
                m_nCurrentY = 0;
                m_nCurrentX = abs(rand()*m_nScreenWidth/RAND_MAX);
                m_nTimer = abs(rand()*50/RAND_MAX);
            }
    
            MoveWindow(m_nCurrentX,m_nCurrentY,17,17);
            SetTimer(1,m_nTimer,0);
        }
    
        CDialog::OnTimer(nIDEvent);
    }
    

这个例子可以通过在桌面上绘制雪堆、显示圣诞老人、雪人和其他对象来扩展。您可以尝试雪花的定位(顶部、最顶部、底部)、雪花的数量、下落速度等。

无论如何,我希望其他人觉得这段代码在圣诞节期间有用。请随时报告错误、问题或请求。

© . All rights reserved.