Duilib支持自绘tooltip

由于Duilib的tooltip使用的是系统默认的实现,这里希望他能像普通窗口一样使用xml定制界面,所以决定尝试修改Duilib源码实现这个效果,最终还是做出一个版本。效果图:


1.为CControlUI增加下面4个函数:

  1. virtual void SetUserToolTipXml(LPCTSTR pstrXml);  
  2. virtual CDuiString GetUserToolTipXml() const;  
  3. virtual void SetToolTipCallBack(IToolTipCallBack* pCallBack);  
  4. virtual IToolTipCallBack* GetToolTipCallback() const;  
  5.   
  6. void CControlUI::SetUserToolTipXml(LPCTSTR pstrXml)  
  7. {  
  8.     m_sToolTipXml = pstrXml;  
  9. }  
  10.   
  11. CDuiString CControlUI::GetUserToolTipXml() const  
  12. {  
  13.     return m_sToolTipXml;  
  14. }  
  15.   
  16. void CControlUI::SetToolTipCallBack(IToolTipCallBack* pCallBack)  
  17. {  
  18.     m_pCallBack = pCallBack;  
  19. }  
  20.   
  21. IToolTipCallBack* CControlUI::GetToolTipCallback() const  
  22. {  
  23.     return m_pCallBack;  
  24. }  
virtual void SetUserToolTipXml(LPCTSTR pstrXml);
virtual CDuiString GetUserToolTipXml() const;
virtual void SetToolTipCallBack(IToolTipCallBack* pCallBack);
virtual IToolTipCallBack* GetToolTipCallback() const;

void CControlUI::SetUserToolTipXml(LPCTSTR pstrXml)
{
    m_sToolTipXml = pstrXml;
}

CDuiString CControlUI::GetUserToolTipXml() const
{
    return m_sToolTipXml;
}

void CControlUI::SetToolTipCallBack(IToolTipCallBack* pCallBack)
{
    m_pCallBack = pCallBack;
}

IToolTipCallBack* CControlUI::GetToolTipCallback() const
{
    return m_pCallBack;
}


CControlUI::SetAttribute:

  1. else if( _tcscmp(pstrName, _T("usertooltip")) == 0 ) SetUserToolTipXml(pstrValue);  
else if( _tcscmp(pstrName, _T("usertooltip")) == 0 ) SetUserToolTipXml(pstrValue);

可以对每个控件单独定制tooltip界面,并且使用IToolTipCallBack回调接口实现界面上的文本

2.自绘tooltip类

CustomToolTipWnd.h

  1. #pragma once  
  2.   
  3.   
  4. namespace DuiLib {  
  5.   
  6.     class IToolTipCallBack {  
  7.     public:  
  8.         virtual LPCTSTR GetToolTip(CControlUI* pTipOwner, LPCTSTR pstrTipCtrl) = 0;  
  9.     };  
  10.   
  11.   
  12.     class CCustomToolTipWnd : public CWindowWnd  
  13.     {  
  14.     public:  
  15.         CCustomToolTipWnd(CControlUI* pOwner);  
  16.         ~CCustomToolTipWnd(void);  
  17.   
  18.         void Init(LPCTSTR pstrXml, IToolTipCallBack* callback);  
  19.     protected:  
  20.         LPCTSTR GetWindowClassName() const;  
  21.         UINT GetClassStyle() const;       
  22.   
  23.         void OnFinalMessage(HWND hWnd);  
  24.         LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);  
  25.   
  26.         void Walk(CControlUI* pCtrl);  
  27.   
  28.     private:  
  29.         CPaintManagerUI m_pm;  
  30.         CDuiString m_sXml;  
  31.         IToolTipCallBack* m_pCallBack;  
  32.         CControlUI* m_pOwner;  
  33.     };  
  34.   
  35. }// namespace Duilib  
#pragma once


namespace DuiLib {

	class IToolTipCallBack {
	public:
		virtual LPCTSTR GetToolTip(CControlUI* pTipOwner, LPCTSTR pstrTipCtrl) = 0;
	};


	class CCustomToolTipWnd : public CWindowWnd
	{
	public:
		CCustomToolTipWnd(CControlUI* pOwner);
		~CCustomToolTipWnd(void);

		void Init(LPCTSTR pstrXml, IToolTipCallBack* callback);
	protected:
		LPCTSTR GetWindowClassName() const;
		UINT GetClassStyle() const;		

		void OnFinalMessage(HWND hWnd);
		LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);

		void Walk(CControlUI* pCtrl);

