⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tuopanchengxu.txt

📁 利用Visual C++实现系统托盘程序
💻 TXT
📖 第 1 页 / 共 2 页
字号:
一、实现方法

   为了实现拖盘程序,首先要使程序的主窗口不可见,这点实现起来十分容易,只要调用ShowWindow(SW_HIDE)就可以了,本实例采用的就是这种方法,还有一种思路是通过分别设置主边框窗口的风格和扩展风格来隐藏主框架:



BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
  cs.style =WS_POPUP;//使主窗口不可见;
  cs.dwExStyle |=WS_EX_TOOLWINDOW;//不显示任务按钮;
  return CFrameWnd::PreCreateWindow(cs);
} 

   在任务条上显示图标是利用系统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 有效  

   在该结构的成员中,cbSize为该结构所占的字节数,hWnd为接受该图标所发出的消息的窗口的句柄(鼠标在任务栏上程序图标上动作时图标将发出消息,这个消息用户要自己定义),uID为被显示图标的ID,uFlags指明其余的几个成员(hIcon、uCallBackMessage和szTip)的值是否有效,uCallbackMessage为一个用户自定义的消息,当用户在该图标上作用一些鼠标动作时,图标将向应用程序的主框架窗口(hWnd成员中指定的窗口)发出该消息,为了使程序的主框架得到该通知消息,需要设置NOTIFYICONDATA 结构的flag成员的值为NIF_MESSAGE。hIcon为将在任务栏上显示的图标句柄,szTip鼠标停留在该图标上时显示的提示字符串。

   尽管Shell_NotifyIcon函数简单实用,但它毕竟是个Win32 API,为此本实例将它封装在了一个C++类中,这个类叫做CTrayIcon,有了它,托盘编程会更加轻松自如,因为它隐藏了NOTIFYICONDATA、消息代码、标志以及一些繁琐的细节。

   二、编程步骤

   1、 启动Visual C++6.0,生成一个单文档的应用程序TrayTest,取消文档视图支持;

   2、 在CMainFrame类中添加自定义消息#define WM_MY_TRAY_NOTIFICATION WM_USER+0,并在该类中为此自定义消息手动添加消息映射ON_MESSAGE(WM_MY_TRAY_NOTIFICATION, OnTrayNotification)和消息响应函数afx_msg LRESULT OnTrayNotification(WPARAM wp, LPARAM lp);

   3、 设计二个图标添加到项目中,其ID标志分别为"IDI_MYICON"、"IDI_MYICON2",作为托盘显示时的图标;

   4、 在CMainFrame类中添加下述变量: CTrayIcon m_trayIcon(用来操作图标的类对象)、CEdit m_wndEdit(编辑框用来显示所跟踪到的鼠标消息)、int m_iWhichIcon(决定当前托盘使用哪个图标)、BOOL m_bShutdown(是否关闭当前拖盘程序标志)、BOOL m_bShowTrayNotifications(是否显示托盘消息标志);

   5、 为程序的IDR_MAINFRAME添加处理菜单项和托盘的上下文菜单IDI_TRAYICON(具体的菜单项的标题和ID标志符参见代码部分),然后使用Class Wizard为各个菜单项添加处理函数;

   6、 添加代码,编译运行程序。 
三、程序代码



////////////////////////////////////////////////CTrayIcon类的头文件;
#ifndef _TRAYICON_H
#define _TRAYICON_H
class CTrayIcon : public CCmdTarget {
  protected:
   DECLARE_DYNAMIC(CTrayIcon)
   NOTIFYICONDATA m_nid; // struct for Shell_NotifyIcon args
  public:
   CTrayIcon(UINT uID);
   ~CTrayIcon();
   // Call this to receive tray notifications
   void SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg);
   BOOL SetIcon(UINT uID); // main variant you want to use
   BOOL SetIcon(HICON hicon, LPCSTR lpTip);
   BOOL SetIcon(LPCTSTR lpResName, LPCSTR lpTip)
   { return SetIcon(lpResName ? 
    AfxGetApp()->LoadIcon(lpResName) : NULL, lpTip); }
   BOOL SetStandardIcon(LPCTSTR lpszIconName, LPCSTR lpTip)
   { return SetIcon(::LoadIcon(NULL, lpszIconName), lpTip); }
   virtual LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent);
};
#endif 
///////////////////////////////////////////////////CTrayIcon类的.CPP文件
#include "stdafx.h"
#include "trayicon.h"
#include <afxpriv.h> // for AfxLoadString
IMPLEMENT_DYNAMIC(CTrayIcon, CCmdTarget)
CTrayIcon::CTrayIcon(UINT uID)
{
  memset(&m_nid, 0 , sizeof(m_nid)); // Initialize NOTIFYICONDATA
  m_nid.cbSize = sizeof(m_nid);
  m_nid.uID = uID; // never changes after construction
  AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip)); 
  // Use resource string as tip if there is one
}

