MFC中托盘(TRAYICON)实现

写在最前面的

将MFC中托盘功能模块抽象成一个类,把整个程序的功能模块细分了。这个想法在网上已经是俯拾即是了,但仍旧不能一下子明白其中的东西,特别是将其抽象之后。 在使用这个类的时候,需要注意:托盘菜单的ID要和图标资源的ID一样,否则会出错。

具体实现代码 

添加新的类,选择父类是CCmdTarget,下面的代码中有足够的提醒:

TrayIcon.h  

#pragma once

//  TrayIcon.h : 头文件
//
//     继承自CCmdTarget才能接收消息,详见《深入浅出 MFC》
class CTrayIcon :  public CCmdTarget 

    DECLARE_DYNAMIC(CTrayIcon)

public
    CTrayIcon(UINT uID); 
     ~CTrayIcon(); 
     
     //  Call this to receive tray notifications 
     void SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg);

     //  SetIcon functions. To remove icon, call SetIcon(0) 
    
// 只安装图盘图标 
    BOOL SetIcon(UINT uID,LPWSTR lpTip=NULL);

     // 安装托盘图标和设置提示信息 
    BOOL SetIcon(HICON hIcon, LPWSTR lpTip);

     // 安装托盘图标和设置提示信息 
    BOOL SetIcon(LPCTSTR lpResName, LPWSTR lpTip) 
    { 
         return SetIcon(lpResName ?  
            AfxGetApp()->LoadIcon(lpResName) : NULL, lpTip); 
    }

     /*  
    BOOL SetStandardIcon(LPCTSTR lpszIconName, LPCSTR lpTip) 
    { 
        return SetIcon(::LoadIcon(NULL, lpszIconName), lpTip); 
    } 
    
*/

     virtual LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent);

     /*
    BOOL ShowBalloonTip();
    笔者没有实现泡泡其实,如果有想法的可以留言
    
*/
protected
    NOTIFYICONDATA m_nid; 
    DECLARE_MESSAGE_MAP() 
};

 

TrayIcon.cpp 

//  TrayIcon.cpp : 实现文件 
//
#include  " stdafx.h " 
#include  " TrayIconShell.h " 
#include  " TrayIcon.h "

/*  
注意:托盘菜单的ID要和图标资源的ID一样,否则会出错!
*/
IMPLEMENT_DYNAMIC(CTrayIcon, CCmdTarget)

CTrayIcon::CTrayIcon(UINT uID) 

    ::memset(&m_nid, 0, sizeof(m_nid)); 
    m_nid.uID = uID; 
    m_nid.cbSize =  sizeof(NOTIFYICONDATA); 
}

CTrayIcon::~CTrayIcon() 

     this->SetIcon( 0); 
}

void CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg) 

     // 断言,正确才中断 
    ASSERT(pNotifyWnd==NULL 
        ||::IsWindow(pNotifyWnd->GetSafeHwnd()));

    m_nid.hWnd = pNotifyWnd->m_hWnd;

    ASSERT(uCbMsg ==  0||uCbMsg>=WM_USER);

    m_nid.uCallbackMessage = uCbMsg; 
}

BOOL CTrayIcon::SetIcon(UINT uID,LPWSTR lpTip) 

    HICON hIcon = NULL; 
     if(uID) 
    { 
        m_nid.uID = uID; // 更改当前对象的uID 
        hIcon = AfxGetApp()->LoadIconW(uID); 
    } 
     return SetIcon(hIcon,lpTip); 
}