	private:
		CPaintManagerUI m_pm;
		CDuiString m_sXml;
		IToolTipCallBack* m_pCallBack;
		CControlUI* m_pOwner;
	};

}// namespace Duilib

CustomToolTipWnd.cpp

  1. #include "stdafx.h"  
  2. #include "CustomToolTipWnd.h"  
  3.   
  4. namespace DuiLib {  
  5.     CCustomToolTipWnd::CCustomToolTipWnd(CControlUI* pOwner) : m_pOwner(pOwner), m_pCallBack(NULL)  
  6.     {  
  7.     }  
  8.   
  9.     CCustomToolTipWnd::~CCustomToolTipWnd(void)  
  10.     {  
  11.     }  
  12.   
  13.     LPCTSTR CCustomToolTipWnd::GetWindowClassName() const  
  14.     {  
  15.         return TOOLTIPS_CLASS;  
  16.     }  
  17.   
  18.     UINT CCustomToolTipWnd::GetClassStyle() const  
  19.     {  
  20.         return 0;  
  21.     }  
  22.   
  23.     void CCustomToolTipWnd::OnFinalMessage(HWND hWnd)  
  24.     {  
  25.         //delete this;  
  26.     }  
  27.   
  28.     void CCustomToolTipWnd::Init(LPCTSTR pstrXml, IToolTipCallBack* callback)  
  29.     {  
  30.         ASSERT(pstrXml);  
  31.         m_pCallBack = callback;  
  32.         m_pm.Init(m_hWnd);  
  33.         CDialogBuilder builder;  
  34.         CControlUI* pRoot = builder.Create(pstrXml, (UINT)0, NULL, &m_pm);  
  35.         ASSERT(pRoot && "Failed to parse XML");  
  36.         m_pm.AttachDialog(pRoot);  
  37.   
  38.         if (m_pCallBack)  
  39.         {  
  40.             Walk(pRoot);  
  41.         }  
  42.     }  
  43.   
  44.     LRESULT CCustomToolTipWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)  
  45.     {  
  46.         LRESULT lRes = 0;  
  47.   
  48.         if( uMsg == WM_DESTROY ) {  
  49.               
  50.         }  
  51.         else if ( uMsg == WM_WINDOWPOSCHANGING || uMsg == WM_WINDOWPOSCHANGED) {  
  52.             WINDOWPOS* pos = (WINDOWPOS*)lParam;  
  53.             pos->cx = m_pm.GetInitSize().cx;  
  54.             pos->cy = m_pm.GetInitSize().cy;  
  55.         }  
  56.         else if ( uMsg == WM_PAINT || uMsg == WM_ERASEBKGND ) {  
  57.             return m_pm.MessageHandler(uMsg, wParam, lParam, lRes);  
  58.         }  
  59.           
  60.         return CWindowWnd::HandleMessage(uMsg, wParam, lParam);  
  61.     }  
  62.   
  63.     void CCustomToolTipWnd::Walk(CControlUI* pCtrl)  
  64.     {  
  65.         if (pCtrl == NULL)  
  66.         {  
  67.             return;  
  68.         }  
  69.   
  70.         IContainerUI* pContainer = static_cast<IContainerUI*>(pCtrl->GetInterface(L"IContainer"));  
  71.         if (pContainer != NULL)  
  72.         {  
  73.             for (int i = 0; i < pContainer->GetCount(); ++i)  
  74.             {  
  75.                 CControlUI* pItem = pContainer->GetItemAt(i);  
  76.                 Walk(pItem);  
  77.             }  
  78.         }  
  79.         else  
  80.         {  
  81.             pCtrl->SetText(m_pCallBack->GetToolTip(m_pOwner, pCtrl->GetName()));  
  82.         }  
  83.     }  
  84.   
  85. }//namespace Duilib  
#include "stdafx.h"
#include "CustomToolTipWnd.h"

namespace DuiLib {
	CCustomToolTipWnd::CCustomToolTipWnd(CControlUI* pOwner) : m_pOwner(pOwner), m_pCallBack(NULL)
	{
	}

	CCustomToolTipWnd::~CCustomToolTipWnd(void)
	{
	}

	LPCTSTR CCustomToolTipWnd::GetWindowClassName() const
	{
		return TOOLTIPS_CLASS;
	}

	UINT CCustomToolTipWnd::GetClassStyle() const
	{
		return 0;
	}

	void CCustomToolTipWnd::OnFinalMessage(HWND hWnd)
	{
		//delete this;
	}

