由于Duilib的tooltip使用的是系统默认的实现,这里希望他能像普通窗口一样使用xml定制界面,所以决定尝试修改Duilib源码实现这个效果,最终还是做出一个版本。效果图:
1.为CControlUI增加下面4个函数:
- 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;
- }
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:
- else if( _tcscmp(pstrName, _T("usertooltip")) == 0 ) SetUserToolTipXml(pstrValue);
else if( _tcscmp(pstrName, _T("usertooltip")) == 0 ) SetUserToolTipXml(pstrValue);
可以对每个控件单独定制tooltip界面,并且使用IToolTipCallBack回调接口实现界面上的文本
2.自绘tooltip类
CustomToolTipWnd.h
- #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
#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
- #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
#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事件中增加下面的蓝色代码:
- 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);
- }
- <span style="color:#3333FF;">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());
- }</span>
- ::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);
- }
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,设置回调
- typedef struct _Info
- {
- CString tooltips[3];
- }Info;
- map<CControlUI*, Info> m_arrToolTips;
typedef struct _Info
{
CString tooltips[3];
}Info;
map<CControlUI*, Info> m_arrToolTips;
- 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);
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);
回调函数实现
- 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"";
- }
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
- <?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>
<?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>