系统托盘技巧

来源:互联网 发布:js get post 区别 编辑:程序博客网 时间:2024/04/30 08:11

    相信大家都注意过,像QQ、MSN、各种杀毒软件运行时系统右下角都会出现一个小图标,我们自己写的程序运行时怎么就没有呢?其实要实现并不难,没去了解现在.Net下怎么实现,在这只是简单讲讲使用MFC在VC5的年代就已经可以轻易实现技巧(尘封N年的技术了,但用起来仍然能够很好的满足需求)

 

    去查查MSDN理解Shell_NotifyIcon函数和NOTIFYICONDATA结构后你基本上已经可以自己实现了,要实现这个功能关键的步骤是:

    1、加入你自己的NOTIFYICONDATA成员变量tind,给它附上满足你显示要求的值(ICON、TIP等等);

    2、在你觉得“合适”的时候调用Shell_NotifyIcon,传入关键的NIM_ADD和你刚刚构造的tind,恭喜你,托盘图标已经加上了。

    3、写程序要负责,好的习惯当然是在你结束程序的时候销毁这个托盘图标了,不销毁也不会出错,但你还想人家再运行你的程序的话,你最好还是加上几行代码吧。跟加入图标一样,再调用Shell_NotifyIcon,但这次传入的关键参数变为NIM_DELETE就OK了。

 

    很简单是吧,如果习惯像我这样先入为主喜欢看代码猜功能的,哪你可以看看我的这个实现了,关键的都给加粗了。

 

#define MYTIP "我在帮你监听着 ^_^"
#define MYTIPX "别烦我睡着呢! -_-.zZ"
#define MYTIPY "你有信息啦! ~_~ "
#define MYTIPZ "我还没起来,设定吧 >_<"
#define MYICON    1000

NOTIFYICONDATA tnid;

BOOL MyTaskBarAddIcon();

BOOL MyTaskBarDeleteIcon();

 

BOOL CKenerDlg::MyTaskBarAddIcon()
{
    BOOL res;
    HICON hicon;

    hicon =LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICONBNOSET));
    tnid.cbSize=sizeof(NOTIFYICONDATA);
    tnid.hWnd=m_hWnd;
    tnid.uID=MYICON;
    tnid.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
    tnid.uCallbackMessage=MYWM_NOTIFYICON;
    tnid.hIcon=hicon;
    lstrcpyn(tnid.szTip,(online?MYTIP:MYTIPZ),sizeof(MYTIPZ));
    res=Shell_NotifyIcon(NIM_ADD,&tnid);
    if (hicon)
        DestroyIcon(hicon);
    return res;
}

BOOL CKenerDlg::MyTaskBarDeleteIcon()
{
    BOOL res;
    tnid.cbSize=sizeof(NOTIFYICONDATA);
    tnid.hWnd=m_hWnd;
    tnid.uID=MYICON;
    res=Shell_NotifyIcon(NIM_DELETE,&tnid);
    return res;
}

 

    现在还有一个问题,哪就是什么时候是加入图标的“合适”的时候呢?最简单的方法当然是在启动的时候了,OnInitDialog()里调用MyTaskBarAddIcon是一个比较好的方案(大多数实现都是这样做的)。

 

    当然,加入图标只是我们最低的要求,我们可能还希望我们的图标能够根据状态不同有所变化,而且有了托盘图标我们的程序最小化时就可以完全隐藏了(不出现在任务栏上),更专业一点我们的图标上应该能够响应鼠标事件,如左键单击显示,右键单击出菜单等等吧,哪就接着说吧。

 

    先说第一个,根据状态图标变换:

    要知道,图标是你指定的,你可以根据不同的状态指定装载时用不同的图标,另外,在你需要改变图标的时候再次调用Shell_NotifyIcon,传入关键的NIM_MODIFY,OK了。想你的图标更个性点?来个动画怎么样?加个Timer轮换图标就有动画效果了。

 

BOOL MyTaskBarChangeIcon(bool);

 

BOOL CKenerDlg::MyTaskBarChangeIcon(bool get)
{
    BOOL res;
    HICON hicon;
    hicon=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICONBMESSAGE));
    tnid.cbSize=sizeof(NOTIFYICONDATA);
    tnid.hWnd=m_hWnd;
    tnid.uID=MYICON;
    tnid.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
    tnid.uCallbackMessage=MYWM_NOTIFYICON;
    tnid.hIcon=hicon;
    lstrcpyn(tnid.szTip,MYTIPY,sizeof(MYTIPY));
    res=Shell_NotifyIcon(NIM_MODIFY,&tnid);
    if (hicon)
        DestroyIcon(hicon);
    return res;
}

 

   接着说第二个要求,最小化程序时任务栏上完全隐藏:

   隐藏没什么技术含量吧,ShowWindow(SW_HIDE)就OK了,关键是如何捕捉到系统最小化的事件?系统有WM_MINIMIZED是个隐藏的消息,你不能通过简单的消息响应去捕捉这个事件,所以得绕一绕了,捕捉WM_SIZE后判断nType是不是等于SIZE_MINIMIZED是可行的:

 

void CKenerDlg::OnSize(UINT nType, int cx, int cy)
{
    __super::OnSize(nType, cx, cy);
    if   (nType   ==   SIZE_MINIMIZED)  
    {  
        ShowWindow(SW_HIDE);

    }  
}

 

    如果你做了第二个要求,哪第三个要求你是逃不过了,因为现在你的程序最小化后你再也没办法重新打开它了,调用任务管理器结束程序吧!

    当你完全隐藏了你的程序后你的程序唯一可见的就是右下角那个图标了,而你还没有给他写响应事件,它现在只是个装饰品,好吧,进入刚才说的第三个需求:图标上的事件响应。

   标准的MFC,用户自定义消息吧!

 

.h:

#define MYWM_NOTIFYICON WM_USER+100

afx_msg LRESULT OnMyNotifyIcon(WPARAM wParam,LPARAM lParam);

 

.cpp:

BEGIN_MESSAGE_MAP(CKenerDlg, CDialog)

    ON_MESSAGE(MYWM_NOTIFYICON,OnMyNotifyIcon)

END_MESSAGE_MAP()

 

LRESULT CKenerDlg::OnMyNotifyIcon(WPARAM wParam,LPARAM lParam)
{
    switch (lParam)
    {
    case WM_LBUTTONDOWN:
        //左键单击,做你想做的

       break;
    case WM_LBUTTONDBLCLK:
        //左键双击,你把人逼急了,双击你还不显示窗口?别忘了不能简单的SW_SHOW啊,你是最小化时隐藏的,SW_SHOW后还是最小化。

        ShowWindow(SW_SHOWNORMAL);

        break;
    case WM_RBUTTONDOWN:

        //右键单击:该出菜单了,怎么出菜单?资源里添加啊IDR_TRAYMENU!
        if (wParam==MYICON)
        {
            CMenu *pt,t;
            CPoint pp;
            GetCursorPos(&pp);
            t.LoadMenu(IDR_TRAYMENU);
            pt=t.GetSubMenu(0);
            ::SetForegroundWindow(tnid.hWnd);
            ::TrackPopupMenu(pt->m_hMenu,0,pp.x,pp.y,0,tnid.hWnd,NULL);
            ::PostMessage(tnid.hWnd,WM_NULL,0,0);
            t.DestroyMenu();
        }
        break;
    default:
        break;
    }
    return 0L;
}

 

    好了,没想过要写那么长,看到这里已经基本上满足大多数的功能需求了吧,为你自己的小软件增加一个更显专业的托盘图标吧!:)

    看看我的效果:

 

托盘效果

原创粉丝点击