	void CCustomToolTipWnd::Init(LPCTSTR pstrXml, IToolTipCallBack* callback)
	{
		ASSERT(pstrXml);
		m_pCallBack = callback;
		m_pm.Init(m_hWnd);
		CDialogBuilder builder;
		CControlUI* pRoot = builder.Create(pstrXml, (UINT)0, NULL, &m_pm);
		ASSERT(pRoot && "Failed to parse XML");
		m_pm.AttachDialog(pRoot);

		if (m_pCallBack)
		{
			Walk(pRoot);
		}
	}

	LRESULT CCustomToolTipWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		LRESULT lRes = 0;

		if( uMsg == WM_DESTROY ) {
			
		}
		else if ( uMsg == WM_WINDOWPOSCHANGING || uMsg == WM_WINDOWPOSCHANGED) {
			WINDOWPOS* pos = (WINDOWPOS*)lParam;
			pos->cx = m_pm.GetInitSize().cx;
			pos->cy = m_pm.GetInitSize().cy;
		}
		else if ( uMsg == WM_PAINT || uMsg == WM_ERASEBKGND ) {
			return m_pm.MessageHandler(uMsg, wParam, lParam, lRes);
		}
		
		return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
	}

	void CCustomToolTipWnd::Walk(CControlUI* pCtrl)
	{
		if (pCtrl == NULL)
		{
			return;
		}

		IContainerUI* pContainer = static_cast<IContainerUI*>(pCtrl->GetInterface(L"IContainer"));
		if (pContainer != NULL)
		{
			for (int i = 0; i < pContainer->GetCount(); ++i)
			{
				CControlUI* pItem = pContainer->GetItemAt(i);
				Walk(pItem);
			}
		}
		else
		{
			pCtrl->SetText(m_pCallBack->GetToolTip(m_pOwner, pCtrl->GetName()));
		}
	}

}//namespace Duilib

3.修改CPaintManagerUI加入CCustomToolTipWnd
添加成员变量CCustomToolTipWnd* m_pCustomToolTipWnd;在MessageHandler的WM_MOUSEHOVER事件中增加下面的蓝色代码:  
  1.          if( m_hwndTooltip == NULL ) {  
  2.     m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWndPaint, NULL, m_hInstance, NULL);          
  3.              ::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &m_ToolTip);  
  4.          }  
  5.   
  6. <span style="color:#3333FF;">if (m_pCustomToolTipWnd) {  
  7.     m_pCustomToolTipWnd->Unsubclass();     
  8. }  
  9.   
  10. if ( pHover->GetUserToolTipXml() != L"" ) {    
  11.     delete m_pCustomToolTipWnd;  
  12.     m_pCustomToolTipWnd = new CCustomToolTipWnd(pHover);  
  13.     if( m_pCustomToolTipWnd == NULL ) return 0;  
  14.     m_pCustomToolTipWnd->Subclass(m_hwndTooltip);    
  15.     m_pCustomToolTipWnd->Init(pHover->GetUserToolTipXml(), pHover->GetToolTipCallback());  
  16. }</span>      
  17.   
  18. ::SendMessage( m_hwndTooltip,TTM_SETMAXTIPWIDTH,0, pHover->GetToolTipWidth());  
  19.          ::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM) &m_ToolTip);  
  20.          ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &m_ToolTip);  
  21.      }  
            if( m_hwndTooltip == NULL ) {
				m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWndPaint, NULL, m_hInstance, NULL);        
                ::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &m_ToolTip);
            }

			if (m_pCustomToolTipWnd) {
				m_pCustomToolTipWnd->Unsubclass();	
			}

			if ( pHover->GetUserToolTipXml() != L"" ) {	
				delete m_pCustomToolTipWnd;
				m_pCustomToolTipWnd = new CCustomToolTipWnd(pHover);
				if( m_pCustomToolTipWnd == NULL ) return 0;
				m_pCustomToolTipWnd->Subclass(m_hwndTooltip);  
				m_pCustomToolTipWnd->Init(pHover->GetUserToolTipXml(), pHover->GetToolTipCallback());
			}	

			::SendMessage( m_hwndTooltip,TTM_SETMAXTIPWIDTH,0, pHover->GetToolTipWidth());
            ::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM) &m_ToolTip);
            ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &m_ToolTip);
        }



实例代码及XML:

