zoukankan      html  css  js  c++  java
  • 在菜单条上添加泡泡提示

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




    CNBIE BLOG

    在菜单中加入图标

    原文:在菜单中加入图标
     
    'API函数声明
    Option Explicit
    Private Declare Function GetMenu Lib "user32"(Byval hwnd As Long) _
    As Long '取得窗口的菜单句柄,hwnd是窗口的句柄
    Private Declare Function GetSubMenu Lib "user32"(Byval hMenu As _
    Long,Byval nPos As Long) As Long '取得子菜单句柄,nPos是菜单的位置
    Private Declare Function SetMenuItemBitmaps Lib "user32"(Byval _
    hMenu As Long,Byval nPos As Long,Byval wFlags As Long,Byval _
    hBitUnchecked As Long,Byval hBitChecked As Long) As Long
    '为菜单设置相应的图形
    Const MF_BITMAP=&H400&
    '用image或picture或imagelist控件装入图形(必须是bmp格式),16*16左右
    '建好菜单
    Private Sub Form_Load()
    Dim hMenu,hSubMenu1,hSubMenu2 As Long
    hMenu=GetMenu(me.hwnd)
    hSubMenu1=GetSubMenu(hMenu,0) '取得第一项菜单的子菜单句柄
    SetMenuItemBitmaps hSubMenu1,0,MF_BITMAP,imagelist1.listimages(1) _
    .picture,imagelist1.listimages(1).picture
    '为hSubMenu1的第一项设置图形,假设用imagelist控件装入图形
    SetMenuItemBitmaps hSubMenu1,1,MF_BITMAP,imagelist1.listimages(2) _
    .picture,imagelist1.listimages(2).picture
    '设置第二项,同样你还可以设置第xx项。

    hSubMenu2=GetSubMenu(hMenu,1) '取得第二项菜单的子菜单句柄

    '也可用SetMenuItemBitmaps来设置它的图形,只更改hSubMenu1为hSubMenu2
    '即可
    End Sub



  • 相关阅读:
    ant 软件包不存在报错
    在 Internet Explorer 中使用 Windows 窗体控件
    智能客户端
    Back to the Future with Smart Clients
    "Automation 服务器不能创建对象" 的解决方案
    Top 10 Reasons for Developers to Create Smart Clients
    Updater Application Block for .NET
    Smart Client Application Model and the .NET Framework 1.1
    Security and Versioning Models in the Windows Forms Engine Help You Create and Deploy Smart Clients
    智能客户端技术总结(二)
  • 原文地址:https://www.cnblogs.com/rainbowzc/p/2422351.html
Copyright © 2011-2022 走看看