zoukankan      html  css  js  c++  java
  • 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/

    更多请访问:http://daoluan.net
  • 相关阅读:
    对比度亮度调整及滑动条应用
    多项式求逆
    【转载】android手势翻页效果
    [Android实例] webview 实现翻页功能
    (转载)Android 平滑和立体翻页效果1
    android背景选择器selector用法
    WebView调用javaScript
    (转载自eoe论坛)Android上百实例源码分析以及开源分析集合打包
    android用户界面之WebView教程实例汇总
    WebView使用总结(应用函数与JS函数互相调用)
  • 原文地址:https://www.cnblogs.com/daoluanxiaozi/p/2246733.html
Copyright © 2011-2022 走看看