为列表的每一项添加tooltip,设置回调

  1. typedef struct _Info  
  2. {  
  3.     CString tooltips[3];  
  4. }Info;  
  5.   
  6.   
  7. map<CControlUI*, Info> m_arrToolTips;  
		typedef struct _Info
		{
			CString tooltips[3];
		}Info;


		map<CControlUI*, Info> m_arrToolTips;


  1. CDialogBuilder builder;  
  2.             CListUI* jokelist = static_cast<CListUI*>(m_PaintManager.FindControl(L"jocklist"));  
  3.             CListContainerElementUI* pItem = static_cast<CListContainerElementUI*>(builder.Create(L"item.xml", 0, NULL, &m_PaintManager));  
  4.             CString s;  
  5.             s.Format(L"%d", jokelist->GetCount());  
  6.             pItem->SetFixedHeight(30);  
  7.             pItem->SetText(s);  
  8.             pItem->SetToolTip(s);  
  9.             pItem->SetToolTipCallBack(this);  
  10.             //if (jokelist->GetCount() % 2 == 0)  
  11.             {  
  12.                 pItem->SetUserToolTipXml(L"tooltip1.xml");  
  13.             }  
  14.             //else  
  15.             {  
  16.                 //pItem->SetUserToolTipXml(L"tooltip2.xml");  
  17.             }             
  18.   
  19.             Info sa;  
  20.             sa.tooltips[0] = s;  
  21.             sa.tooltips[1] =  CTime::GetCurrentTime().Format(L"%Y/%m/%d %H:%M:%S ");  
  22.             sa.tooltips[2] +=  L"你好,我是" + s + L"。";  
  23.             m_arrToolTips[pItem] = sa;  
  24.   
  25.             jokelist->Add(pItem);  
CDialogBuilder builder;
			CListUI* jokelist = static_cast<CListUI*>(m_PaintManager.FindControl(L"jocklist"));
			CListContainerElementUI* pItem = static_cast<CListContainerElementUI*>(builder.Create(L"item.xml", 0, NULL, &m_PaintManager));
			CString s;
			s.Format(L"%d", jokelist->GetCount());
			pItem->SetFixedHeight(30);
			pItem->SetText(s);
			pItem->SetToolTip(s);
			pItem->SetToolTipCallBack(this);
			//if (jokelist->GetCount() % 2 == 0)
			{
				pItem->SetUserToolTipXml(L"tooltip1.xml");
			}
			//else
			{
				//pItem->SetUserToolTipXml(L"tooltip2.xml");
			}			

			Info sa;
			sa.tooltips[0] = s;
			sa.tooltips[1] =  CTime::GetCurrentTime().Format(L"%Y/%m/%d %H:%M:%S ");
			sa.tooltips[2] +=  L"你好,我是" + s + L"。";
			m_arrToolTips[pItem] = sa;

			jokelist->Add(pItem);

 回调函数实现   

  1. LPCTSTR CMainFrame::GetToolTip( CControlUI* pTipOwner, LPCTSTR pstrTipCtrl )  
  2. {  
  3.     if ( _tcscmp(pstrTipCtrl, L"IDC_CURRENT_BUDDY_ID") ==0 )  
  4.     {  
  5.         return m_arrToolTips[pTipOwner].tooltips[0];  
  6.     }  
  7.     else if ( _tcscmp(pstrTipCtrl, L"IDC_CURRENT_BUDDY_NAME") ==0 )  
  8.     {  
  9.         return m_arrToolTips[pTipOwner].tooltips[1];  
  10.     }  
  11.     else if ( _tcscmp(pstrTipCtrl, L"IDC_CURRENT_BUDDY_MESSAGE") ==0 )  
  12.     {  
  13.         return m_arrToolTips[pTipOwner].tooltips[2];  
  14.     }  
  15.   
  16.     return L"";  
  17. }  
LPCTSTR CMainFrame::GetToolTip( CControlUI* pTipOwner, LPCTSTR pstrTipCtrl )
{
	if ( _tcscmp(pstrTipCtrl, L"IDC_CURRENT_BUDDY_ID") ==0 )
	{
		return m_arrToolTips[pTipOwner].tooltips[0];
	}
	else if ( _tcscmp(pstrTipCtrl, L"IDC_CURRENT_BUDDY_NAME") ==0 )
	{
		return m_arrToolTips[pTipOwner].tooltips[1];
	}
	else if ( _tcscmp(pstrTipCtrl, L"IDC_CURRENT_BUDDY_MESSAGE") ==0 )
	{
		return m_arrToolTips[pTipOwner].tooltips[2];
	}

	return L"";
}

