注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

fancye的博客

 
 
 

日志

 
 

VC系统托盘编程指南  

2008-05-11 00:31:57|  分类: Vc |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

参考自:http://hi.baidu.com/zoupng/blog

转载:http://blog.csdn.net/TurkeyCock/archive/2008/02/27/2125837.aspx

现在比较流行的软件都会在系统托盘上显示一个图标,左键点击该图标时可以显示/隐藏软件主界面,节省任务栏的空间;右键点击该图标会出现一个菜单,显示一些常用的功能。那么这是怎么实现的呢?其实很简单,只需要一个API函数就搞定了,跟我一起看吧~
    首先看一个结构体:
    typedef struct _NOTIFYICONDATA {
        DWORD cbSize;
        HWND hWnd;
        UINT uID;
        UINT uFlags;
        UINT uCallbackMessage;
        HICON hIcon;
        TCHAR szTip[64];
        DWORD dwState; //Version 5.0
        DWORD dwStateMask; //Version 5.0
        TCHAR szInfo[256]; //Version 5.0
        union {
            UINT uTimeout; //Version 5.0
            UINT uVersion; //Version 5.0
        } DUMMYUNIONNAME;
        TCHAR szInfoTitle[64]; //Version 5.0
        DWORD dwInfoFlags; //Version 5.0
    } NOTIFYICONDATA, *PNOTIFYICONDATA;

    使用该结构指定托盘图标的相关信息,其中Version 5.0的部分表示的是Shell DLL的版本号,可以用DllGetVersion获得当前系统的DLL版本。出于兼容的考虑,该部分很少使用。
    cbSize: NOTIFYICONDATA结构的大小,sizeof(NOTIFYICONDATA)
    hWnd:接收托盘通知的窗口句柄
    uID:托盘图标的ID号,该ID与hWnd一起唯一标识了一个托盘图标的身份,因此该ID号不能重复,一般使用与该图标相关联的菜单的ID
    uFlags:为下列值的组合
    NIF_ICON:表示结构中的hIcon有效
    NIF_MESSAGE:表示结构中的uCallbackMessage有效
    NIF_TIP:表示结构中的szTip有效
    NIF_STATE:表示结构中的dwState和dwStateMask有效
    NIF_INFO:使用气球型的托盘提示代替传统的方框型托盘提示.结构中的szInfo, uTimeout, szInfoTitle,和dwInfoFlags有效
    uCallbackMessage:托盘消息,当托盘区域有鼠标事件(如鼠标移动,单击等)产生时,会向接收窗口发送该消息,进行相应的处理
    hIcon:托盘图标句柄
    szTip:托盘提示字符
    好了,就介绍这么多,下面接收这个API函数Shell_NotifyIcon:
    BOOL Shell_NotifyIcon(
        DWORD dwMessage,
        PNOTIFYICONDATA pnid
    );

    dwMessage:为下列值之一
        NIM_ADD:添加托盘图标
        NIM_DELETE:删除图盘图标
        NIM_MODIFY:修改托盘图标
        NIM_SETFOCUS:Version 5.0
        NIM_SETVERSION:Version 5.0
        pnid:NOTIFYICONDATA结构的指针

    好了,下面言归正传,开始着手编程了~
    我们分为以下几步逐步分析:
        初始化
        添加/修改/移除图标
        添加托盘消息响应函数
        添加菜单消息处理函数
    (1)初始化
    首先要声明一个NOTIFYICONDATA成员变量:
    NOTIFYICONDATA m_nid;
    然后在资源面板中添加一个菜单资源IDR_TRAYMENU和一个图标资源IDI_RED
由于我们要处理鼠标消息,因此先定义一个用户自定义消息:
    #define UM_ TRAYNOTIFICATION (WM_USER+100)
    然后对该结构的成员进行初始化:
    void InitTray()
    {
           //初始化m_nid
           m_nid.cbSize = sizeof(NOTIFYICONDATA);
           m_nid.hWnd = this->m_hWnd;
           m_nid.uID = IDR_TRAYMENU;
           m_nid.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE;
           m_nid.hIcon = AfxGetApp()->LoadIcon(IDI_RED);
           strcpy (m_nid.szTip, "我的托盘听我的");
           m_nid.uCallbackMessage = UM_TRAYNOTIFICATION;
    }

    上面的程序我就不多说了,相信大家都能看懂。
    (2)添加/修改/移除图标
    这个更简单,直接调用Shell_NotifyIcon函数就可以了:
   //向托盘添加图标
    void AddTray()
    {
           Shell_NotifyIcon(NIM_ADD, &m_nid);
    }

    //移除托盘图标,在程序退出时一定要记得调用,否则图标会残留在托盘上
    void RemoveTray()
    {
           Shell_NotifyIcon(NIM_DELETE, &m_nid);
    }

    //修改图标,QQ登陆时托盘上的动态效果不用我教了吧?
    void ModifyTray(UINT uId)//参数为要显示的Icon的ID号
    {
           m_nid.hIcon = AfxGetApp()->LoadIcon(uId);
           Shell_NotifyIcon(NIM_MODIFY, &m_nid);
    }

   (3)添加托盘消息响应函数
    这个其实就是响应自定义消息,忘了?好,那我们一起复习一下吧~
    首先定义消息标识符(第1步已经定义过了):
    #define UM_ TRAYNOTIFICATION (WM_USER+100)
    然后在头文件的DECLARE_MESSAGE_MAP()之前定义消息响应函数:
    afx_msg LRESULT OnTrayNotification(WPARAM wId, LPARAM lEvent);
    其中两个参数分别为图标ID号和鼠标事件

补充:必须在cpp文件此处添加代码将事件与响应函数对应:

BEGIN_MESSAGE_MAP(CxxxDlg, CDialog)
    //{{AFX_MSG_MAP(CxxxDlg)
    …………
    ON_MESSAGE(WM_TRAYNOTIFICATION, OnTrayNotification)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

    最后在cpp文件里实现该函数:
    LRESULT CXXXDlg::OnTrayNotification(WPARAM wId, LPARAM lEvent)
    {
           if(wId!=m_nid.uID
            || (lEvent!=WM_LBUTTONUP && lEvent!=WM_RBUTTONUP))
            return 0;

          //加载菜单
           CMenu menu;
           if(!menu.LoadMenu(wId))
                return 0;
          //获取弹出菜单
           CMenu *pSubMenu = menu.GetSubMenu(0);
           if(!pSubMenu)
                return 0;

           if(lEvent == WM_RBUTTONUP)
           {
                //设置默认菜单项
                 ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);

                //获取鼠标位置
                 CPoint mouse;
                 GetCursorPos(&mouse);

                //设置快捷菜单
                 ::SetForegroundWindow(m_nid.hWnd);
                 ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0, m_nid.hWnd, NULL);
           }
           else
           {
                 ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
           }

           return 1;
    }
    下面逐句解释上面这段代码:
    首先判断发送该消息的图标的ID是否等于m_nid中的ID号,再判断接收到的鼠标消息是否为左键单击消息WM_LBUTTONUP或右键单击消息WM_RBUTTONUP,如果不是则不对该消息进行响应。
    然后加载菜单,右键单击时显示该菜单。先用LoadMenu()加载顶层菜单,再用GetSubMenu()获得一级子菜单。
当鼠标事件为右键单击时,显示菜单,否则(即左键单击时)用::SendMessage()向接收窗口发送命令消息,进行相应的处理。:: SetMenuDefaultItem()用于设置菜单的默认选择项,以粗体显示。最后用::TrackPopupMenu()函数显示右键菜单。该菜单 可能不会像通常那样马上消失,这是因为从弹出菜单接收消息的窗口必须是前景窗口。调用::SetForegroundWindow()函数就可以纠正该错 误。
    (4)添加菜单消息处理函数
    在右键菜单中选择一项后,就会发送命令消息WM_COMMAND,在ClassWizard里添加WM_COMMAND的消息处理函数:
   BOOL CZYJReportDlg::OnCommand(WPARAM wParam, LPARAM lParam)
    {
           // TODO: Add your specialized code here and/or call the base class
           switch(LOWORD(wParam))
           {
           case ID_SHOWHIDE:
                 ShowWindow(m_bShow?SW_HIDE:SW_SHOW);
                 m_bShow = !m_bShow;
                 break;
           case ID_EXIT:
                 RemoveTray();
                 PostQuitMessage(0);
                 break;
           case ID_ABOUT:
                 CAboutDlg about;
                 about.DoModal();
                 break;
           }

           return CDialog::OnCommand(wParam, lParam);
    }
    其中第一个参数wParam的低字节LOWORD(wParam)标识了所选子菜单的ID,根据所选的菜单项执行相应的程序。
      OK,以上介绍了写托盘程序的完整过程,是不是很简单呢?当然托盘编程的内容还远不止这些,比如Version 5.0的部分,还可以添加很多漂亮的效果,欢迎大家跟我一起探讨!

  评论这张
 
阅读(74)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018