天天看点

Win32实现系统任务栏的小图标

A.第一种方法是通过MFC来实现的,从网上找的,red已经注明。

如果我们在程序最小化时采用在系统任务栏中的小图标,就象金山词霸一样,单击左键可以

实现最大最小化,单击右键有快捷菜单,那么整个程序会显的很简洁。

采用SDK的Shell_NotifyIcon等API可以实现系统任务栏的小图标,但是程序员必须仔细理解

这些API的具体用法,Chris Maunder 开发的系统任务栏类CSystemTray封装了这些API的功能,

使MFC程序员可以方便的实现具有系统任务栏小图标的程序。

---- CsytemTray的功能很多,看一看它的成员函数就可以知道其大致功能了。

  BOOL Enabled() { return m_bEnabled; }

  BOOL Visible() { return !m_bHidden; }

  //Create the tray icon

  Create(CWnd* pWnd, UINT uCallbackMessage,

  LPCTSTR szTip, HICON icon, UINT uID);

  //Change or retrieve the Tooltip text

  BOOL  SetTooltipText(LPCTSTR pszTooltipText);

  BOOL  SetTooltipText(UINT nID);

  CString GetTooltipText() const;

  //Change or retrieve the icon displayed

  BOOL  SetIcon(HICON hIcon);

  BOOL  SetIcon(LPCTSTR lpIconName);

  BOOL  SetIcon(UINT nIDResource);

  BOOL  SetStandardIcon(LPCTSTR lpIconName);

  BOOL  SetStandardIcon(UINT nIDResource);

  HICON GetIcon() const;

  void   HideIcon();

  void   ShowIcon();

  void   RemoveIcon();

  void   MoveToRight();

  //Change or retrieve the window to

  send notification messages to

  BOOL  SetNotificationWnd(CWnd* pNotifyWnd);

  CWnd* GetNotificationWnd() const;

下面是实现步骤:

(1)首先在Project中加入CsystemTray类的.cpp和.h文件,这样在Workspace的

   ClassView中可以看到CsystemTray类。

(2)然后在CframeWnd的派生类的头文件中

    a.加入WM_ICON_NOTIFY 的消息定义

      #define WM_ICON_NOTIFY WM_USER+1

    b.在CframeWnd的派生类中添加变量

      CSystemTray m_TrayIcon;

    c.在CframeWnd的派生类的CPP文件中添加消息映射

      BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

      ... ...

      ON_MESSAGE(WM_ICON_NOTIFY, OnTrayNotification)

      END_MESSAGE_MAP()

(3)在CframeWnd的派生类中添加成员函数

    LRESULT CMainFrame::OnTrayNotification(WPARAM wParam, LPARAM lParam)

    {

      return m_TrayIcon.OnTrayNotification(wParam, lParam);

    }

(4)定义快捷菜单

    在MENU中添加新菜单IDR_POPUP_MENU,可以如一般的菜单一样从ClassWizard中定义其响应。

(5)在CsystemTray中修改OnTrayNotification函数,

    定义你希望实现的效果,如单击左键可以实现最大最小化,单击右键有快捷菜单等功能。

LRESULT CSystemTray::OnTrayNotification(UINT wParam, LONG lParam)

{

  //Return quickly if its not for this tray icon

  if (wParam != m_tnd.uID)

    return 0L;

  CMenu menu, *pSubMenu;

  //定义单击右键有快捷菜单

  if (LOWORD(lParam) == WM_RBUTTONUP)

  {

    if (!menu.LoadMenu(m_tnd.uID))

      return 0;

    if (!(pSubMenu = menu.GetSubMenu(0)))

      return 0;

    // Make first menu item the default (bold font)

    ::SetMenuDefaultItem(pSubMenu- >m_hMenu, 0, TRUE);

    //Display and track the popup menu

    CPoint pos;

    GetCursorPos(&pos);

    ::SetForegroundWindow(m_tnd.hWnd);

    ::TrackPopupMenu(pSubMenu->m_hMenu, 0, pos.x,

    pos.y, 0, m_tnd.hWnd, NULL);

    // BUGFIX: See "PRB: Menus for Notification

    Icons Don't Work Correctly"

    ::PostMessage(m_tnd.hWnd, WM_NULL, 0, 0);

    menu.DestroyMenu();

}

//定义双击左键有产生单击快捷菜单第一项功能的响应

  else if (LOWORD(lParam) == WM_LBUTTONDBLCLK)

  {

      if (!menu.LoadMenu(m_tnd.uID)) return 0;

      if (!(pSubMenu = menu.GetSubMenu(0))) return 0;

      // double click received, the default action is to execute first menu item

      ::SetForegroundWindow(m_tnd.hWnd);

      ::SendMessage(m_tnd.hWnd, WM_COMMAND,

      pSubMenu->GetMenuItemID(0), 0);

      menu.DestroyMenu();

  }

  //定义单击左键为最小化或恢复窗口

  else if (LOWORD(lParam) == WM_LBUTTONUP)

  {

      if(AfxGetMainWnd()->IsIconic()!=0)

      {

        EnableWindow(m_tnd.hWnd,TRUE);

        ShowWindow(m_tnd.hWnd,SW_SHOW);

        ShowWindow(m_tnd.hWnd,SW_RESTORE);

      }

      else

      {

        ShowWindow(m_tnd.hWnd,SW_SHOWMINIMIZED);

        EnableWindow(m_tnd.hWnd,FALSE);

        ShowWindow(m_tnd.hWnd,SW_HIDE);

      }

  }

    return 1;

}

