找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 34|回复: 1

soui4实现自定义ToolTip

[复制链接]
  • TA的每日心情

    3 天前
  • 签到天数: 301 天

    [LV.8]以坛为家I

    3

    主题

    0

    回帖

    5131

    积分

    论坛元老

    积分
    5131
    发表于 2025-9-22 17:12:03 | 显示全部楼层 |阅读模式
    首先我们先定义个展示tooltip的xml
    1. <?xml version="1.0"?>
    2. <SOUI name="tip" title="tip" width="-1" height="-1" resizable="0" wndType="normal" toolwindow="1" translucent="1">
    3.         <root size="-1,-1" colorBkgnd="#212629f0" class="style_tip" padding="10,10,10,10" layout="vbox">
    4.                 <text name="txt_tip" colorText="#FFFFFFb0" font="face:微软雅黑,size:12" maxWidth="300" multiLines="1"/>
    5.         </root>
    6. </SOUI>
    复制代码
    其中txt_tip就是用来展示tip内容的。我们可以在此处指定tooltip的展示样式。
    在uires中关联一下这个xml
    1.   <LAYOUT>
    2.           <file name="XML_TOOLTIP" path="xml\tooltip.xml"/>
    3.   </LAYOUT>
    复制代码
    然后我们实现一个tooltip类
    1. //头文件CToolTipEx.h
    2. #pragma once
    3. class CToolTipEx : public IToolTip
    4.         , public IMsgFilter
    5.         , public SHostWnd
    6. {
    7. public:
    8.         CToolTipEx(void);
    9.         virtual ~CToolTipEx(void);

    10.         BOOL CreateWnd();
    11.         HWND Hwnd();

    12. public://IToolTip
    13.         STDMETHOD_(BOOL, Create)(THIS) OVERRIDE;
    14.         STDMETHOD_(BOOL, Destroy)(THIS) OVERRIDE;
    15.         STDMETHOD_(BOOL, PreTranslateMessage)(THIS_ MSG* pMsg) OVERRIDE;
    16.         STDMETHOD_(void, UpdateTip)(THIS_ const TIPID* id, RECT rc, LPCTSTR pszTip, int nScale) OVERRIDE;
    17.         STDMETHOD_(void, SetToolTip)(THIS_ LPCRECT rc, UINT tipAlign, LPCTSTR pszTip, int nScale) OVERRIDE;
    18.         STDMETHOD_(void, ClearTip)(THIS) OVERRIDE;
    19.         STDMETHOD_(void, RelayEvent)(THIS_ const MSG* pMsg) OVERRIDE;

    20.         STDMETHOD_(long, AddRef)(THIS) OVERRIDE {
    21.                 return SNativeWnd::AddRef();
    22.         }
    23.         STDMETHOD_(long, Release)(THIS) OVERRIDE {
    24.                 return SNativeWnd::Release();
    25.         }
    26.         STDMETHOD_(void, OnFinalRelease)(THIS) OVERRIDE {
    27.                 delete this;
    28.         }

    29.         STDMETHOD_(IMsgFilter*, GetMsgFilter)(THIS) OVERRIDE {
    30.                 return this;
    31.         }
    32.         
    33.         //要重写这两个接口,不然内部自己建立时会不停建立tip。会导致死循环
    34.         virtual IToolTip* CreateTooltip() const { return NULL; }
    35.         virtual void DestroyTooltip(IToolTip* pTooltip) {}

    36. protected:
    37.         int OnCreate(LPCREATESTRUCT lpCreateStruct);
    38.         BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam);
    39.         void OnTimer(UINT_PTR idEvent);

    40.         BEGIN_MSG_MAP_EX(CToolTipEx)
    41.                 MSG_WM_CREATE(OnCreate)
    42.                 MSG_WM_INITDIALOG(OnInitDialog)
    43.                 MSG_WM_TIMER(OnTimer)
    44.                 CHAIN_MSG_MAP(SHostWnd)
    45.                 REFLECT_NOTIFICATIONS_EX()
    46.                 END_MSG_MAP()

    47.         void ShowTip(BOOL bShow);

    48. private:
    49.         HWND        m_hWnd;
    50.         DWORD        m_Tick;
    51.         int                m_nDelay;
    52.         int                m_nShowSpan;
    53.         SStringT        m_strTip;
    54.         int                m_nScale;
    55.         CRect        m_rcTarget;
    56.         SStatic*        m_txtTip;
    57.         TIPID        m_id;
    58.         bool        m_bShow;
    59. };

    60. //源文件CToolTipEx.cpp
    61. #include "stdafx.h"
    62. #include "CToolTipEx.h"

    63. #define TIMERID_DELAY2   1
    64. #define TIMERID_SPAN2     2
    65. #define MARGIN_TIP2        5

    66. CToolTipEx::CToolTipEx(void) : SHostWnd(_T("LAYOUT:XML_TOOLTIP"))
    67. , m_nDelay(50)
    68. , m_nShowSpan(5000)
    69. , m_Tick(0)
    70. {
    71.         m_id.dwHi = m_id.dwLow = 0;
    72.         m_bShow = false;
    73. }

    74. CToolTipEx::~CToolTipEx(void)
    75. {
    76. }

    77. BOOL CToolTipEx::CreateWnd()
    78. {
    79.         m_hWnd = SHostWnd::Create(::GetActiveWindow(), 0, 0, 0, 0);
    80.         SendMessage(WM_INITDIALOG);
    81.         return TRUE;
    82. }

    83. HWND CToolTipEx::Hwnd()
    84. {
    85.         return m_hWnd;
    86. }

    87. BOOL CToolTipEx::Create()
    88. {
    89.         CreateWnd();
    90.         return TRUE;
    91. }

    92. BOOL CToolTipEx::Destroy()
    93. {
    94.         return TRUE;
    95. }

    96. BOOL CToolTipEx::PreTranslateMessage(MSG* pMsg)
    97. {
    98.         if (IsWindow())
    99.                 RelayEvent(pMsg);

    100.         return FALSE;
    101. }

    102. void CToolTipEx::UpdateTip(const TIPID* id, RECT rc, LPCTSTR pszTip, int nScale)
    103. {
    104.         if (m_id.dwHi == id->dwHi && m_id.dwLow == id->dwLow) return;

    105.         m_id = *id;
    106.         m_rcTarget = rc;
    107.         m_strTip = pszTip;
    108.         m_strTip.Replace(_T("\\n"), _T("\n"));

    109.         if (IsWindowVisible())
    110.                 ShowTip(TRUE);
    111. }

    112. void CToolTipEx::SetToolTip(LPCRECT rc, UINT tipAlign, LPCTSTR pszTip, int nScale)
    113. {
    114. }

    115. void CToolTipEx::ClearTip()
    116. {
    117.         m_id.dwHi = m_id.dwLow = 0;
    118.         ShowTip(FALSE);
    119. }

    120. void CToolTipEx::RelayEvent(const MSG* pMsg)
    121. {
    122.         switch (pMsg->message)
    123.         {
    124.         case WM_LBUTTONDOWN:
    125.         case WM_LBUTTONUP:
    126.         case WM_RBUTTONDOWN:
    127.         case WM_RBUTTONUP:
    128.         case WM_MBUTTONUP:
    129.         case WM_MBUTTONDOWN:
    130.                 OnTimer(TIMERID_SPAN2);//hide tip
    131.                 break;
    132.         case WM_MOUSEMOVE:
    133.         {
    134.                 CPoint pt(GET_X_LPARAM(pMsg->lParam), GET_Y_LPARAM(pMsg->lParam));
    135.                 if (!m_rcTarget.PtInRect(pt))
    136.                 {
    137.                         OnTimer(TIMERID_SPAN2);//hide tip
    138.                 }
    139.                 else if (/*!IsWindowVisible() &&*/ !m_strTip.IsEmpty())
    140.                 {
    141.                         DWORD t = ::GetTickCount();
    142.                         if ((t - m_Tick) > DWORD(m_nDelay))
    143.                         {
    144.                                 KillTimer(TIMERID_DELAY2);
    145.                                 SetTimer(TIMERID_DELAY2, m_nDelay);
    146.                                 m_Tick = t;
    147.                         }
    148.                         ::ClientToScreen(pMsg->hwnd, &pt);
    149.                         SetWindowPos(0, pt.x, pt.y + 18, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE);
    150.                 }
    151.         }
    152.         break;
    153.         default:
    154.                 break;
    155.         }
    156. }

    157. int CToolTipEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
    158. {
    159.         SHostWnd::OnCreate(lpCreateStruct);

    160.         return 0;
    161. }

    162. BOOL CToolTipEx::OnInitDialog(HWND wndFocus, LPARAM lInitParam)
    163. {
    164.         m_txtTip = FindChildByName2<SStatic>(L"txt_tip");
    165.         return TRUE;
    166. }

    167. void CToolTipEx::OnTimer(UINT_PTR idEvent)
    168. {
    169.         SetMsgHandled(FALSE);
    170.         switch (idEvent)
    171.         {
    172.         case TIMERID_DELAY2:
    173.         {
    174.                 if (!m_bShow)
    175.                 {
    176.                         KillTimer(TIMERID_DELAY2);
    177.                         ShowTip(TRUE);
    178.                         m_bShow = true;
    179.                 }
    180.                 SetTimer(TIMERID_SPAN2, m_nShowSpan);
    181.         }
    182.         break;
    183.         case TIMERID_SPAN2:
    184.         {
    185.                 ShowTip(FALSE);
    186.                 KillTimer(TIMERID_SPAN2);
    187.                 m_bShow = false;
    188.         }
    189.         break;
    190.         }
    191. }

    192. void CToolTipEx::ShowTip(BOOL bShow)
    193. {
    194.         if (!bShow)
    195.         {
    196.                 ShowWindow(SW_HIDE);
    197.                 m_rcTarget.SetRect(0, 0, 0, 0);
    198.                 m_strTip = _T("");
    199.         }
    200.         else if (!m_strTip.IsEmpty())
    201.         {
    202.                 ShowWindow(SW_SHOW);
    203.                 m_txtTip->SetWindowText(m_strTip);
    204.         }
    205. }
    复制代码
    控件使用:
    我们需要在cpp中实现一个SToolTipFactory,然后将SToolTipFactory注册到App中。
    1. #include "CToolTipEx.h"
    2. class SToolTipFactory : public TObjRefImpl<IToolTipFactory>
    3. {
    4. public:
    5.         IToolTip* CreateToolTip(HWND hHost)
    6.         {
    7.                 CToolTipEx* pTipCtrl = new CToolTipEx;
    8.                 if (!pTipCtrl->CreateWnd())
    9.                 {
    10.                         delete pTipCtrl;
    11.                         return NULL;
    12.                 }
    13.                 return pTipCtrl;
    14.         }

    15.         void DestroyToolTip(IToolTip* pToolTip)
    16.         {
    17.                 if (pToolTip)
    18.                 {
    19.                         CToolTipEx* pTipCtrl = (CToolTipEx*)pToolTip;
    20.                         pTipCtrl->DestroyWindow();
    21.                 }
    22.         }
    23. };

    24. //注册
    25.         //注册用户自定义皮肤和控件
    26.         void Regitercustom()
    27.         {
    28.                 m_theApp->SetToolTipFactory(new SToolTipFactory);
    29.         }
    复制代码
    效果如下:
    10789b299d2547eda57942db103fc3b3.png
    代码地址:
    https://github.com/JeanPenty/ToolTipExDemo

    ToolTipExDemo-main.zip (33.81 KB, 下载次数: 0)





  • TA的每日心情
    开心
    6 天前
  • 签到天数: 64 天

    [LV.6]常住居民II

    81

    主题

    15

    回帖

    1807

    积分

    管理员

    积分
    1807
    发表于 2025-9-22 21:58:31 | 显示全部楼层
    谢谢分享,论坛有你更精彩!
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    Archiver|手机版|小黑屋|SOUI官方论坛

    GMT+8, 2025-10-3 10:37 , Processed in 0.070369 second(s), 25 queries .

    Powered by Discuz! X3.5

    © 2001-2025 Discuz! Team.

    快速回复 返回顶部 返回列表