程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 關於托盤的一點總結

關於托盤的一點總結

編輯:關於VC++

很多軟件例如:KV3000等在關閉之後會在托盤區有一個小的托盤圖標,這表示程序並沒有真正停止而在後台運行。當我們單擊鼠標時可以使它在桌面上出現一個最大化窗口;而如果我們單擊程序右上角х,或者單擊文件菜單中的退出項時程序仍然在托盤上運行;只有我們右鍵單擊托盤圖標在出現的菜單中選擇退出才能夠真正退出程序等。

現在我們通過一個類CSystemTray和修改系統菜單來實現上述功能。

我們先來改變系統菜單。

1、當我們在程序的標題欄上單擊鼠標右鍵時,只出現如圖的幾項。

而通過MFC生成的還會出現About一項,我們已經把它給去掉了。

我們調用函數GetSystemMenu()來取的系統菜單,然後調用DeleteMenu()來去掉不要的系統菜單項,在這裡我們去掉了“關閉”下面的分隔線和“about”項代碼如下:

CMenu *pSystemMenu=GetSystemMenu(FALSE);
pSystemMenu->DeleteMenu(8,MF_BYPOSITION);
pSystemMenu->DeleteMenu(7,MF_BYPOSITION);

其中的數字7和8表示系統菜單的第7項和第8項,注意分隔線在VC中也算是一項。(這裡和前面所講的修改系統菜單的方法是一樣的)。當我們去掉“about”這項後就應該在系統命令中也去掉相應的相應代碼。我們找到函數OnSysCommand(UINT nID, LPARAM lParam)去掉其中截獲about對話框的代碼:

if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
     CAboutDlg dlgAbout;
     dlgAbout.DoModal();
}

它對我們沒有任何用處,放在這裡只能給我們調試帶來麻煩。當然如果你不去掉它程序完全沒有一點錯誤。那麼,為什麼我們要去掉這兩項呢,因為我們准備在托盤中實現相同的功能。1,我們再改變程序的關閉標志“X”的功能,把它改為隱藏而不是完全關閉。我們來截獲關閉命令,把它改為隱藏。

if ((nID & 0xFFF0)==SC_CLOSE){
     //OnClose();本來這個是關閉的這裡也改為隱藏。
     AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);
     KillTimer(0);
     ShowWindow(SW_HIDE);//系統菜單的關閉也改為隱藏。
}

在ShowWindow(SW_HIDE)前面的兩句是為了實現一種特效,即是慢慢很溫和的隱藏,不過只有這兩句還是不行的還應該在stdafx.h的前面加上如下兩行代碼:

#undef WINVER
#define WINVER 0X500

2、我們來建立一個托盤菜單,ID號為IDR_TUOPAN當我們在托盤上點擊右鍵時,會出現一個菜單,在菜單裡我們有:關於、顯示(隱藏)、換歌、退出四項。我們先在頭文件VioletPlayDlg.h中自定義一個消息:

#define WM_USER_TRAY_NOTIFICATION (WM_USER+0x101)

注意它的格式。在文件中定義一個托盤變量CSystemTray m_trayIcon,有了這些後我們就可以先做一個托盤雛形了。在主文件VioletPlayDlg.cpp中來產生一個托盤了。我們用Creat()函數定義如下:

m_trayIcon.Create(this, WM_USER_TRAY_NOTIFICATION, "VioletPlay", m_hIcon, IDR_TUOPAN);

其中第二個參數為我們自定義的功能,即出現托盤圖標,第三個參數為當我們把鼠標放在圖標上時出現的說明文字,第五個參數為當我們單擊右鍵時出現的菜單,由於我們通過這個函數並不能響應右鍵,所以在這裡並不能出現這個菜單,(下文會講) 當我們的鼠標離開圖標的時候出現的說明文字VioletPlay會自動消失,我們通過一個條件語句來實現。首先我們定義一個BOOL變量BOOL start_minimized我們來判斷它的值:

if (start_minimized)
  PostMessage(WM_CLOSE);

當我們鼠標移走的時候就發送一個CLOSE命令,關閉窗口。我們在文件VioletPlay.cpp中加上一句代碼時程序運行的時候即可以在托盤中顯示又可以在桌面上顯示:

