在菜单条上添加泡泡提示

类别:VC语言 点击:0 评论:0 推荐:

该功能的实现来源于codeproject上面的一个例子《Tooltips for Menu Item and popup menuitem》,其实例子讲的步骤很简单,不过我不打算简单的翻译一下,林语堂先生不是说:“只用一样东西,不明白它的道理,实在不高明”。
   实现该功能的核心在于作者自己建立的一个MenuToolTip类,182行的代码实现了菜单提示的功能,下面我就将其一一解释开来,在每行代码的后面有具体的解释。
   #ifndef _MENU_TOOLTIP //条件编译语句,判断是否定义了_MENU_TOOLTI宏
#define _MENU_TOOLTIP
//以下定义一些常量标识符
#ifndef TTS_NOANIMATE
 #define TTS_NOANIMATE           0x10
 #define TTS_NOFADE              0x20
 #define TTS_BALLOON             0x40
 #define TTS_CLOSE               0x80

 #define TTM_SETTITLEA           (WM_USER + 32)  // wParam = TTI_*, lParam = char* szTitle
 #define TTM_SETTITLEW           (WM_USER + 33)  // wParam = TTI_*, lParam = wchar* szTitle

 #ifdef UNICODE
 #define TTM_SETTITLE            TTM_SETTITLEW
 #else
 #define TTM_SETTITLE            TTM_SETTITLEA
 #endif
#endif


class CMenuToolTip
{

  public:
 CMenuToolTip():m_hToolTip(0), m_hParent(0) {}

 // 创建与菜单项相关的提示
 void Create(HWND hParent, LPCTSTR sczTipText,
   HINSTANCE hInstance = NULL,
   DWORD dwStyle = 0,
   LPCTSTR sczTipTitle = NULL);
 //触发WM_MENUSELECT消息时调用此函数
 void OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSubMenu);

 // 显示或隐藏提示的函数
 void ShowToolTip(BOOL bShow)
 {
  TOOLINFO    ti;//TOOLINFO是一个存放控件提示信息的结构
                 //以下初始化该结构中的一些变量
  ti.cbSize = sizeof(TOOLINFO);//设定结构的大小
  ti.uFlags = TTF_IDISHWND;//指出uid成员是窗口的句柄
  ti.hwnd   = m_hParent;//包含提示的窗口的句柄
  ti.uId    = (UINT)m_hParent;//应用程序定义的标识符
  //发送出现提示的消息
  ::SendMessage(m_hToolTip,TTM_TRACKACTIVATE,(WPARAM)bShow,(LPARAM)&ti);
 }

 // 设置提示出现的位置
 void SetToolTipPosition(HMENU hMenu, UINT nItemID)
 {
  RECT rt = {0,0,0,0};
  
  // find Item Rectangle and position
  //根据菜单项的数量完成以下循环
  for(int nItem = 0; nItem < ::GetMenuItemCount(hMenu); nItem++) {
   UINT cmd = ::GetMenuItemID(hMenu, nItem);//将当前菜单项的标识符存放到一个变量中
   //如果当前菜单项是选定的菜单项,则获取菜单项的区域
   if(cmd == nItemID) {
    ::GetMenuItemRect(m_hParent, hMenu, nItem, &rt);
   }
  }
  
  
  //发送消息以设定显示提示的位置
  ::SendMessage(m_hToolTip, TTM_TRACKPOSITION, 0,
      (LPARAM)MAKELPARAM(rt.right, rt.bottom + 2));
  //将提示显示在最顶层,否则的话提示箭头会出现在菜单下面,试试看:->
  ::SetWindowPos(m_hToolTip, HWND_TOPMOST ,0,0,0,0, SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOMOVE);
 }

 // 更新提示信息
 void UpdateToolTipText(LPCTSTR szBuff, HINSTANCE hInstance = 0)
 {

  TOOLINFO    ti;
  ti.cbSize = sizeof(TOOLINFO);
  ti.uFlags = TTF_IDISHWND;
  ti.hwnd   = m_hParent;
  ti.uId    = (UINT)m_hParent;
  ti.hinst = hInstance;
  ti.lpszText  = const_cast<LPTSTR>(szBuff);//更新提示文本的内容
  //发送更新的消息
  ::SendMessage(m_hToolTip,TTM_UPDATETIPTEXT,(WPARAM)0,(LPARAM)&ti);
 }
//重载句柄操作符
 operator HWND()
 {
  return m_hToolTip;
 }

  private:
  HWND m_hToolTip;
  HWND m_hParent;
  TCHAR m_szDefault[_MAX_PATH] ;//存放缺省提示的串
  HINSTANCE m_hInstance;
};

inline//以下内联函数创建提示控件
void CMenuToolTip::Create(HWND hParent, LPCTSTR sczTipText, HINSTANCE hInstance,
       DWORD dwStyle, LPCTSTR sczTipTitle)
{
 INITCOMMONCONTROLSEX icex;//在公用控件的动态链接库中注册公用控件类
 TOOLINFO    ti;
 // Load the ToolTip class from the DLL.
 icex.dwSize = sizeof(icex);
 icex.dwICC  = ICC_BAR_CLASSES;
 //如果注册失败,则返回
 if(!InitCommonControlsEx(&icex))
    return;

 m_hParent = hParent;
 m_hInstance = hInstance;
   
 // 创建提示控件
 m_hToolTip = ::CreateWindow(TOOLTIPS_CLASS, TEXT(""),
        WS_POPUP| dwStyle,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance,
        NULL);

 // 设置控件的一些初始参数
 ti.cbSize = sizeof(TOOLINFO);
 ti.uFlags = TTF_IDISHWND | TTF_TRANSPARENT | TTF_TRACK | TTF_ABSOLUTE;//TTF_CENTERTIP
 ti.hwnd   = hParent;
 ti.uId    = (UINT)hParent;
 ti.hinst  = hInstance;
 ti.lpszText  = const_cast<LPTSTR>(sczTipText);
 if(sczTipText != LPSTR_TEXTCALLBACK) {
  //以下设定缺省提示文本
  if(sczTipText) {//如果当前菜单存在提示文本,则将其存放到m_szDefault
   _tcscpy(m_szDefault, sczTipText);
  }
  else {//如果不存在提示文本,则显示以下字符串
   _tcscpy(m_szDefault, _T("No Text associated"));
  }
 }

 ti.rect.left = ti.rect.top = ti.rect.bottom = ti.rect.right = 0;

 //把提示添加到控件中
 ::SendMessage(m_hToolTip,TTM_ADDTOOL,0,(LPARAM)&ti);

 ::SendMessage(m_hToolTip, TTM_SETMAXTIPWIDTH, 0, 300);
 if(sczTipTitle) {
  ::SendMessage(m_hToolTip, TTM_SETTITLE, 1, (LPARAM)sczTipTitle);
 }
}

inline //以下内联函数设定在选定菜单时所做的操作
void CMenuToolTip::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSubMenu)
{
 if(nFlags & MF_POPUP
  || (nFlags == 0xFFFF && hSubMenu == NULL)) { // 菜单关闭时不出现提示
  ShowToolTip(FALSE);
 }

 if(!(nFlags & MF_POPUP)) {
  
  // 设置提示的位置
  SetToolTipPosition(hSubMenu, nItemID);

  // 更新提示的文本
  TCHAR szBuff[256];//定义一个存放提示文本的字符数组
  szBuff[0] = 0;
  //将指定的提示文本存放到预先设定的缓冲区中
  int nRet = ::LoadString(m_hInstance, nItemID, szBuff, 256);
#if 0
  for(int i = 0; i < nRet; i++)
  {
   if(szBuff[i] == _T('\n'))
   {
    szBuff[i] = 0;
    break;
   }
  }
#endif  
  //以下部分主要用于更新提示文本,否则文本是固定的
  if(szBuff[0] != 0) {
   UpdateToolTipText(szBuff);
  }
  else {
   UpdateToolTipText(m_szDefault);
  }
  ShowToolTip(TRUE);//设定需要显示提示
 }
}

#endif _MENU_TOOLTIP
上面的注释写的比较详细了,您可以在相应的地方做修改,以更改提示的位置和内容,将上面的代码存为一个名为menutooltip.h的头文件,将其加入到您的工程当中,然后在需要处理提示信息的类的初始函数(如对话框的OnInitDialog函数或者是类的构造函数)中添加如下语句:
 myMenuToolTip.Create(m_hWnd, _T("Sample Menu Text"), AfxGetResourceHandle()
   ,TTS_NOPREFIX | TTS_BALLOON
   , _T("My Best Tool Tip Title")
   );
同时在相应的类中创建OnMenuSelect函数如下:
void CMenuItemToolTipDlg::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSubMenu)
{
 myMenuToolTip.OnMenuSelect(nItemID, nFlags, hSubMenu);
 CWnd::OnMenuSelect(nItemID, nFlags, hSubMenu);
}
同时不要忘了加入上述头文件,并定义一个提示信息类的变量
#include "MenuToolTip.h"
CMenuToolTip myMenuToolTip;
最后在消息循环中加入ON_WM_MENUSELECT()
一切ok了。
Ps:在这里显示的提示信息都是您在定义菜单资源时设定的,也就是在定义一个菜单项时,右键选定属性,在general中有一个prompt文本框,用于设定提示文本,如果文本过长,可以在其中加上“\r\n”进行换行。

本文地址:http://com.8s8s.com/it/it335.htm