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

一個托盤程序演示--鬧鐘 Alert

編輯:關於VC++

想必大家都看見過那些在系統托盤(Tray)中的程序吧,本文就演示了如何創建一個這樣的托盤程序Alert。Alert是一個運行在系統托盤中的小鬧鐘,它在設定的時間後觸發,運行屏幕保護程序並播放一首歌曲。這個程序是很久以前寫的了,而我現在沒有安裝VC++了,所以本文的截圖都是朋友Leoyin幫我做出來後傳給我的(好麻煩,呵呵),在此也對他表示感謝!

建立一個托盤程序的關鍵在於Windows API-Shell_NotifyIcon()的使用,這個API的聲明包含在ShellAPI.H文件中。請在StdAfx.h中使用“#include <ShellAPI.H>”將其引入工程,別象我當時那麼傻-在工程管理器裡引入了該文件,導致現在你們在類視圖中看見了許多不希望看到的東西。我現在也沒有VC++ IDE來修改它了,就這樣吧。

首先,給大家介紹一下相關的函數和結構:Shell_NotifyIcon()的原型和說明(最新版)如下:

BOOL Shell_NotifyIcon(
  DWORD dwMessage,
  PNOTIFYICONDATA lpdata
  );
參數及返回值說明:

dwMessage:[輸入參數] 說明要執行的動作。動作的可選值如下:

NIM_ADD 增加一個圖標到托盤區

NIM_DELETE 從托盤區刪除一個圖標

NIM_MODIFY 修改圖標

NIM_SETFOCUS 將焦點(Focus)返回托盤區。這個消息通常在托盤區圖標完成了用戶界面下的操作後發出。比如一個托盤圖標顯示了一個快捷菜單,然後用戶按下ESC鍵了操作,這時使用NIM_SETFOCUS將焦點繼續保留在托盤區。該項僅在系統外殼與常用控制DLL( Shlwapi.dll與Comctl32.dll)5.0以上版本才可用。

NIM_SETVERSION 指定使用特定版本的系統外殼與常用控制DLL。缺省值為0,表示使用Win95方式。該項僅在系統外殼與常用控制DLL 5.0以上版本才可用。

lpdata:[輸入參數] 一個指向NOTIFYICONDATA結構的指針。

返回值:成功時函數返回TRUE,否則FALSE。

NOTIFYICONDATA 結構的說明(最新版)如下:

typedef struct _NOTIFYICONDATA {
  DWORD cbSize;
  HWND hWnd;
  UINT uID;
  UINT uFlags;
  UINT uCallbackMessage;
  HICON hIcon;
  TCHAR szTip[64];
  DWORD dwState;
  DWORD dwStateMask;
  TCHAR szInfo[256];
  union {
    UINT uTimeout;
    UINT uVersion;
  };
  TCHAR szInfoTitle[64];
  DWORD dwInfoFlags;
  GUID guidItem;
} NOTIFYICONDATA, *PNOTIFYICONDATA;

cbSize 以字節計的結構大小,以適應不同版本。 hWnd 接收Windows消息的窗口句柄。 uID 托盤圖標的ID。 uFlags 指示結構中的哪些成員包含有效數據,可選值:NIF_ICON, NIF_MESSAGE,NIF_TIP,NIF_STATE,NIF_INFO,NIF_GUID。 uCallbackMessage 回調消息ID,由用戶自定義。與一個自定義的消息處理函數關聯。 hIcon 托盤圖標的句柄。 szTip 托盤圖標的提示字符串。

注意:以下數據成員僅限系統外殼與常用控制DLL 5.0及以上版本才有效!

dwState 圖標的狀態:NIS_HIDDEN-隱藏,或NIS_SHAREDICON-可視。 dwStateMask 圖標狀態掩碼,用以設置dwState szInfo 氣球型提示(Balloon ToolTip)的字符串。 uTimeout 以毫秒計的提示顯示時間 uVersion 確定所依賴的版本。0-Win95,NOTIFYICON_VERSION-Win2000 szInfoTitle 氣球型提示的標題 dwInfoFlags

設置氣球型提示所用的圖標(類似MessageBox中所使用的圖標):

NIIF_ERROR   錯誤

NIIF_INFO    信息

NIIF_NONE    沒有圖標

NIIF_WARNING  警告

NIIF_ICON_MASK 6.0版本保留

NIIF_NOSOUND  限6.0版本,不播放對應的聲音

guidItem 6.0版本保留

接下來,讓我們開始實現這個Alert吧。Alert是一個基於對話框的Win32應用程序,利用AppWizard 創建它吧。然後設計一下這個對話框如圖:

在AlertDlg.H中加入:

#include < mmsystem.h > //這個頭文件是干什麼的記不得了,呵呵
#define WM_NOTIFYICON  WM_USER+5 //自定義消息的ID
#define IDI_ICON    0x0005   //圖標ID
#define IDT_APPLY    WM_USER+6 //我要使用的定時器Timer的自定義消息ID

