MFC程序添加系统托盘 博客
  • 暖风 等级 N0
    2018-11-21 15:27

    看到火哥给他的程序加上了系统托盘,我的没有很是不爽。于是花了几分钟找了些资料,给自己的也加上了系统托盘。现在将我的实现步骤分享一下。

    先来解释下什么是系统托盘: 其实准确的说法应该是任务栏通知区域。系统托盘区可以看着是任务栏下的一个子工具栏。(任务栏最右面)。一般像QQ,酷狗,杀软,百度云等很多程序都会在系统托盘里显示图标。

    我们需要完成的任务:

        1.隐藏任务栏的程序图标。

        2.系统托盘创建图标 

        3.托盘图标右键菜单及菜单消息处理函数

        4.添加托盘消息处理函数

        5.销毁托盘图标

     1.隐藏任务栏的程序图标。

        这个是最简单的,我们只需要在主窗口的OnInitDialog()函数里加上 ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);修改主窗口的属性就可以了。

    2.系统托盘创建图标

        1.添加系统托盘首先要了解一个结构体,_NOTIFYICONDATA ,下面列出了这个结构体的成员,并对我们需要关注的成员加上了注释。

    /***该系统需要处理的任务栏状态区的消息***/  
    typedef struct _NOTIFYICONDATA {  
        DWORD cbSize;        //结构体的大小
        HWND hWnd;           //窗口的句柄  
        UINT uID;            //应用程序定义的任务栏图标的标识符  
        UINT uFlags;         //此成员表明具体哪些其他成员为合法数据  
        UINT uCallbackMessage;   //自定义的消息标识  
        HICON hIcon;         //托盘图标的句柄
        TCHAR szTip[64];     //指向一个以/0结束的字符串的指针,当鼠标指向系统托盘时现实的提示  
        DWORD dwState;       
        DWORD dwStateMask;   
        TCHAR szInfo[256];   //指向用来表示气泡内容的字符串。     union {  
            UINT uTimeout;   //表示气球提示超时的时间,单位为毫秒,此时间后气球提示将消失  
            UINT uVersion;   //
        };  
        TCHAR szInfoTitle[64];   //指向用来表示气泡标题的字符串。
        DWORD dwInfoFlags;   
        GUID guidItem;       
        HICON hBalloonIcon;  
    } NOTIFYICONDATA, *PNOTIFYICONDATA;  

        2.在主窗口的类中(XXXXXDlg.h XXXXX是你的工程名)添加成员变量 NOTIFYICONDATA m_nid;

        3. 在XXXXDlg.cpp(XXXXX是你的工程名)文件中加上 #define WM_SYSTEMTRAY WM_USER+100 。其中100的值可以自定义。 这个宏也可以加到其他地方。看自己习惯。

        4.然后实现对改成员的初始化函数

    VOID CControlCenterDlg::InitNid()//CControlCenterDlg 改成你自己的主窗口名
    {
    m_nid.cbSize = sizeof(NOTIFYICONDATA);
    m_nid.hWnd = m_hWnd;
    m_nid.uID = IDR_MAINFRAME;
    m_nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;
    m_nid.uCallbackMessage = WM_SYSTEMTRAY; //自定义消息
    m_nid.hIcon = m_hIcon; //这里的是程序的图标,如果想修改可以添加图标资源, 把 这行代码改成m_nid.hIcon = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(/* 你添加的图标的ID*/));
    strcpy_s(m_nid.szTip, "滴水爱达人");
    strcpy_s(m_nid.szInfo, _T("www.bcdaren.com"));
    strcpy_s(m_nid.szInfoTitle, _T("爱达人官网"));
    m_nid.dwInfoFlags = NIIF_INFO;
    m_nid.uTimeout = 2000; //这个时间的长短是气泡显示的时间
    ::Shell_NotifyIcon(NIM_ADD, &m_nid);

    然后在该类的OnInitDialog()函数中调用初始化函数InitNid()。这个时候编译运行已经可以在系统托盘里看到图标了。但是我们还没有添加消息处理 和 右键菜单以及程序退出后托盘中的图标不会自动消失  

    3.托盘图标右键菜单     

        添加右键菜单的方法有很多,这里我只举例最简单的。

        1.在程序的资源视图中添加菜单。(资源文件夹上右键-->添加资源,选择Menu,然后点新建 )。如下图所示,可以直接输入菜单的名称,比如我先输入了右键菜单,输入完以后又在他的下面输入了“编程达人”和“退出”两项。

           

      2.选中编程达人,右键-->添加事件处理程序


       

         3.在弹出的对话框里选择要关联的类

        

        4.在生成的代码中,加上自己的代码。我这里实现的功能是显示主窗口

        ShowWindow(SW_SHOWNORMAL);

        5.同样的方法实现退出项,并加上如下代码

    	OnCancel();

    4.添加托盘消息处理函数

        右键菜单加好了,但是我们现在点击系统托盘图标的时候是没有反应的,因为我们还没有添加对应的消息处理函数.这里我提供里两种方法,看个人选择。

        第一种

        1.在XXXXXDlg类中加上如下函数声明: afx_msg LRESULT onShowTask(WPARAM wParam, LPARAM lParam);


        2. 在XXXXXDlg.cpp文件的BEGIN_MESSAGE_MAP 和 END_MESSAGE_MAP()中间加上如下代码 ON_MESSAGE(WM_SYSTEMTRAY, onShowTask)//注意不要有分号

        3.实现消息处理函数的代码

    	switch (lParam)
    {
    case WM_RBUTTONUP://右键单击 弹出菜单
    {
    CMenu menu;
    menu.LoadMenu(IDR_MENU2);
    CMenu *pPopUp = menu.GetSubMenu(0);
    CPoint pt;
    GetCursorPos(&pt);
    SetForegroundWindow(); //顶层显示主窗口
    pPopUp->TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);//确定弹出式菜单的位置
    HMENU hmenu = menu.Detach(); //资源回收
    menu.DestroyMenu();
    }break;

    case WM_LBUTTONUP://左键单击显示主窗口
    {
    this->ShowWindow(SW_SHOWNORMAL); //简单的显示主窗口完事儿
    }break;
    }
    return 0;

    加上代码以后就完成啦,可以弹出右键菜单 和单击图标显示主窗口了。

       第二种

        我们可以重载WindowProc函数。 高版本编译器中添加重载函数的方法如下:

        1.在类视图中选择我们需要重载WindowProc函数的类,右键-->属性。 在属性对话框中点击 重载按钮,然后找到 WindowProc函数,选择添加。

        

    添加代码实现对消息的处理:

    LRESULT CMFCApplication3Dlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
    switch (message)
    {
    case WM_SYSTEMTRAY: //自定义消息

    if (lParam == WM_LBUTTONUP)
    {
    ShowWindow(SW_SHOWNORMAL);
    break;
    }
    if (lParam == WM_RBUTTONDOWN)
    {
    //右击弹出托盘菜单
    CMenu menu;
    menu.LoadMenu(IDR_MENU1);
    CMenu *pPopUp = menu.GetSubMenu(0);
    CPoint pt;
    GetCursorPos(&pt);

    SetForegroundWindow();
    pPopUp->TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);
    SetForegroundWindow(); //顶层显示主窗口
    HMENU hmenu = menu.Detach(); //资源回收
    menu.DestroyMenu();
    }
    }

    return CDialogEx::WindowProc(message, wParam, lParam);//这句代码千万不要删除掉哦!
    }


    5.销毁托盘图标    

     当我们点击窗口的关闭按钮和右键菜单中的退出的时候,托盘中的图标是不能自动消失的。我们需要做的是重载OnCancel函数,方法和重载WindowProc函数一样,然后在OnCancel函数中加上::Shell_NotifyIcon(NIM_DELETE, &m_nid);这个时候我们退出程序以后,系统托盘中的图标也就消失了。

    应该还有其他的方式实现系统托盘,有什么问题和疑问欢迎留言交流。

  • 浏览 103
  • 点赞 0
  • 收藏 1
  • 分享 4
  • 查看云盘地址请登录
  • 点赞 已赞 收藏 已收藏
评论
    页 到
    talk top
    展开
    >