CTrayIcon::~CTrayIcon()
{
  SetIcon(0); // remove icon from system tray
}

void CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg) 
{
  // Set notification window. It must created already.
  ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd()));
  m_nid.hWnd = pNotifyWnd->GetSafeHwnd();
  ASSERT(uCbMsg==0 || uCbMsg>=WM_USER);
  m_nid.uCallbackMessage = uCbMsg;
}

BOOL CTrayIcon::SetIcon(UINT uID)
{
  // Sets both the icon and tooltip from resource ID ,To remove the icon, call SetIcon(0)
  HICON hicon=NULL;
  if (uID) {
   AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
   hicon = AfxGetApp()->LoadIcon(uID);
  }
  return SetIcon(hicon, NULL);
}

BOOL CTrayIcon::SetIcon(HICON hicon, LPCSTR lpTip) 
{
  // Common SetIcon for all overloads.
  UINT msg;
  m_nid.uFlags = 0;
  if (hicon) {
   // Set the icon
   msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
   m_nid.hIcon = hicon; // Add or replace icon in system tray
   m_nid.uFlags |= NIF_ICON;
  } else { 
   if (m_nid.hIcon==NULL) // remove icon from tray
    return TRUE; // already deleted
   msg = NIM_DELETE;
  }
  if (lpTip) // Use the tip, if any
   strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
  if (m_nid.szTip[0])
   m_nid.uFlags |= NIF_TIP;
  if (m_nid.uCallbackMessage && m_nid.hWnd) // Use callback if any
   m_nid.uFlags |= NIF_MESSAGE;
   BOOL bRet = Shell_NotifyIcon(msg, &m_nid); // Do it
  if (msg==NIM_DELETE || !bRet)
   m_nid.hIcon = NULL; // failed
  return bRet;
}

LRESULT CTrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent)
{
  if (wID!=m_nid.uID || (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK))
   return 0;
  CMenu menu;//装载上下文菜单;
  if (!menu.LoadMenu(m_nid.uID))
   return 0;
  CMenu* pSubMenu = menu.GetSubMenu(0);
  if (!pSubMenu) 
   return 0;
  if (lEvent==WM_RBUTTONUP) {//设置第一个菜单项为默认菜单项目
   ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE); 
   //将当前菜单作为上下文菜单;
   CPoint mouse;
   GetCursorPos(&mouse);
   ::SetForegroundWindow(m_nid.hWnd); 
   ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0,m_nid.hWnd, NULL);
  } else // double click: execute first menu item
   ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
  return 1; 
}

///////////////////////////////// MainFrm.h : interface of the CMainFrame class
#if !defined(AFX_MAINFRM_H__9ED70A69_C975_4F20_9D4E_B2877E3575D0__INCLUDED_)
#define AFX_MAINFRM_H__9ED70A69_C975_4F20_9D4E_B2877E3575D0__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "trayicon.h"
class CMainFrame : public CFrameWnd
{
  public:
   CMainFrame();
  protected: 
   DECLARE_DYNAMIC(CMainFrame)
   // Attributes
  public:
   // Overrides
   // ClassWizard generated virtual function overrides
   //{{AFX_VIRTUAL(CMainFrame)
   //}}AFX_VIRTUAL
   // Implementation
  public:
   virtual ~CMainFrame();
   #ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
   #endif
  protected: // control bar embedded members
   CStatusBar m_wndStatusBar;
   CTrayIcon m_trayIcon; // my tray icon
   CEdit m_wndEdit; // to display tray notifications
   int m_iWhichIcon; // which HICON to use
   BOOL m_bShutdown; // OK to terminate TRAYTEST
   BOOL m_bShowTrayNotifications; // display info in main window
   // Generated message map functions
  protected:
   //{{AFX_MSG(CMainFrame)
    afx_msg LRESULT OnTrayNotification(WPARAM wp, LPARAM lp);
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnToggleIcon();
    afx_msg void OnViewClear();
    afx_msg void OnViewNotifications();
    afx_msg void OnUpdateViewClear(CCmdUI* pCmdUI);
    afx_msg void OnUpdateViewNotifications(CCmdUI* pCmdUI);
    afx_msg void OnClose();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -