Hallelujah. I know how to manually display a tooltip!!!
We do this by using tracking tooltips. But there is one trick/ pitfall.
Create tooltip
HWND createToolTip(HWND owner)
{
INITCOMMONCONTROLSEX ic{ sizeof(ic), ICC_WIN95_CLASSES };
InitCommonControlsEx(&ic);
HWND tip = CreateWindowExA(
WS_EX_TOPMOST|ex_style, //MSDN states that WS_EX_TOOLWINDOW is always apart of ToolTip style
TOOLTIPS_CLASSA,
NULL,
style, // MSDN states that WS_POPUP is always apart of ToolTip style
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
owner,
NULL,
(HINSTANCE)0x400000,
NULL
);
//SetWindowPos(tip,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
return tip;
}
Create and add Tracking Tool.
Note that the tooltip itself is not tracking. It is the tool that is a tracking tool.
Thus you can have multiple tools that are tracking and non-tracking registered for the same tool tip.
TOOLINFOA createTrackingTool(HWND owner,HWND tool)
{
TOOLINFOA info = {};
info.cbSize = sizeof(info);
info.uFlags = TTF_IDISHWND | //dictates that TOOLINFO::uId is Window Handle of tool
TTF_TRACK | //dictates that this is a tracking tool
TTF_ABSOLUTE; //Required for TTF_TRACK, ass tracking tools use absolute co-ords; Don't ask why.
//TTF_SUBCLASS is not needed for our case.
// but I think using TTF_SUBCLASS with TTF_TRACK can cause
// tooltip to automatically popup and balloon arrow pointing
// to a point we specify
info.hwnd = owner;
info.uId = (UINT_PTR)tool;
return info;
}
TOOLINFOA createTrackingTool(HWND owner,uint id,const RECT &toolRect)
{
TOOLINFOA info = {};
info.cbSize = sizeof(info);
info.uFlags = TTF_TRACK | TTF_ABSOLUTE;
info.hwnd = owner;
info.uId = id; // owner and id uniquely identifies a tool
info.rect = toolRect;
return info;
}
void addTool(HWND toolTip,const TOOLINFOA &info)
{
SendMessage(toolTip, TTM_ADDTOOL, 0, (LPARAM)&info);
}
Manipulate tool tip
void setText(HWND toolTip,TOOLINFOA &info,const char *text)
{
info.lpszText = text;
SendMessage(toolTip, TTM_SETTOOLINFO, 0, (LPARAM)&info);
}
void setPos(HWND toolTip,HWND relHwnd,int x,int y)
{
SendMessage(widget,TTM_TRACKACTIVATE,true,(LPARAM)&info);
POINT pt = {x,y};
ClientToScreen(relHwnd,&pt);
SendMessage(widget,TTM_TRACKPOSITION,0,MAKELPARAM(pt.x,pt.y));
}
void redraw(HWND toolTip)
{
RedrawWindow(toolTip,NULL,NULL,RDW_INVALIDATE);
}
Put Every together
LRESULT CALLBACK proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
if(msg == WM_CREATE)
{
HWND tip = createToolTip(mainWindow);
TOOLINFOA info = createTrackingTool(mainWindow,button);
addTool(tip,info);
// By causing the tooltip to draw itself now, it will be overdrawn
// by this window once WM_CREATE is finished.
// By redrawing the tooltip later you can see that the tooltip
// was really activated at this point.
setText(tip,info,"MyText");
setPos(tip,hwnd,20,20);
return 0;
}
if(msg == WM_SHOWWINDOW)
{
redraw(tip); //Cause the tool tip to redraw so it is visible on screen
return 0;
}
if(msg == WM_KEYDOWN)
{
// You can draw the tooltip now and not have to worry about this window
// drawing over the tooltip.
setText(tip,info,"Time to activate track tooltip");
setPos(tip,hwnd,20,20);
}
return DefWindowProc(hwnd,msg,wparam,lparam);
}