Mfc系统托盘

31 篇文章 1 订阅
17 篇文章 0 订阅

以下内容便是看完《系统托盘编程完全指南》后写下来的!

这里将比较系统地描述托盘应用的编程。
MFC框架没有提供任何现成的类应用于系统托盘UI,那么如何将表示应用程序的图标添加到任务栏中呢?方法很简单,只用到一个API函数,它就是Shell_NotifyIcon。这个函数本身也相当容易理解和使用。看看它的原型就知道了:

BOOL Shell_NotifyIcon(
    DWORD dwMessage, 
    PNOTIFYICONDATA pnid
);

第一个参数dwMessage类型为DWORD,表示要进行的动作,它可以是下面的值之一:

NIM_ADD:             添加一个图标到任务栏。
NIM_MODIFY:       修改状态栏区域的图标。
NIM_DELETE:       删除状态栏区域的图标。
NIM_SETFOCUS:  将焦点返回到任务栏通知区域。当完成用户界面操作时,任务栏图标必须用此消息。
例如,如果任务栏图标正显示上下文菜单,但用户按下"ESCAPE"键取消操作,这时就必须用此消息将焦点返回到任务栏通知区域。 
NIM_SETVERSION:指示任务栏按照相应的动态库版本工作。

第二个参数pnid是NOTIFYICONDATA结构的地址,其内容视dwMessage的值而定。这个结构在SHELLAPI.H文件中定义如下:

typedef struct _NOTIFYICONDATA {
    DWORD cbSize;             // 结构大小(sizeof struct),必须设置
    HWND hWnd;                // 发送通知消息的窗口句柄
    UINT uID;                 //  图标ID ( 由回调函数的WPARAM 指定)
    UINT uFlags;            
    UINT uCallbackMessage;    // 消息被发送到此窗口过程
    HICON hIcon;              // 图标句柄
    CHAR szTip[64];           // 提示文本
} NOTIFYICONDATA;

uFlags的值:
#define NIF_MESSAGE 0x1     // 表示uCallbackMessage 有效
#define NIF_ICON    0x2     // 表示hIcon 有效
#define NIF_TIP     0x4     // 表示szTip 有效

有关Shell_NotifyIcon函数的详细使用细节请参考MSDN。

NOTIFYICONDATA结构中的 
hWnd 是"拥有" 图标的窗口句柄。
uID可以是任何标示托盘图标的ID(如果有多个图标),一般使用资源ID。
uFlags指明其余的几个成员(hIcon、uCallbackMessage和szTip)的值是否有效。
uCallbackMessage为一个自定义的消息,当用户在该图标上作用一些鼠标动作时,将向hWnd成员中指定的窗口发出该消息,可以自定义该消息。
hIcon可以是任何图标的句柄,包括预定义的系统图标,如IDI_HAND、IDI_QUESTION、IDI_EXCLAMATION、或者Windows的徽标IDI_WINLOGO。
szTip为一字符数组,当鼠标停留在该图标上时,将其内容显示在浮动的提示信息框中。

图标的显示并不难,关键是事件的处理。 当用户将鼠标移到图标上或者在图标上单击鼠标时,为了得到通知消息,你可以将自己的消息ID赋给uCallbackMessage,并设置NIF_MESSAGE标志。当用户在图标上移动或单击鼠标时,Windows将用hWnd指定的窗口句柄调用你建立的窗口过程;消息ID在uCallbackMessage中指定,uID的值即为wParam,lParam为鼠标事件,如WM_LBUTTONDOWN等。


这里先利用API函数,单独在一个文档框架中完成系统托盘功能。

程序启动是将界面隐藏,比较容易实现,只需在CMainFrane类中重载PreCreateWindow()函数并将其按如下代码进行修改即可:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT &cs)
{
    ...
    cs.style = WS_POPUP;
    cs.dwExStyle |= WS_EX_TOOLWINDOW;
    return TRUE; 
}

初始化NOTIFYICONDATA结构,必须在程序一开始执行时就完成,所以要在主框架类的OnCreate()函数中添加代码:

