Related
We are trying to create dynamic tool tips where the tool tip changes based on the language the user selected. (C++ win api 64 bit application, no external libraries being used)
However we can't get this to work. The tool tip only ever displays the first letter of the text.
Code snipet:
wchar_t* ws = new wchar_t[200];
swprintf(ws, 200, L"Hello");
TTTOOLINFOW toolInfoW = { 0 };
toolInfoW.cbSize = sizeof(toolInfoW);
toolInfoW.hwnd = hDlg;
toolInfoW.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfoW.uId = (UINT_PTR)hwndTool;
toolInfoW.lpszText = ws;
Even if we hard code the 'Hello', only the first letter is displayed
TTTOOLINFOW toolInfoW = { 0 };
toolInfoW.cbSize = sizeof(toolInfoW);
toolInfoW.hwnd = hDlg;
toolInfoW.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfoW.uId = (UINT_PTR)hwndTool;
toolInfoW.lpszText = L"Hello";
We must be missing something extremely obvious because it can't be this hard to get this to work.
Thanks in advance for any advice.
Out of curiosity, I've tried it out, and the following code did work when compiled for x64 using MSVC 2019 on Windows 10. It creates a simple window with a button in it, and when you hover over that button, it displays a tooltip with text This works! ☺ (containing a smiley face Unicode character).
Be sure to compile this example with C++17 enabled, otherwise the buffer returned by data() will have type const wchar_t* and thus will be incompatible with the lpszText (member of the TTTOOLINFOW structure), which has type LPWSTR, i.e. just wchar_t*.
#pragma comment(linker, "\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")
#pragma comment(lib, "comctl32.lib")
#define _WIN32_WINNT _WIN32_WINNT_WIN10
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include <SDKDDKVer.h>
#include <windows.h>
#include <commctrl.h>
#include <string>
HINSTANCE g_hInstance{ nullptr };
HWND CreateMyButton(HINSTANCE hInstance, HWND hWndApp)
{
return ::CreateWindowExW(0UL, L"BUTTON", L"Hover over this button",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 45, 10, 200, 35,
hWndApp, nullptr, hInstance, nullptr);
}
void CreateMyTooltip(HWND hWndParent, HWND hWndControl)
{
HWND hWndTip{ ::CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW,
nullptr, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, 0, 0, 0, 0,
hWndParent, nullptr, nullptr, nullptr) };
::SetWindowPos(hWndTip, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
std::wstring wsTooltipText{ L"This works! \u263A" };
TTTOOLINFOW ti{};
ti.cbSize = sizeof ti;
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
ti.hwnd = hWndParent;
ti.uId = reinterpret_cast<UINT_PTR>(hWndControl);
ti.lpszText = wsTooltipText.data();
::SendMessageW(hWndTip, TTM_ADDTOOL, 0U, reinterpret_cast<LPARAM>(&ti));
}
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
CreateMyTooltip(hWnd, CreateMyButton(g_hInstance, hWnd));
break;
case WM_DESTROY:
::PostQuitMessage(0);
break;
default:
break;
}
return ::DefWindowProcW(hWnd, msg, wParam, lParam);
}
int WINAPI wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int)
{
g_hInstance = hInstance;
const INITCOMMONCONTROLSEX initControls
{
sizeof(INITCOMMONCONTROLSEX),
ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES
};
::InitCommonControlsEx(&initControls);
WNDCLASSW wc{};
wc.lpfnWndProc = MyWndProc;
wc.hInstance = hInstance;
wc.hCursor = ::LoadCursorW(nullptr, IDC_ARROW);
wc.hbrBackground = ::GetSysColorBrush(COLOR_3DFACE);
wc.lpszClassName = L"Tooltip";
::RegisterClassW(&wc);
::CreateWindowExW(0UL, wc.lpszClassName, L"Tooltip Example",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
300, 100, nullptr, nullptr, hInstance, nullptr);
MSG msg{};
while (::GetMessageW(&msg, nullptr, 0U, 0U))
{
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
}
return static_cast<int>(msg.wParam);
}
In a Win32 / C++ app, running under 64-bit Windows 7, using Visual Studio 16.7.7, I want to implement tracking tooltips in the main (and only) window. Following the examples in Microsoft SDK documentation, the tracking seems to work, but the tooltip window itself does not appear.
I have verified, using the debugger, that the tooltip is activated and deactivated, that the expected mouse tracking is occurring, that the screen coordinates in the TTM_TRACKPOSITION message are correct, and the text is OK. The app is Unicode, and I have checked that the structures are the Unicode versions, and common controls are initialized, and that the current version of the common controls library is linked. The tooltip window has the WS_EX_TOPMOST and WS_EX_TOOLWINDOW extended styles, per Spy++.
What changes are needed to make the tooltip show?
Here is the code I am using:
Global variables:
HINSTANCE hInst;
HWND hWnd;
HWND hwndTT;
WCHAR ttText[12];
TOOLINFO toolTipInfo;
BOOL trackingMouse;
Initialization:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
// Set up for mouse tracking (tooltips)
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = ICC_BAR_CLASSES;
BOOL ok=InitCommonControlsEx(&icc);
trackingMouse = FALSE;//
WCHAR nullString[15] = { L"After create" };
hwndTT = CreateTrackingToolTip(0 /*toolID*/, hWnd, nullString);
...
HWND CreateTrackingToolTip(int toolID, HWND hWndParent, WCHAR* pText)
{
// Create a tooltip.
HWND h = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
hWndParent, NULL, hInst, NULL);
if(!h)
{
return NULL;
}
// Set up the tool information. In this case, the "tool" is the entire parent window.
memset(&toolTipInfo, 0, sizeof(TOOLINFO));
toolTipInfo.cbSize = sizeof(TOOLINFO);
toolTipInfo.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
toolTipInfo.hwnd = hWndParent;
toolTipInfo.hinst = hInst;
toolTipInfo.lpszText = pText;
toolTipInfo.uId = (UINT_PTR)hWndParent;
GetClientRect(hWndParent, &toolTipInfo.rect);
// Associate the tooltip with the tool window.
SendMessage(h, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&toolTipInfo);
return h;
}
Window procedure:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_MOUSELEAVE: // The mouse pointer has left our window. Deactivate the tooltip.
SendMessage(hwndTT, TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)&toolTipInfo);
trackingMouse = FALSE;
TRACE(L"\nDeactivate tooltip");
return FALSE;
case WM_MOUSEMOVE:
static int oldX, oldY;
int newX, newY;
if(!trackingMouse) // The mouse has just entered the window.
{ // Request notification when the mouse leaves.
TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) };
tme.hwndTrack = hWnd;
tme.dwFlags = TME_LEAVE;
BOOL ok=TrackMouseEvent(&tme);
// Activate the tooltip.
SendMessage(hwndTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&toolTipInfo);
trackingMouse = TRUE;
TRACE(L"\nActivate tooltip");
}
newX = GET_X_LPARAM(lParam); newY = GET_Y_LPARAM(lParam);
// Make sure the mouse has actually moved. The presence of the tooltip
// causes Windows to send the message continuously.
if((newX != oldX) || (newY != oldY))
{
oldX = newX; oldY = newY;
// Update the text.
swprintf_s(ttText, ARRAYSIZE(ttText), L"%d, %d", newX, newY);
toolTipInfo.lpszText = ttText;
SendMessage(hwndTT, TTM_SETTOOLINFO, 0, (LPARAM)&toolTipInfo);
// Position the tooltip. The coordinates are adjusted so that the tooltip does not overlap the mouse pointer.
POINT pt = { newX, newY };
ClientToScreen(hWnd, &pt);
SendMessage(hwndTT, TTM_TRACKPOSITION, 0, (LPARAM)MAKELONG(pt.x + 10, pt.y - 20));
}
return FALSE;
...
The following line is required:
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Refer to "Using Manifests or Directives to Ensure That Visual Styles Can Be Applied to Applications" for more detailed information.
I am creating a Windows desktop application using win32 api in visual studio 2019. I know there are many other options avialable to build UI like MFC, XAMAL and C#, but i needed to build it in win32. I have learnt some basics in win32 api but recently i was working on tabControll and there i got an issue or i missed some thing. I am creating two tabs and want to add different content withing them. My current code is working and creating the tabs but it is adding same content in both tabs. How should i define each tab's content differently.
void createTabView(HWND hWnd) {
RECT rcClient;
INITCOMMONCONTROLSEX icex;
static HWND hwndTab_1_1_1;
HWND hwndTab;
TCITEM tie;
int i;
TCHAR achTemp[256];
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
GetClientRect(hWnd, &rcClient);
hwndTab = CreateWindow(WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hWnd, NULL, hInst, NULL);
// Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 1, &tie);
tie.pszText = tabLBL2;
TabCtrl_InsertItem(hwndTab, 2, &tie);
SendMessage(hwndTab, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), 0);
HWND hwndStatic = CreateWindow(WC_STATIC, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInst, // g_hInst is the global instance handle
NULL);}
The tab control triggers the WM_NOTIFY signal when the tab page is switched, so as long as we process the WM_NOTIFY message, we can control the tab control message.
In the WM_NOTIFY message:
wParam: a control ID that identifies the WM_NOTIFY message sent.
lParam: a pointer to the NMHDR structure.
Therefore, we can determine the notification code sent by the Tab control in the WM_NOTIFY message processing program by judging the code value in the NMHDR structure.
We can use TCN_SELCHANGE to handle the operation when the Tab tab changes, and use TabCtrl_GetCurSel to get the index of the current tab and define the content of the current tab.
Here is the sample:
#include <Windows.h>
#include <commctrl.h>
LRESULT CALLBACK WndProc(HWND, UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam)
{
static HINSTANCE hInstance;
static HWND hwndTab = 0 , hwndStatic = 0;
TCITEM tie;
RECT rcClient;
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
TCHAR tabLBL1[256];
GetClientRect(hwnd, &rcClient);
switch (message)
{
case WM_CREATE:
{
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
hwndTab = CreateWindow(WC_TABCONTROL, "",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hwnd, NULL, hInstance, NULL);
// Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
wsprintf(tabLBL1, "tab1");
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
wsprintf(tabLBL1, "tab2");
TabCtrl_InsertItem(hwndTab, 1, &tie);
SendMessage(hwndTab, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), 0);
hwndStatic = CreateWindow(WC_STATIC, "",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
ShowWindow(hwndStatic,TRUE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NOTIFY:
if (((LPNMHDR)lParam)->code == TCN_SELCHANGE)
{
int tabID = TabCtrl_GetCurSel(hwndTab);
switch (tabID)
{
case 0:
ShowWindow(hwndStatic, TRUE);
break;
case 1:
ShowWindow(hwndStatic, FALSE);
break;
default:
break;
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
Not sure if this is the solution, but the iItem parameter to TabCtrl_InsertItem is zero-based. Try:
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
tie.pszText = tabLBL2;
TabCtrl_InsertItem(hwndTab, 1, &tie);
Also (and I'm not sure if this is relevant), you look like you intended to call InitCommonControlsEx in your code but fail to do so.
I am newbie in c++ win32 Programming and I am using visual studio 2013 on Windows 7 X64 SP1.
I have used this code in link below to create tooltip for a button in DialogBox and successfully it worked.
Tooltip for button
but when I want to change the background color or foreground color , it does not work and it shows the default colors.
SendMessage(hwndTip, TTM_SETTIPBKCOLOR, 0xFF326FD8, 0);
//SendMessage(hwndTip, TTM_SETTIPBKCOLOR, (WPARAM)CreateSolidBrush(RGB(255,255, 255), 0);
SendMessage(hwndTip, TTM_SETTIPTEXTCOLOR, (WPARAM)CreateSolidBrush(RGB(255,255, 255)), 0);
Because in this link :
http://msdn.microsoft.com/en-us/library/windows/desktop/bb760411%28v=vs.85%29.aspx
the MSDN said that "When visual styles are enabled, this message has no effect." so I changed the
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON |TTS_USEVISUALSTYLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL,
hInst, NULL);
to :
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL,
hInst, NULL);
but without any success.
also I have used :
#pragma comment(linker, \
"\"/manifestdependency:type='Win32' "\
"name='Microsoft.Windows.Common-Controls' "\
"version='6.0.0.0' "\
"processorArchitecture='*' "\
"publicKeyToken='6595b64144ccf1df' "\
"language='*'\"")
in my code so I removed it to see if tooltip coloring works but the tooltip did not appeared at all !
what is the problem ?
Thanks.
Update 1 :
Here is my full source code , hope to solve the problem :
Main.cpp :
#include <Windows.h>
#include <stdlib.h>
#include <tchar.h>
#include <memory>
#include <malloc.h>
#include "resource.h"
#include <CommCtrl.h>
#include <Uxtheme.h>
HINSTANCE hInst;
BOOL InitInstance(HINSTANCE, int);
INT_PTR CALLBACK MainWin(HWND, UINT, WPARAM, LPARAM);
#pragma comment(linker, \
"\"/manifestdependency:type='Win32' "\
"name='Microsoft.Windows.Common-Controls' "\
"version='6.0.0.0' "\
"processorArchitecture='*' "\
"publicKeyToken='6595b64144ccf1df' "\
"language='*'\"")
#pragma comment(lib, "ComCtl32.lib")
#pragma comment(lib,"UxTheme.lib")
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine,_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
while (GetMessage(&msg, NULL, 0, 0)>0)
{
if (!IsDialogMessage(msg.hwnd,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
HWND CreateToolTip(int toolID, HWND hDlg, HINSTANCE hInst, PTSTR pszText)
{
if (!toolID || !hDlg || !pszText)
{
return NULL;
}
HWND hwndTool = GetDlgItem(hDlg, toolID);
if (!hwndTool)
{
return NULL;
}
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON |TTS_USEVISUALSTYLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL,
hInst, NULL);
if (!hwndTip)
{
return NULL;
}
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hDlg;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hwndTool;
toolInfo.lpszText = pszText;
if (!SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo))
{
DestroyWindow(hwndTip);
return NULL;
}
SendMessage(hwndTip, TTM_SETTIPBKCOLOR, 0xFF326FD8, 0);
return hwndTip;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hWnd = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_MainDlg), NULL, MainWin, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
SetWindowTheme(hWnd, L"", L"");
return TRUE;
}
INT_PTR CALLBACK MainWin(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
{
CreateToolTip(IDC_TestBtn, hDlg, hInst, L"TESTTOOLTIP");
return (INT_PTR)TRUE;
}
break;
case WM_CLOSE:
DestroyWindow(hDlg);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_TestBtn)
{
MessageBox(NULL, L"TEST", L"TEST", MB_OK);
return (INT_PTR)TRUE;
}
}
return (INT_PTR)FALSE;
}
resource.h :
#define IDD_MainDlg 103
#define IDC_TestBtn 104
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 106
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1006
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
resource script for resource.rc :
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_MainDlg, DIALOG
BEGIN
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_MainDlg DIALOGEX 0, 0, 149, 75
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_TOOLWINDOW
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "testbtn",IDC_TestBtn,41,12,57,49
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
I'm attempting to add a set of tooltips to a set of checkboxes on a dialog inheriting from CAxDialogImpl, where CSG32GridViewControlDlg is my dialog's class.
Using the example code on MSDN as a base, I've added the following code:
void CSG32GridViewControlDlg::AddCheckboxTooltip(const int toolId, PTSTR tooltipText)
{
HWND hCheckbox = GetDlgItem(toolId);
char label1[501];
::GetWindowText(hCheckbox, label1, 500);
HINSTANCE hInstance = _AtlBaseModule.GetResourceInstance( ); // This bit I'm not sure about...
// Need to create the ToolTip first
HWND hWndToolTip = ::CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hCheckbox,
NULL,
hInstance, 0);
if (!hCheckbox || !hWndToolTip)
{
return;
}
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hCheckbox;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hWndToolTip;
toolInfo.lpszText = tooltipText;
LRESULT result = ::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM) &toolInfo);
return hWndToolTip;
}
Debugging the code, I can see that the message gets sent, and the result comes back as "1", which would seem to suggest that everything's worked successfully. But when I mouseover the checkbox in question... no tooltip.
What could I do to check if the tooltip is successfully registered, and why might it not be appearing on Mouseover? Alternatively, is there a better way to approach this?
There are a few problems with your code. The starting point worth mentioning is obviosuly this: How to Create a Tooltip for a Control.
Parent window for the tooltip control should be the dialog, not the checkbox
uId member for the tool with TTF_IDISHWND flag needs to be the tool window, and not tooltip control window
This gives code:
HWND AddCheckboxTooltip(const int toolId, PTSTR tooltipText)
{
HWND hCheckbox = GetDlgItem(toolId);
// Need to create the ToolTip first
HWND hWndToolTip = ::CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
m_hWnd,
NULL,
_AtlBaseModule.GetModuleInstance(), 0);
if (!hCheckbox || !hWndToolTip)
return NULL;
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hCheckbox;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hCheckbox;
toolInfo.lpszText = tooltipText;
LRESULT result = ::SendMessage(hWndToolTip, TTM_ADDTOOL,
0, (LPARAM) &toolInfo);
return hWndToolTip;
}
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL& /*bHandled*/)
{
AddCheckboxTooltip(IDC_CHECK1, _T("Checkbox Tooltip Test"));
//...
Which runs as: