现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

在菜单条上添加泡泡提示

2012-08-14 23:04 工业·编程 ⁄ 共 4958字 ⁄ 字号 暂无评论

该功能的实现来源于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”进行换行。

给我留言

留言无头像?