BOOL CTrayIcon::SetIcon(HICON hIcon, LPWSTR lpTip) 

    UINT uMsg; 
    m_nid.uFlags =  0;

     if(hIcon) 
    { 
        uMsg = m_nid.hIcon?NIM_MODIFY:NIM_ADD; // 当前如果存在ICON,就修改 
        m_nid.hIcon = hIcon; 
        m_nid.uFlags = NIF_ICON; // 设置标志

        
// 如果存在hIcon才进行设置提示 
         if(lpTip) 
        { 
            ::lstrcpyn(m_nid.szTip,(LPCWSTR)lpTip, sizeof(m_nid.szTip)); 
        } 
         if(m_nid.szTip[ 0]) 
            m_nid.uFlags |= NIF_TIP; // 设置标志 
    } 
     else // 删除图标 
    { 
         // 如果当前m_nid的hIcon为null,那么直接结束,啥都不用干啦 
         if(m_nid.hIcon==NULL)     return  true;
        uMsg = NIM_DELETE;     // 如果当前m_nid的hIcon不为null,删除图标 
        m_nid.hIcon = NULL; 
    }

     if(m_nid.uCallbackMessage && m_nid.hWnd) 
        m_nid.uFlags |= NIF_MESSAGE;

    BOOL bRet = ::Shell_NotifyIcon(uMsg,&m_nid);

     // 把失败和NIM_DELETE的操作放在这里 
     if(!bRet)    m_nid.hIcon = NULL;
     return bRet; 


LRESULT CTrayIcon::OnTrayNotification(WPARAM uID, LPARAM lEvent) 

     if(uID != m_nid.uID ||         // 如果uID不属于此对象 
        (lEvent != WM_RBUTTONUP && lEvent != WM_LBUTTONDBLCLK)) 
         return  0;

    CMenu menu;  // 知道吗,MFC的封装我觉得在这里已经表现得淋漓尽致了。
     if(!menu.LoadMenuW(m_nid.uID)) 
         return  0;

    CMenu * pSubMenu = menu.GetSubMenu( 0);

     if(!pSubMenu) 
         return  0;

     if(lEvent == WM_RBUTTONUP) 
    { 
        CPoint mouse; 
        ::GetCursorPos(&mouse); 
        ::SetForegroundWindow(m_nid.hWnd); 
        ::TrackPopupMenu(pSubMenu->m_hMenu,TRUE,mouse.x,mouse.y, 0
            m_nid.hWnd,NULL); 
    } 
     if(lEvent == WM_LBUTTONDBLCLK) 
    { 
        ::SendMessage(m_nid.hWnd,WM_COMMAND, 
            pSubMenu->GetMenuItemID( 0), 0); 
    } 
     return  1
}

BEGIN_MESSAGE_MAP(CTrayIcon, CCmdTarget) 
END_MESSAGE_MAP()

使用方法 

由于这个类的父类是CCmdTarget,所以,可以接受命令消息(菜单的消息),我们可以自定义添加消息。 

在需要使用“托盘”的窗口类中声明一个CTrayIcon的对象,然后在OnCreate函数当中调用即可。

int CTrayIconShellDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
     if (CDialog::OnCreate(lpCreateStruct) == - 1)
         return - 1;

     //  TODO:  在此添加您专用的创建代码
    TCHAR tip[ 100] = TEXT( " 捣乱小子 ");
    TrayIcon.SetNotificationWnd( this,WM_NOTIFY_MSG);
    TrayIcon.SetIcon(IDR_MAINFRAME,tip);
     return  0;
}

 总结 

  在这一次实验之后,我更加仰慕和崇尚面向对象(OO)的思想,如果编程思路清晰,数据设计得当,接口功能完善,以及接口与接口之间有良好的信息沟通,OO能让你在程序设计当中游刃有余,所以在平时的时候要养成面向对象的思考习惯。

  在C++面向对象编程的过程当中,会遇到一些公共的接口,这些接口只完成某些固定的操作,与其他的接口的联系不是非常的紧密的时候,我们可以将此接口设计为static模式,这样就不会让每个对象都担负着那么多的方法了。

 

本文完 Monday, April 23, 2012(更新)

捣乱小子 http://www.cnblogs.com/daoluanxiaozi/

你可能感兴趣的:(MFC中托盘(TRAYICON)实现)