WIN32API: owner-drawn button creates white background around the text when clicked - c++

I have created an Owner-Drawn button . I use the WM_CTLCOLORBTN message in order to paint it :
//get the text of the button
wchar_t buttonText[20];
int textLength = SendMessage((HWND)lParam,WM_GETTEXT,20,(LPARAM)buttonText);
Font FootlightMTLight(L"Footlight MT Light",20,0,false,false,false,L"Black");
SelectObject((HDC)wParam,FootlightMTLight.getWindowHandle());
TextOut((HDC)wParam,30,15,buttonText,textLength);
SetTextColor((HDC)wParam, RGB(0,0,0));
SetBkColor((HDC)wParam, RGB(229,255,229));
PatBlt((HDC)wParam,0,0,1,50,BLACKNESS); //x,y,width,height
PatBlt((HDC)wParam,269/2-1,0,1,50,BLACKNESS);
PatBlt((HDC)wParam,0,49,269/2,1,BLACKNESS);
PatBlt((HDC)wParam,0,0,269/2,1,BLACKNESS);
static HBRUSH handleToButtonBrush = CreateSolidBrush(RGB(229,255,229));
return (INT_PTR)handleToButtonBrush;
"Font" is an object I created (I wrapped HFONT handle and CreateFont function with class etc. getWindowHandle() basically returns HFONT ).
the button renders nicely , yet pressing on it make the text-background turn white.
I search the net for a reason and a solution yet I didn't find a concrete one.
thanks in advanced!

You need to call those lines before the actual text drawing occurs
SetTextColor((HDC)wParam, RGB(0,0,0));
SetBkColor((HDC)wParam, RGB(229,255,229));
TextOut((HDC)wParam,30,15,buttonText,textLength);

Related

Button TABSTOP in ownerdraw not working