(6)在CmainFrame的派生类中添加WM_SIZE的消息响应函数,这可以实现程序最小化时

    只在系统任务栏中有一个小图标,而不会在一般任务栏中有显示

  void CMainFrame::OnSize(UINT nType, int cx, int cy)

  {

    CFrameWnd::OnSize(nType, cx, cy);

    if(nType==SIZE_MINIMIZED)

    {

      EnableWindow(FALSE);

      ShowWindow(SW_HIDE);

    }

  }

  看起来似乎这样实现步骤也不少,但是当我们再开发新的功能时会很方便,程序会更容易

  理解与开发。如我们可以很方便实现动态小图标。

  a.我们只需在CmainFrame的派生类中添加一个定时器,

  SetTimer(IDW_TIMER1,500,NULL);

  icon_id=0;

  b.对定时发出的WM_TIME消息进行处理,例如时间到了就换一个图标,图标的变化可以根据

  自己的喜好及实际情况定义,此处有3个图标轮流变化。

  void CMainFrame::OnTimer(UINT nIDEvent)

  {

    // TODO: Add your message handler code here and/or call default

    //change the icon

    //icon_id from 0 to 2 every 0.5s

    if(nIDEvent ==IDW_TIMER1)

    {

      if(icon_id==0)

      {

        hIcon=AfxGetApp()->LoadIcon(IDR_ICON0);

        icon_id++;

      }

      else if(icon_id==1)

      {

        hIcon=AfxGetApp()->LoadIcon(IDR_ICON1);

        icon_id++;

      }

      else if(icon_id=2)

      {

        hIcon=AfxGetApp()->LoadIcon(IDR_ICON2);

        icon_id=0;

      }

      m_TrayIcon.SetIcon(hIcon);

    }

    CFrameWnd::OnTimer(nIDEvent);

}

B.第二种方法是通过消息去处理;

创建的基于对话框,看下面说明:

a.在WM_SIZE 消息里面处理有检测到最小化的动作时,作如下的操作:

主要是从代码中摘取的,看主要的代码就好了:

case WM_SIZE:

  if(wParam == SIZE_MINIMIZED)//if wparam == minimized,then add the icon into the taskbar only;

  {

   if(!g_bAddIcon)

   {  

    if(!AddIconToTaskbar(hDlg))

     MessageBox(0,"Add Icon to task bar ,failed!",0,0);

   }

   ShowWindow(hDlg,SW_HIDE);//hide the window;

  }

  break;

b.在WM_COMMAND消息中要remove掉图标;

 switch (LOWORD(wParam))

{

  case IDCANCEL:

    if (!g_bColor)

    {

         KillTimer(hDlg, 1);

    }

    portio.ShutdownDriver(szDriverName);

    CloseHandle(hLogFile);

    g_bRemove = TRUE;

    AddIconToTaskbar(hDlg);

    DeleteObject(hBrush);

    DeleteObject(hCurrentFont);

    EndDialog(hDlg, FALSE);

    return TRUE;

}

C.关键函数 AddIconTaskBar(HWND hwnd),主要处理如下:

BOOL AddIconToTaskbar(HWND hwnd)

{

  NOTIFYICONDATA nid;

  memset(&nid, 0, sizeof(nid));

  nid.cbSize = sizeof(nid);

  strcpy(nid.szTip, "XXX");

  nid.hWnd = hwnd;

  nid.uID = 100;

  nid.uFlags = NIF_ICON | NIF_MESSAGE;

  nid.hIcon = LoadIcon(gst_hInstance, MAKEINTRESOURCE(IDI_TEMP));

  nid.uCallbackMessage = WM_TASKMOUSE;//here to catch the mouse move message

  if (nid.hIcon == NULL)

  {

    MessageBox(0, "Can not add icon ,failed!", 0, 0);

    return FALSE;

  }

  if (!g_bRemove)

  {

    if (Shell_NotifyIcon(NIM_ADD, &nid))//add the icon into the taskbar

    {

      g_bAddIcon = TRUE;

      return TRUE;

    }

    else

      return FALSE;

  }

  else

  {

    Shell_NotifyIcon(NIM_DELETE, &nid);//delete the icon from the taskbar

    return TRUE;

  }

}

here, 处理鼠标的动作如下,比较粗糙:

case WM_TASKMOUSE:

  if( lParam == WM_LBUTTONDBLCLK)

  {

           ShowWindow(hDlg,SW_SHOWNORMAL);//double left click to show the window

  }

  break;

转载请注明,谢谢合作!

red 2010/02/10