然後為類CAlertDlg添加數據成員m_Interval和自定義成員函數的聲明(怎麼添加不用我教了吧?)。最後形成CAlertDlg類的聲明(已去掉了一些注釋)如下: class CAlertDlg : public CDialog
{
public:
  ~CAlertDlg();
  CAlertDlg(CWnd* pParent = NULL);
  enum { IDD = IDD_ALERT_DIALOG };
  int  m_Interval; //定時間隔,以分鐘為單位
protected:
  virtual void DoDataExchange(CDataExchange* pDX);
protected:
  void ShowMessage(void); //自定義的定時觸發時運行的函數
  HICON m_hIcon; //圖標句柄
  virtual BOOL OnInitDialog();
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();
  afx_msg void OnClickApply(); //"應用"按鈕的點擊消息處理函數
  virtual void OnCancel(); //"退出"按鈕的點擊消息處理函數
  afx_msg void OnTimer(UINT nIDEvent); //定時器消息處理函數
  afx_msg void OnClickHide(); //"隱藏"按鈕的點擊消息處理函數
  //自定義WM_NOTIFYICON消息的處理函數
  afx_msg void OnNotifyIcon(WPARAM wParam, LPARAM lParam);
  afx_msg void OnSysCommand(UINT nID, LPARAM lParam); //系統消息處理函數
  afx_msg BOOL OnQueryEndSession(); //Windows關閉消息處理函數
  DECLARE_MESSAGE_MAP()
};
以下是AlertDlg.CPP中相應函數的實現(還是設置點錨點吧): BOOL CAlertDlg::OnInitDialog()
{
  SetIcon(m_hIcon, TRUE);
  SetIcon(m_hIcon, FALSE);

  // 初始化時間間隔
  CSpinButtonCtrl * pSpin;
  pSpin = (CSpinButtonCtrl *) GetDlgItem(IDC_SPIN);
  pSpin->SetRange(5,150);
  m_Interval = 30;
  CDialog::OnInitDialog();

  // 設置定時器,每秒一次心跳
  SetTimer(1, 1000, NULL);
  // 將圖標放入系統托盤
  NOTIFYICONDATA nd;
  nd.cbSize  = sizeof (NOTIFYICONDATA);
  nd.hWnd  = m_hWnd;
  nd.uID  = IDI_ICON;
  nd.uFlags  = NIF_ICON|NIF_MESSAGE|NIF_TIP;
  nd.uCallbackMessage= WM_NOTIFYICON;
  nd.hIcon  = m_hIcon;
  strcpy(nd.szTip, "我的鬧鐘");

  Shell_NotifyIcon(NIM_ADD, &nd);

  return TRUE;
}
void CAlertDlg::OnClickApply()
{
  // 重置時間間隔
  UpdateData();
  OnTimer(IDT_APPLY);
}
void CAlertDlg::OnCancel()
{
  // 釋放定時器
  KillTimer(1);
  // 將圖標從系統托盤中刪除
  NOTIFYICONDATA nd;
  nd.cbSize  = sizeof (NOTIFYICONDATA);
  nd.hWnd  = m_hWnd;
  Shell_NotifyIcon(NIM_DELETE, &nd);

  CDialog::OnCancel();
}
void CAlertDlg::OnTimer(UINT nIDEvent)
{
  static CString  strTemp;
  static int    Count = 0;
  COleDateTime  dtTime;
  // 刷新顯示的時間
  //常在論壇裡遇到人問怎麼獲得當前時間,這相知道了吧?
  dtTime = COleDateTime::GetCurrentTime();
  strTemp.Format("現在時間 %02i:%02i:%02i ",
      dtTime.GetHour(),
      dtTime.GetMinute(),
      dtTime.GetSecond());
  GetDlgItem(IDC_CURTIME)->SetWindowText(strTemp);
  // 刷新剩余時間值
  if (nIDEvent == IDT_APPLY) Count = 0; //若用戶重新定義了時間間隔,則重新開始計時
  Count++;
  int RestTime;
  RestTime = m_Interval - Count/60;
  if (RestTime <= 0)
  {
    Count = 0;
    ShowMessage();
  }

  strTemp.Format("離下次提醒還差 %i 分鐘", RestTime);
  GetDlgItem(IDC_RESTTIME)->SetWindowText(strTemp);
  CDialog::OnTimer(nIDEvent);
}

//這個ShowMessasge()函數,你們需要自己修改一下,我的代碼太死板了

void CAlertDlg::ShowMessage()
{
  //調用C:\InfoCD\WinaMP\下的WinaMP3播放Music.m3u清單
  ::WinExec("C:\\INFOCD\\WINAMP\\WINAMP.EXE music.m3u",SW_HIDE);

  MessageBox("您該休息一會兒了......",
      "休息",
      MB_SYSTEMMODAL|MB_OK|MB_ICONEXCLAMATION|MB_ICONWARNING);
  //運行C:\Windows\System下的太空屏保
  ShellExecute(m_hWnd,"open","C:\\WINDOWS\\SYSTEM\\太空.scr", NULL,NULL,SW_SHOWNORMAL);
}
afx_msg void CAlertDlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam)
{
  // 響應在托盤圖標上的單擊
  //wParam中是響應消息的圖標ID,lParam中則是Windows的消息
  if ((wParam == IDI_ICON)&&(lParam == WM_LBUTTONDOWN))
    ShowWindow(SW_SHOWNORMAL);
}
void CAlertDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
  // 屏蔽最大化(MFC Bug?),將最小化重定向至隱藏窗口
  if (nID == SC_MAXIMIZE)
    return;
  if (nID == SC_MINIMIZE)
    ShowWindow(SW_HIDE);
  else
    CWnd::OnSysCommand(nID, lParam);
}
BOOL CAlertDlg::OnQueryEndSession()
{
  // 在用戶退出Windows時自動退出應用程序
  CAlertDlg::OnCancel();
  return TRUE;
}
void CAlertDlg::OnClickHide()
{
  OnSysCommand(SC_MINIMIZE, 0x0000);
  return;
}

好了,通過閱讀上面這些源代碼,我想大家對托盤程序的創建有了一定的認識了吧,這也是本文的根本目的。 只是這個程序有個Bug:在程序退出後圖標仍在托盤區顯示,要把鼠標在圖標上面過一下才會消失。這個Bug記得有人提出過解決辦法,好象是要釋放圖標句柄什麼的。可惜我記不得了,這個程序也沒有再修改。

衷心希望大家給我回復,謝謝!

本文配套源碼

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