NOTIFYICONDATA tnd;
tnd.cbSize = sizeof(NOTIFYICONDATA);
tnd.hWnd = this->m_hWnd;
tnd.uID = IDR_MAINFRAME;
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnd.uCallbackMessage = WM_TRAY;    //WM_TRAY为自定义消息WM_USER+103
tnd.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
strcpy(tnd.szTip, "vic.MINg's System Tray");
Shell_NotifyIcon(NIM_ADD, &tnd);

为了使人机界面更友好,与用户更好的进行交互,使用户在该图标上双击鼠标左键时能弹出程序主界面,再次双击则隐藏。如果用户右键点击图标,则弹出浮动菜单供用户选择使用。可以在自定义消息WM_TRAY的响应函数里加入对鼠标左、右键的处理过程:

//MainFrm.h头文件,自定义消息
//{{AFX_MSG(CMainFrame)
    ...
    afx_msg void OnTray(WPARAM wParam,LPARAM lParam);
//}}AFX_MSG
    DECLARE_MESSAGE_MAP()

//MainFrm.cpp源文件,消息处理
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
    ...
    ON_MESSAGE(WM_TRAY,OnTray)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CMainFrame::OnTray(WPARAM wParam,LPARAM lParam)
{
    // 发出该消息的图标的ID
    UINT uID;
 
    // 鼠标动作
    UINT uMouseMsg;
    POINT pt;
    uID = (UINT) wParam;
    uMouseMsg = (UINT) lParam;
    CMenu menu;
    SetForegroundWindow();
 
    // 如果是单击右键
    if (uMouseMsg == WM_RBUTTONDOWN)
    {
        switch(uID)
        {
        case IDR_MAINFRAME: // 如果是我们的图标
            // 取得鼠标位置
            GetCursorPos(&pt);
   
            // 执行相应操作
            menu.LoadMenu(IDR_BEGINMENU);
            pMenu = menu.GetSubMenu(0);
            ASSERT(pMenu != 0);
            pMenu->TrackPopupMenu(0, pt.x, pt.y, this);
            break;
        default:
            break;
        }
    }
    else if (uMouseMsg == WM_LBUTTONDBLCLK) // 如果是单击左键
    {
        static bool isMax = false;
        switch(uID)
        {
        case IDR_MAINFRAME:
            if (isMax == false)
            {
                OnMainWindow();
                isMax = true;
            }
            else
            {
                ShowWindow(SW_HIDE);
                ModifyStyle(WS_CAPTION | FWS_PREFIXTITLE | WS_SYSMENU | WS_MINIMIZEBOX, WS_POPUP);
                ModifyStyleEx(WS_EX_TOPMOST, WS_EX_TOOLWINDOW);
                isMax = false;
            }
            break;
        default:
            break;
        }
    }
    return; 
}

对鼠标右键弹出的浮动菜单项的处理需要通过自定义消息来响应,这将不能通过ClassWizard向导来完成而要一步步地手动添加。

首先在头文件里添加响应函数的声明:

//{{AFX_MSG(CMainFrame)        
...
afx_msg void OnMainWindow();
afx_msg void OnExit();
afx_msg void OnSupport();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

然后,在源文件里添加消息映射:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
    ...
    ON_COMMAND(ID_MAIN, OnMainWindow)
    ON_COMMAND(ID_EXIT, OnExit)
    ON_COMMAND(ID_SUPPORT, OnSupport)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

最后在其各自的实现函数中加入与其菜单项对应的功能代码即可:

void CMainFrame::OnMainWindow()
{
    ModifyStyle(WS_POPUP, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
    ModifyStyleEx(WS_EX_TOOLWINDOW, WS_EX_TOPMOST);
    ShowWindow(SW_SHOW);
}

void CMainFrame::OnSupport()
{
    AfxMessageBox("vic.MINg");
}

void CMainFrame::OnExit()
{
    NOTIFYICONDATA tnd;
    tnd.cbSize = sizeof(NOTIFYICONDATA);
    tnd.hWnd = this->m_hWnd;
    //保证删除的是本程序的图标
    tnd.uID = IDR_MAINFRAME;
    Shell_NotifyIcon(NIM_DELETE, &tnd);
    AfxPostQuitMessage(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值