I created a custom button class CMyButton inherited from CButton, then I am using the DrawItem to customize the button.
Using the custtom button, I created 3button on dialog.
The issue is that the TAB key for the button is not working. If I remove drawitem then there is no issue. Can anyone please help on this?
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;
UINT state = lpDrawItemStruct->itemState;
pDC->DrawFrameControl(rect, DFC_BUTTON , DFCS_BUTTONPUSH | DFCS );
pDC->FillSolidRect(rect, RGB(24, 72, 76));
pDC->SetTextColor(RGB(255, 255, 255));
CString strText;
GetWindowText(strText);
pDC->DrawText(strText,rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
I doubt it. If you make a button owner draw, then you are responsible for drawing it all the time. This includes the focused state, etc. See the documentation for DRAWITEMSTRUCT.itemstate.
https://msdn.microsoft.com/en-us/library/windows/desktop/bb775802%28v=vs.85%29.aspx
The focus rectangle is automatically rendered for standard controls on a dialog. If you subscribe to owner-drawing, responsibility to render visual cues is shifted to the custom implementation. While TABbing still works, keyboard focus remains invisible unless the implementation explicitly accounts for it.
You can use the DRAWITEMSTRUCT passed to your DrawItem method to query the item's state. If itemState contains the ODS_FOCUS flag, the control being rendered has the keyboard focus, and should produce the desired visual cue.
As a simple illustration, replace your call to FillSolidRect with the following code:
if ( state & ODS_FOCUS )
// Control has keyboard focus -> render it green
pDC->FillSolidRect( rect, RGB( 0, 255, 0 ) );
else
// Control doesn't have keyboard focus -> render it red
pDC->FillSolidRect( rect, RGB( 255, 0, 0 ) );
This allows you to see, that the TAB key does work as expected: The button control with keyboard focus is rendered green, whereas all other buttons are red.
If you are looking for a more standard appearance you can call CDC::DrawFocusRect (or DrawFocusRect) instead.

MFC tooltips only show up on special occasions

I have been tasked with assigning tooltips to each item in a configuration menu. I have completed "adding" the tooltip to each control on the page, but it seems sometimes the tooltip shows up and sometimes it does not, depending on the position of the control on the screen.
To tooltip-erize the pages I first
EnableToolTips(TRUE);
In each CPropertyPage's OnInitDialog method.
I then add the notification map
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText)
With the function OnToolTipText looking as such
BOOL CCfgPrefPage::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID = pNMHDR->idFrom;
if (pTTT->uFlags & TTF_IDISHWND)
{
nID = ::GetDlgCtrlID((HWND)nID);
if(nID)
{
if( nID == GetDlgItem(IDC_PICKDIST_EDIT)->GetDlgCtrlID())
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
else if( nID == GetDlgItem(IDC_ENDPTTOL_EDIT)->GetDlgCtrlID())
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
pTTT->lpszText = pTTT->szText; // Sanity Check
pTTT->hinst = AfxGetResourceHandle(); // Don't think this is needed at all
return TRUE;
}
}
return FALSE;
}
It seems for some of my controls the tool tip will not show up. For most of the check box controls the tool tip displays, but for a few they just do not show. There are no other controls covering them up, they are not disabled.
Another thing, if I use the non-standard cursor windows repeatedly flashes the tool tip, so much so it is unreadable in some cases. How can I fix this? This is not a problem on CEdit controls, so why is it a problem elsewhere?
EDIT: Update, the controls that have been on the pages for years seem to show tool tips. Any control that I try to add now/today will not show tool tips at all. No matter the position, control type, settings, I cannot get a single tool tip to show on a newly inserted control.
If you do not want to use helper class I have proposed then fix the problems in your code.
First, use ON_NOTIFY_EX_RANGE macro when mapping the even handler, like this (this will cover all IDs):
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
Next, you need to fix your function. I see a few problems here. First, when testing for TTF_IDISHWND flag you only need to re-initalise the nID. You do not need to apply this to the whole function. Second, after all manipulations, your nID will be the actual dialog ID. There is no need to GetDlgItem() function
BOOL CCfgPrefPage::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID = pNMHDR->idFrom;
if (pTTT->uFlags & TTF_IDISHWND)
{
nID = ::GetDlgCtrlID((HWND)nID);
}
if(nID)
{
if( nID == IDC_PICKDIST_EDIT)
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
else if( nID == IDC_ENDPTTOL_EDIT)
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
//pTTT->lpszText = pTTT->szText; // Sanity Check
*pResult = 0;
return TRUE;
}
return FALSE;
}
Working with a toolbar which repeats some menu items from menus of an older MFC application, I have worked on this issue of tool tips as well as (1) modifying the toolbar bit map to include additional icons and (2) providing user feedback on current application state. My problem is that I have to do most of this by hand rather than using the various wizards and tools.
What I have done is to (1) add new members to the CView derived class to handle additional messages, (2) modified the toolbar bit map to add in the additional icons using both MS Paint and the Resource Editor, and (3) added new event ids and event handlers to the message map for the CView derived class.
One problem I ran into with the toolbar bitmap change was that since I was inserting an icon, I had to shift an existing icon in the bitmap to the right. My first attempt at this resulted in the shifted icon showing as a blank on the application toolbar. Then I realized that I needed to add a bit more to the length of the toolbar bitmap. After adding a couple more columns to the last icon in the toolbar bitmap to make it a standard width in pixels, the icon displayed properly.
For tooltips I added the following to the message map:
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText)
I then added the following method to my class to handle the notifications for my menu items. As a side note, it appears that OnToolTipText() is the standard method used in CFrameWnd class and CMDIChildWnd class however CView derives from CWnd as does CFrameWnd so I doubt it makes a difference as to what the method is named.
inline BOOL CPCSampleView::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
static wchar_t toolTextToggleExportSylk [64] = L"Toggle SYLK export.";
static wchar_t toolTextClearWindow [64] = L"Clear the log displayed.";
static wchar_t toolTextConnectLan [64] = L"Log on the POS terminal through the LAN.";
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
switch (pNMHDR->idFrom) {
case ID_TOGGLE_SYLK_EXPORT:
pTTT->lpszText = toolTextToggleExportSylk;
return TRUE;
case ID_WINDOW_CLEAR:
pTTT->lpszText = toolTextClearWindow;
return TRUE;
case ID_CONNECT_LAN_ON:
pTTT->lpszText = toolTextConnectLan;
return TRUE;
}
// if we do not handle the message then return FALSE to let someone else do it.
return FALSE;
}
For the user feedback on a menu item which toggles a file export when doing reports I provided the following changes to the message map and then implemented the necessary methods. There are two types of messages involved so I had to add two methods and two new message map entries:
// New message map entries to handle the menu item selection event
// and to update the menu item and the toolbar icon with state changes
ON_COMMAND(ID_TOGGLE_SYLK_EXPORT, OnToggleExportSylk)
ON_UPDATE_COMMAND_UI(ID_TOGGLE_SYLK_EXPORT, OnUpdateToggleExportSylk)
// New methods added to the CView derived class
// handle the menu selection event generated by either selecting the menu item
// from the menu or by clicking on the icon in the toolbar.
void CPCSampleView::OnToggleExportSylk()
{
// Exclusive Or to toggle the indicator bit from 0 to 1 and 1 to 0.
GetDocument()->ulReportOptionsMap ^= CPCSampleDoc::ulReportOptionsExportSylk;
}
// handle the request from the MFC framework to update the displayed state this
// not only does a check mark against the menu item it also causes the toolbar
// icon to appear depressed if click is set or non-depressed if click is not set
inline void CPCSampleView::OnUpdateToggleExportSylk (CCmdUI* pCmdUI)
{
if (GetDocument()->ulReportOptionsMap & CPCSampleDoc::ulReportOptionsExportSylk)
{
// SYLK export is turned on so indicate status to the user. This will
// put a check mark beside the menu item and show the toolbar button depressed
pCmdUI->SetCheck (1);
}
else
{
// SYLK export is turned off so indicate status to the user. This will
// remove the check mark beside the menu item and show the toolbar button as raised.
pCmdUI->SetCheck (0);
}
}
The resource file changes were needed to provide a new button for the toggle action as well as to add a new menu item for the toggle action. I am using the same resource id for several different things since these are all separate. So the id for the resource string is the same as for the menu item and is same for the toolbar button so as to simplify my life and make it easy to find all the particular bits and pieces.
The toolbar resource file definition looks like:
IDR_MAINFRAME TOOLBAR 16, 15
BEGIN
BUTTON ID_CONNECT_LAN_ON
SEPARATOR
BUTTON ID_WINDOW_CLEAR
SEPARATOR
BUTTON ID_TOGGLE_SYLK_EXPORT
SEPARATOR
BUTTON ID_APP_ABOUT
END
And the specific part of the menu, which uses the same resource id for the toggle event id looks like:
MENUITEM "Export to SYLK file", ID_TOGGLE_SYLK_EXPORT
Then to provide the status bar text which shows up with a mouse over there is a string table addition:
ID_TOGGLE_SYLK_EXPORT "Toggle export of SYLK format report files for spreadsheets."
The lpszText member of the struct is describe in the MSDN documentation for the TOOLINFO struct as:
Pointer to the buffer that contains the text for the tool, or
identifier of the string resource that contains the text. This member
is sometimes used to return values. If you need to examine the
returned value, must point to a valid buffer of sufficient size.
Otherwise, it can be set to NULL. If lpszText is set to
LPSTR_TEXTCALLBACK, the control sends the TTN_GETDISPINFO notification
code to the owner window to retrieve the text.
Reviewing the existing answer to this question, I wondered about the if statement check for the TTF_IDISHWND flag. The MSDN documentation for the TOOLINFO struct has this to say:
Indicates that the uId member is the window handle to the tool. If
this flag is not set, uId is the tool's identifier.