dlg.start_minimized=GetProfileInt(_T(""),_T("StartMinimized"),FALSE);

我們在這裡在顯示主程序的對話框之前加上這句代碼,起到一個“攔截”作用。這樣我們就實現了最初的功能,即在托盤中出現了一個圖標,但是這還是遠遠不夠的,我們在來一步步實現其他的功能。

3、雖然我們有了一個托盤菜單,但是我們到現在還不能通過單擊鼠標右鍵使它出現,因為我們的程序還不能響應這個消息,下面我們通過重載函數:afx_msg LONG OnTrayNotification( WPARAM wparam, LPARAM lparam )並在裡面加上響應代碼來實現這個功能。

我們用switch…case…結構來響應鼠標右鍵這一消息,當然如果你願意也是可以用if語句來實現同樣的功能的。

代碼如下:

LONG CVioletPlayDlg::OnTrayNotification(WPARAM wparam, LPARAM lparam)
{
  switch ( lparam )
  {
  case WM_RBUTTONDOWN:
  {// 用戶在托盤圖標上單擊鼠標右鍵,彈出上下文菜單隱藏/顯示對話框。
    CMenu oMenu;
    if (oMenu.LoadMenu(IDR_TUOPAN))
    {
      CMenu* pPopup = oMenu.GetSubMenu(0);
      ASSERT(pPopup != NULL);
      CPoint oPoint;
      if (IsWindowVisible())// 根據對話框窗口的顯示/隱藏狀態修改菜單名稱
        oMenu.ModifyMenu(IDC_SHOW,MF_STRING,IDC_SHOW,"隱藏(&H)");
      else
        oMenu.ModifyMenu(IDC_SHOW,MF_STRING,IDC_SHOW,"顯示(&S)");
      // 確定鼠標位置以便在該位置附近顯示菜單
      GetCursorPos( &oPoint );
      SetForegroundWindow();
      pPopup->TrackPopupMenu(
        TPM_LEFTALIGN | TPM_RIGHTBUTTON,
        oPoint.x, oPoint.y, this);
    }
  }
  break;
  // 單擊/雙擊鼠標左鍵均顯示出對話框
  case WM_LBUTTONDBLCLK:
  case WM_LBUTTONDOWN:
    OnShow();
    break;
  }
  return 0;
}

在上述代碼中我們同時實現了動態改變菜單“顯示/隱藏”的功能,當程序主界面出現時,菜單中變為“隱藏”表示如果我們再單擊它時程序主界面就隱藏起來了。如果為隱藏狀態時菜單中變為“顯示”表示當我們單擊它時可以顯示程序主界面。另外,在上面代碼的最後三句表示不管我們是單擊還是雙擊鼠標左鍵它發送的命令都是一樣的即出現主程序界面,即OnShow()。

我們在對托盤菜單中的命令一個一個的分析。這裡的“退出”菜單我們使程序真正的退出,因此它接受的命令為 ::PostQuitMessage(0),使程序真正退出,注意前面我們也說了,其它的兩個“退出”皆為隱藏。因為程序的使用者也許並不知道這一點,所以我們有必要在這裡設計一個對話框進行提醒,如果要求這一點我們就把點擊“退出”菜單所發送的命令改為調用一個AfxMessageBox,當是使用者點擊“是”才實現真正的退出。點擊“否”而不退出。

代碼如下:

void CVioletPlayDlg::OnClose()
{
  if(AfxMessageBox("真的要退出嗎",MB_YESNO)==IDYES)
  {
    AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);
    KillTimer(0);
    ::PostQuitMessage(0);
  }
}

當你點擊了文件菜單中的退出時也是同樣的道理只是當你點擊“是”時只能隱藏主界面,而當你點擊“否”時,不能隱藏主界面。我們只需要把上面代碼中的退出命令:::PostQuitMessage(0)改為隱藏命令ShowWindow(SW_HIDE)就可以了。

到現在為止我們實現了托盤圖標的所有功能。

注意:類CSystemTray繼承於CWnd是public形式,類的定義和實現可以參考文件:VioletPlay,文件名分別為SystemTray.h和SystemTray.cpp 源文件見:VioletPlay (注,有一些代碼用的是VCKBASE網站中,我只對其進行了分析和總結。再此表示謝意和歉意)

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved