В своё время меня не устроил стандартный CTooltipCtrl -- мне была нужена подсказка которая бы появлялась и пропадала когда ей скажут. Кроме того, нужно было, что бы подсказка была прозрачна для всех сообщений мыши (я делал т.н. inplace tooltip). Этот простой класс делает всё вышеперечисленное.
Короткое описание:
m_hWndOwner -- окно, которое будет получать все сообщения мыши
DelayShowAtCursor( UINT time ) -- показать посказку под курсором через определённое время. Не сказать что бы самая востребованная функция, но нне это было нужно.
Остальное должно быть понятно
Маленькое замечание: при создании нужно указать окно хозяин, и это не тоже самое что окно владелец(m_hWndOwner). В качестве хозяина удобнее всего установить ::GetDesktopWindow(), в противном случае возникают малопонятные глюки с позиционированием.
namespace UI2
{
class Tooltip
: public CWindowImpl<Tooltip, ATL::CWindow>
{
public:
typedef CWindowImpl<Tooltip, ATL::CWindow> baseClass;
typedef Tooltip thisClass;
HWND m_hWndOwner;
private:
TOOLINFO m_ToolInfo;
bool m_bActive;
enum { TIMER_MSG_DELAY_SHOW = 100, TIMER_MSG_DELAY_HIDE = 101, };
static LPCTSTR GetWndClassName(){ return _T("Zaebis_Tooltip"); }
public:
DECLARE_WND_SUPERCLASS(GetWndClassName(), baseClass::GetWndClassName())
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_TIMER, OnTimer)
MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
END_MSG_MAP()
Tooltip()
: baseClass()
, m_bActive(false) // подсказка видна
, m_hWndOwner(0) // окно, которому будут передаваться мышиные сообщения
{
}
virtual ~Tooltip()
{ }
bool Create( HWND hWndParent, HWND hWndOwner = NULL )
{
HWND hWnd = ::CreateWindowEx(WS_EX_TOPMOST,
TOOLTIPS_CLASS,
NULL,
TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hWndParent,
NULL,
NULL,
NULL);
ATLASSERT(hWnd);
// initialize toolinfo struct
memset(&m_ToolInfo, 0, sizeof(m_ToolInfo));
m_ToolInfo.cbSize = sizeof(m_ToolInfo);
m_ToolInfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_SUBCLASS;
m_ToolInfo.hwnd = hWndParent;
::SendMessage(hWnd, TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
::SendMessage(hWnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &m_ToolInfo);
m_hWndOwner = hWndOwner;
SubclassWindow( hWnd );
return true;
}
void SetBackColor( COLORREF c ){ ::SendMessage(m_hWnd, TTM_SETTIPBKCOLOR, c, 0); }
void SetTextColor( COLORREF c ){ ::SendMessage(m_hWnd, TTM_SETTIPTEXTCOLOR, c, 0); }
void SetMargins( const RECT* rectMargins ){ ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)rectMargins); }
void SetMaxWidth( int maxWidth ){ ::SendMessage(m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)maxWidth); }
bool IsVisible(){ return m_bActive; };
CString GetText()
{
::SendMessage( m_hWnd, TTM_GETTEXT, 0, m_ToolInfo );
return CString( m_ToolInfo.lpszText );
}
void SetText( const TCHAR* str )
{
delete m_ToolInfo.lpszText;
if( str )
{
m_ToolInfo.lpszText = new TCHAR[ _tcslen(str)+1 ];
_tcscpy( m_ToolInfo.lpszText, str );
}
else m_ToolInfo.lpszText = NULL;
::SendMessage( m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)(LPTOOLINFO) &m_ToolInfo );
}
void Show( int x, int y )
{
m_bActive = true;
::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( x, y ) );
::SendMessage( m_hWnd, TTM_TRACKACTIVATE, TRUE, (LPARAM)(LPTOOLINFO) &m_ToolInfo );
}
void Show( const RECT* r )
{
m_bActive = true;
m_ToolInfo.rect = *r;
::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( r->left, r->top ) );
::SendMessage( m_hWnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(r->right - r->left) );
::SendMessage( m_hWnd, TTM_TRACKACTIVATE, TRUE, (LPARAM)(LPTOOLINFO)&m_ToolInfo );
}
void Show( BOOL bShow = TRUE )
{
KillTimer( TIMER_MSG_DELAY_SHOW );
KillTimer( TIMER_MSG_DELAY_HIDE );
m_bActive = (bShow == TRUE);
::SendMessage( m_hWnd, TTM_TRACKACTIVATE, bShow, (LPARAM)(LPTOOLINFO) &m_ToolInfo );
}
void Move( int x, int y )
{
::SendMessage( m_hWnd, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG( x, y ) );
}
void DelayShowAtCursor( UINT timeToShow )
{
KillTimer( TIMER_MSG_DELAY_SHOW );
SetTimer( TIMER_MSG_DELAY_SHOW, timeToShow );
}
operator HWND() { return m_hWnd; }
// Message handlers
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if( TIMER_MSG_DELAY_SHOW == wParam )
{
POINT pt; ::GetCursorPos( &pt );
Show( pt.x, pt.y+20 );
KillTimer( wParam );
}
else if( TIMER_MSG_DELAY_HIDE == wParam )
{
Show(FALSE);
KillTimer( wParam );
}
bHandled = FALSE;
return 0;
}
LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// forward message to owner window
if( m_hWndOwner )
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ClientToScreen( &pt ); ::ScreenToClient( m_hWndOwner, &pt );
lParam = PtToLPARAM(pt);
::SendMessage( m_hWndOwner, uMsg, wParam, lParam );
}
bHandled = TRUE;
return 0;
}
};
// ----------------------------------------------------
inline LPARAM PtToLPARAM( POINT pt )
{
LPARAM lParam = 0;
WORD* pLParam = (WORD*)&lParam;
pLParam[0] = (short)pt.x;
pLParam[1] = (short)pt.y;
return lParam;
}
}
Думай, что хочешь, делай, что хочешь, живи, как хочешь -- всё тебе припомню!!