Change static background in tab color c++

I have create tab
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = (DWORD)ICC_TAB_CLASSES;
InitCommonControlsEx(&icc);
icc.dwICC = (DWORD)ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icc);
hwndTab = CreateWindow(WC_TABCONTROL,L"",WS_CHILD|WS_VISIBLE|WS_DLGFRAME|WS_CLIPSIBLINGS
,10,10,780,271,hwnd,(HMENU)3,hInstance,NULL);
TCITEM tcitem; tcitem.mask = TCIF_TEXT;
tcitem.pszText = L"Tab1";
TabCtrl_InsertItem(hwndTab,0,&tcitem);
and put a static control into the tab
CreateWindow(L"STATIC",L"Static control 1",
WS_CHILD|WS_VISIBLE,50,30,65,24,hwndTab,(HMENU)NULL,hInstance,NULL);
But the Static control 1 have the grey background. How can I give it a color.
Thanks
Because you've made the static control a child of the tab it will be sending WM_CTLCOLORSTATIC messages to the tab control. If you sub-class the tab control you can catch this message and modify its colours. Note however that with visual styles enabled the tab control isn't a flat single colour - it's more of a gradient, so even returning a matching solid colour won't necessarily look that great.
Tab controls are not meant to be parents. For each tab page, you should create a new modeless dialog as a sibling to the tab and place your static control in it. If you obey the following rules:
reference Common Controls v6 in your manifest
call InitCommonControlsEx() on startup
no WS_CLIPCHILDREN in your main window
no handling of WM_ERASEBACKGROUND
call EnableThemeDialogTexture() in the WM_INITDIALOG handler of the modeless dialog
call SetWindowPos(tab, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE) after creating the tab page (or it will be on the wrong end of the Z order)
… then your static control will be drawn with the correct color gradient, as will all other controls (checkboxes, sliders, …) in the modeless dialog, on all Windows version from XP to 10.

Custom control drawing - focus state