item.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <Window size="200,80" mininfo="200,54" caption="0,0,0,0" sizebox="4,4,4,4" bktrans="false">  
  3.   <Font id="0" name="微软雅黑" size="14" bold="false" default="true" />  
  4.   <Font id="1" name="微软雅黑" size="12" bold="false"/>  
  5.   <Default name="VScrollBar" value="width="9" button1normalimage="file='public_scrollbar.png' source='0,0,9,9'" button1hotimage="file='public_scrollbar.png' source='9,0,18,9'" button1pushedimage="file='public_scrollbar.png' source='18,0,27,9'" button2normalimage="file='public_scrollbar.png' source='0,15,9,24'" button2hotimage="file='public_scrollbar.png' source='9,15,18,24'" button2pushedimage="file='public_scrollbar.png' source='18,15,27,24'" thumbnormalimage="file='public_scrollbar.png' source='0,24,9,30' corner='0,2,0,2'" thumbhotimage="file='public_scrollbar.png' source='9,24,18,30' corner='0,2,0,2'" thumbpushedimage="file='public_scrollbar.png' source='18,24,27,30' corner='0,2,0,2'" bknormalimage="file='public_scrollbar.png' source='0,9,9,15'"" />  
  6.   <VerticalLayout bkcolor="#FF9CCF7A">  
  7.     <HorizontalLayout inset="3,3,3,3">  
  8.       <Button name="IDC_CURRENT_BUDDY_FACE" width="48" height="48" xborderround="48,48" xbkcolor="#FFDCE7D7" foreimage="pikachu.png" normalimage="tabbtn_highlight.png" hotimage="indicator\indicator_window_btn_hot.png" pushedimage="indicator\indicator_window_btn_hot.png" />  
  9.       <VerticalLayout>  
  10.         <Label name="IDC_CURRENT_BUDDY_ID" autocalcwidth="false" textpadding="8,0,0,0" textcolor="#FF210029" font="0"/>  
  11.         <Label name="IDC_CURRENT_BUDDY_NAME" autocalcwidth="false" textpadding="8,0,0,0" textcolor="#FF210029" font="0"/>  
  12.         <Label name="IDC_CURRENT_BUDDY_MESSAGE" autocalcwidth="false" textpadding="8,0,0,0" textcolor="#FF210029" font="0"/>  
  13.       </VerticalLayout>  
  14.     </HorizontalLayout>  
  15.   </VerticalLayout>  
  16. </Window>  
<?xml version="1.0" encoding="utf-8"?>
<Window size="200,80" mininfo="200,54" caption="0,0,0,0" sizebox="4,4,4,4" bktrans="false">
  <Font id="0" name="微软雅黑" size="14" bold="false" default="true" />
  <Font id="1" name="微软雅黑" size="12" bold="false"/>
  <Default name="VScrollBar" value="width="9" button1normalimage="file='public_scrollbar.png' source='0,0,9,9'" button1hotimage="file='public_scrollbar.png' source='9,0,18,9'" button1pushedimage="file='public_scrollbar.png' source='18,0,27,9'" button2normalimage="file='public_scrollbar.png' source='0,15,9,24'" button2hotimage="file='public_scrollbar.png' source='9,15,18,24'" button2pushedimage="file='public_scrollbar.png' source='18,15,27,24'" thumbnormalimage="file='public_scrollbar.png' source='0,24,9,30' corner='0,2,0,2'" thumbhotimage="file='public_scrollbar.png' source='9,24,18,30' corner='0,2,0,2'" thumbpushedimage="file='public_scrollbar.png' source='18,24,27,30' corner='0,2,0,2'" bknormalimage="file='public_scrollbar.png' source='0,9,9,15'"" />
  <VerticalLayout bkcolor="#FF9CCF7A">
    <HorizontalLayout inset="3,3,3,3">
      <Button name="IDC_CURRENT_BUDDY_FACE" width="48" height="48" xborderround="48,48" xbkcolor="#FFDCE7D7" foreimage="pikachu.png" normalimage="tabbtn_highlight.png" hotimage="indicator\indicator_window_btn_hot.png" pushedimage="indicator\indicator_window_btn_hot.png" />
      <VerticalLayout>
        <Label name="IDC_CURRENT_BUDDY_ID" autocalcwidth="false" textpadding="8,0,0,0" textcolor="#FF210029" font="0"/>
        <Label name="IDC_CURRENT_BUDDY_NAME" autocalcwidth="false" textpadding="8,0,0,0" textcolor="#FF210029" font="0"/>
        <Label name="IDC_CURRENT_BUDDY_MESSAGE" autocalcwidth="false" textpadding="8,0,0,0" textcolor="#FF210029" font="0"/>
      </VerticalLayout>
    </HorizontalLayout>
  </VerticalLayout>
</Window>


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值