您的位置:首页 > 产品设计 > UI/UE

Duilib 源码分析之 ToolTip 篇

2017-12-15 16:41 661 查看
首先关于 ToolTip 的相关资料,建议先看一下百度百科的介绍:TOOLINFO

Duilib 中对 Tooltip 的用法还算是比较简单易懂的,而且实现方法也很简单,只需要为控件添加属性
tooltip
, 值是希望提示的字符串就可以了,当鼠标移动到控件上停留时,会发送 WM_MOUSEHOVER 消息,Duilib 此时就会开始显示 tooltip 窗口了。 接下来看一下实现 tooltip 的代码:

bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)
{
......
case WM_MOUSEHOVER:
......
// Create tooltip information
CDuiString sToolTip = pHover->GetToolTip();
if( sToolTip.IsEmpty() ) return true;
::ZeroMemory(&m_ToolTip, sizeof(TOOLINFO));
m_ToolTip.cbSize = sizeof(TOOLINFO);
m_ToolTip.uFlags = TTF_IDISHWND;
m_ToolTip.hwnd = m_hWndPaint;
m_ToolTip.uId = (UINT_PTR) m_hWndPaint;
m_ToolTip.hinst = m_hInstance;
m_ToolTip.lpszText = const_cast<LPTSTR>( (LPCTSTR) sToolTip );
m_ToolTip.rect = pHover->GetPos();
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);                  ::SendMessage(m_hwndTooltip,TTM_SETMAXTIPWIDTH,0, pHover->GetToolTipWidth());
}
if(!::IsWindowVisible(m_hwndTooltip))
{
::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM)&m_ToolTip);
::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&m_ToolTip);
}

......
case WM_MOUSELEAVE:
{
if( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip);
.....
}
}


以上代码段是创建、显示、隐藏 Tooltip 窗口的代码。从代码可以看出,一个窗口只创建了一个 Tooltip 的窗口,不论鼠标移动到哪个子控件上显示 Tooltip,其实都是显示的同一个 Windows 窗口,只不过会修改其中的文字而已

CreateWindowEx 创建一个 ToolTip 窗口

SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &m_ToolTip) 将 Tooltip 的数据设置到当前 ToolTip 窗口中

::SendMessage(m_hwndTooltip,TTM_SETMAXTIPWIDTH,0, pHover->GetToolTipWidth()) 设置 ToolTip 窗口的宽度,我看了下 Duilib 中目前
m_nTooltipWidth
默认为 300,而且没有对应的属性可以修改。我建议可以添加一个
tooltipwidth
的属性,解析到此属性后调用已存在的方法:
void SetToolTipWidth(int nWidth)


::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM)&m_ToolTip) 这行代码的作用其实是想改变 Tooltip 窗口中的文字,而且是在 Tooltip 隐藏的情况下,因为此时我们有可能是从前一个控件移动到下一个控件,此时需要重新显示 Tooltip 窗口并修改文字。控制 Tooltip 窗口的隐藏显示需要用到下面的 2 行代码

::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&m_ToolTip) 显示 Tooltip 窗口

::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &m_ToolTip) 隐藏 Tooltip 窗口

接下来,如果我们在 Duilib 中搜索一下
m_hwndTooltip
的出现场景,除了上面提到的场景和窗口关闭时销毁窗口外,还有一个地方用到了
m_hwndTooltip
:

case WM_MOUSEMOVE:
{
if( m_pRoot == NULL ) break;
// Start tracking this entire window again...
if( !m_bMouseTracking ) {
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.hwndTrack = m_hWndPaint;
tme.dwHoverTime = m_hwndTooltip == NULL ? m_iHoverTime : (DWORD) ::SendMessage(m_hwndTooltip, TTM_GETDELAYTIME, TTDT_INITIAL, 0L);
_TrackMouseEvent(&tme);
m_bMouseTracking = true;
}
}


这里用到 了一个 API :
BOOL TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack)
, 这个函数可以寄送
WM_MOUSEHOVER
WM_MOUSELEAVE
两个消息, 默认情况下 Windows 是不会向窗口发送这两个消息的,需要调用
TrackMouseEvent
来实现。
RACKMOUSEEVENT
的定义如下:

typedef struct tagTRACKMOUSEEVENT {
DWORD cbSize;
DWORD dwFlags;
HWND  hwndTrack;
DWORD dwHoverTime;
} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;


cbSize -> 直接设置为
sizeof(TRACKMOUSEEVENT)
即可

dwFlags ->代表
TrackMouseEvent
寄送的消息类型,
TME_HOVER
TME_LEAVE
分别对应 WM_MOUSEHOVER
WM_MOUSELEAVE
,也可以两个都写上:
TME_HOVER | TME_LEAVE


hwndTrack -> 寄送消息的目的窗口

dwHoverTime -> 发送
WM_MOUSEHOVER
消息前鼠标所需保持停止不动的时间

每次
TrackMouseEvent
调用并发送消息后即失效,若想再次接收
WM_MOUSEHOVER
WM_MOUSELEAVE
需要再次调用
TrackMouseEvent
。这部分实现可以看一下
CPaintManagerUI::m_bMouseTracking
的赋值情况,每次
WM_MOUSEHOVER
WM_MOUSELEAVE
处理后即设置为
false
, 且在
WM_MOUSEMOVE
时发现为
false
,会重新调用
TrackMouseEvent
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 tooltip 控件