I've created two instances of Fred Acker's CHoverButtonEx class with a slight modification to include a disabled state.
These buttons exist on modeless dialog which contains the following properties:
IDD_MY_DIALOG DIALOGEX 0, 0, 162, 27
STYLE DS_SETFONT | WS_POPUP
EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW
FONT 9, "Arial", 400, 0, 0x0
BEGIN
CONTROL 146,IDC_STATIC_BKGND,"Static",SS_BITMAP,0,0,162,27
LTEXT "",IDC_STATIC_1,6,4,101,9,SS_WORDELLIPSIS
LTEXT "",IDC_STATIC_2,6,15,101,9
CONTROL "",IDC_BUTTON_1,"Button",BS_OWNERDRAW | WS_TABSTOP,108,4,24,19
CONTROL "",IDC_BUTTON_2,"Button",BS_OWNERDRAW | WS_TABSTOP,134,4,24,19
END
Everything is working well with the buttons except that now I need to implement a focus state but the behavior is strange and unexpected.
In my DrawItem message handler, I have the following code which functions pretty much exactly the same as the original minus some stuff I cleaned out which wasn't needed:
void CHoverButtonEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// Do other stuff above and now find the state and draw the bitmap
if(lpDrawItemStruct->itemState & ODS_SELECTED)
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,m_ButtonSize.cx,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
else
{
if(m_bHover)
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx*2,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,m_ButtonSize.cx*2,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
else
{
if (IsWindowEnabled())
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,0,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,0,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
else
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx*3,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,m_ButtonSize.cx*3,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
}
}
if (lpDrawItemStruct->itemAction & ODA_FOCUS)
{
RECT rcFocus;
int iChange = 3;
rcFocus.top = lpDrawItemStruct->rcItem.top + iChange;
rcFocus.left = lpDrawItemStruct->rcItem.left + iChange;
rcFocus.right = lpDrawItemStruct->rcItem.right - iChange;
rcFocus.bottom = lpDrawItemStruct->rcItem.bottom - iChange;
pMemDC->DrawFocusRect(&rcFocus);
}
// clean up
pMemDC -> SelectObject(pOldBitmap);
delete pMemDC;
}
What is occurring is that when the dialog is the active window and I press tab once, the focus box jumps to the second button, even though I can confirm through the button's click handler that the first button has the real focus. Then when I press tab again the focus box jumps to include both buttons. Then another tab press moves the focus box to the other button and finally another tab press removes the focus box entirely. This sequence keeps occurring. Even holding Shift-Tab won't affect it.
I sniffed out the windows messages using spy++ and it looks pretty normal. I get a WM_DRAWITEM message for both button controls and they are successfully handled.
I'll mention one last thing; in my dialog code, when I'm initializing the buttons, I'm forced to place the buttons in the bottom of the z-order or else the IDC_STATIC_BKGND would draw over the buttons. This didn't seem normal to me because they should already be at the bottom of the z-order. (Just adding it in case it's a part of the cause to my problem).
m_button1.SetHorizontal(true);
m_button1.SetMoveable(FALSE);
m_button1.LoadBitmap(IDB_BUTTON_1);
m_button1.SetToolTipText(_T("Some Text1"));
// Draws the button after the background is drawn
m_button1.SetWindowPos(&CWnd::wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
m_button2.SetHorizontal(true);
m_button2.SetMoveable(FALSE);
m_button2.LoadBitmap(IDB_BUTTON_2);
m_button2.SetToolTipText(_T("Some Text2"));
// Draws the button after the background is drawn
m_button2.SetWindowPos(&CWnd::wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
Does anyone know how to correctly add a focus box for my situation?
Thanks.
Update:
After trying BrendanMcK's suggestion and not resolving the issue, I dug some more in the captured messages in spy++ and noticed something that seems like odd behavior. The following messages represent a single tab press in the dialog.
<00283> 00870794 R WM_CTLCOLORBTN hBrush:01900015
<00284> 00870794 S WM_DRAWITEM idCtl:112 lpdis:002AEF2C
<00285> 00870794 R WM_DRAWITEM fProcessed:True
<00286> 00870794 S DM_GETDEFID
<00287> 00870794 R DM_GETDEFID wHasDef:DC_HASDEFID wDefID:0001
<00288> 00870794 S WM_CTLCOLORBTN hdcButton:110114A7 hwndButton:01090502
<00289> 00870794 R WM_CTLCOLORBTN hBrush:01900015
<00290> 00870794 S WM_DRAWITEM idCtl:113 lpdis:002AF2A0
<00291> 00870794 R WM_DRAWITEM fProcessed:True
As evident there are two separate WM_DRAWITEM messages delivered. The details for each message is:
Message #284: action= ODA_FOCUS, state= 0x0110 (ODS_FOCUS = 0x0010)
Message #290: action= ODA_DRAWENTIRE, state= ODS_NOACCEL
I would have expected that in message #290, the action would again be ODA_FOCUS to allow the other button to "un-draw" the focus box.
I'm not sure why I'm even receiving an ODS_NOACCEL state as I'm using Win7. Is there something I've forgot to disable?
From MSDN on DRAWITEMSTATE:
ODA_FOCUS
The control has lost or gained the keyboard focus. The itemState member should be checked to determine whether the control has the focus.
Because you're redrawing the control, you should only be drawing the focus rect if the itemState indicates that the control has focus. Instead, you're drawing it in all cases, regardles of whether the control gains or loses focus. Add a check to see if itemState & ODS_FOCUS and you should be good.

Tool tips for custom made control using CToolTipCtrl ? (MFC)

I made a custom control derived from CWnd (a line chart) and I'm wondering if I can use CToolTipCtrl for displaying tool tips for points on the graph. If yes, how could I do that?
Btw, when I move my mouse over the point, the rectangle containg string with information about values of the point, should pop up.
Yes, this works, actually I do this exact same thing, also in a line graph chart, however there are a few drawbacks/remarks. The message handling is a bit wonky, with some messages not being send according to the documentation, and some workarounds being necessary to keep the control self-contained (not requiring help from the parent to reflect notifications).
What you do is declare a variable in your CWnd-derived class
CToolTipCtrl m_ToolTipCtrl;
CString m_ToolTipContent;
Then do this on OnCreate:
m_ToolTipCtrl.Create(this, TTS_ALWAYSTIP);
m_ToolTipCtrl.Activate(TRUE);
Optionally, you can also set the delay time:
m_ToolTipCtrl.SetDelayTime(TTDT_AUTOPOP, -1);
m_ToolTipCtrl.SetDelayTime(TTDT_INITIAL, 0);
m_ToolTipCtrl.SetDelayTime(TTDT_RESHOW, 0);
When you want to show your tooltip (presumably in OnMouseMove()), use
m_ToolTipCtrl.Pop();
BUT this only works in UNICODE builds. So if you're still on MBCS (like I am), you can only show the tooltip after a certain delay.
Use this to set your tooltip text (also in OnMouseMove):
// Not using CToolTipCtrl::AddTool() because
// it redirects the messages to the parent
TOOLINFO ti = {0};
ti.cbSize = sizeof(TOOLINFO);
ti.uFlags = TTF_IDISHWND; // Indicate that uId is handle to a control
ti.uId = (UINT_PTR)m_hWnd; // Handle to the control
ti.hwnd = m_hWnd; // Handle to window
// to receive the tooltip-messages
ti.hinst = ::AfxGetInstanceHandle();
ti.lpszText = LPSTR_TEXTCALLBACK;
ti.rect = <rectangle where, when the mouse is over it, the tooltip should be shown>;
m_ToolTipCtrl.SendMessage(TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
m_ToolTipCtrl.Activate(TRUE);
m_ToolTipContent = "my tooltip content";
Furthermore, you need to handle TTNNeedText:
// The build-agnostic one doesn't work for some reason.
ON_NOTIFY_EX(TTN_NEEDTEXTA, 0, OnTTNNeedText)
ON_NOTIFY_EX(TTN_NEEDTEXTW, 0, OnTTNNeedText)
BOOL GraphCtrlOnTTNNeedText(UINT id, NMHDR* pTTTStruct, LRESULT* pResult)
{
TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pTTTStruct;
//pTTT->lpszText = "some test text";
//pTTT->lpszText = m_ToolTipContent;
strncpy_s(pTTT->lpszText, 80, m_ToolTipContent, _TRUNCATE);
return TRUE;
}
You'll have to modify this a bit, and read the documentation of the functions and messages, to get this to work in your project but yes it can be done.
For those that may still be looking for an answer to this as I was. (I couldn't get the one above to work - Things in MFC may have changed.)
All code is contained within the custom control class.
In your class definition add:
CToolTipCtrl ToolTip;
In PreSubclassWindow() add:
#define TOOLTIP_ID 1
ToolTip.Create(this, TTS_ALWAYSTIP );
CRect rc;
GetClientRect(rc);
ToolTip.AddTool(this, "Tool tip text", rc, TOOLTIP_ID);
In PreTranslateMessage() add:
ToolTip.RelayEvent(msg);
Whenever your tool tip text changes add:
ToolTip.UpdateTipText("New Tip Text", this, TOOLTIP_ID);