天天看點

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