Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / MFC

How to Use CMFCToolTipCtrl Tooltips in a View for Dynamic Context Sensitive Tips

Rate me:
Please Sign up or sign in to vote.
4.14/5 (7 votes)
9 Jun 2011CPOL2 min read 44.4K   1.9K   20   18
How to use CMFCToolTipCtrl tooltips in a view for dynamic context sensitive tips

Introduction

CMFCToolTipCtrl provides a very nice looking, multi-line tooltip for use on controls such as buttons, sliders, etc.

I also wanted to use the same class to display dynamic tooltips based on the location of the mouse in the view area (CSrollView class in my case).

This article will describe a very simple way to override the OnDrawLabel method to get the tooltip to draw any text you like at run time.

Background

I have used a tooltip class from this site before but my solution is very simple and uses the nicer looking CMFCToolTipCtrl class.

This code is based on the DlgToolTips example that comes with VS 2010.

Using the Code

Here is the class header CCustomToolTipCtrl.h.

The key thing is the override of OnDrawLabel.

C++
//
#pragma once

/////////////////////////////////////////////////////////////////////////////
// CCustomToolTipCtrl window

class CCustomToolTipCtrl : public CMFCToolTipCtrl
{
// Construction
public:
	CCustomToolTipCtrl();

// Attributes
public:
	int	m_nCurrID;

// Operations
public:

// Overrides

// Implementation
public:
	virtual ~CCustomToolTipCtrl();

protected:
	CSize OnDrawLabel(CDC* pDC,CRect rect,BOOL bCalcOnly);
};

Here is the class declaration CCustomToolTipCtrl.cpp.

Most of the code is taken directly from the original implementation of CMFCToolTipCtrl::OnDrawLabel in MFC. The interesting part is how I produce the two strings, labelText and descriptionText.

C++
//
#include "stdafx.h"
#include "CustomToolTipCtrl.h"

/////////////////////////////////////////////////////////////////////////////
// CCustomToolTipCtrl

CCustomToolTipCtrl::CCustomToolTipCtrl()
{
	m_nCurrID = 0;
}

CCustomToolTipCtrl::~CCustomToolTipCtrl()
{
}

/////////////////////////////////////////////////////////////////////////////
// CCustomToolTipCtrl message handlers

CSize CCustomToolTipCtrl::OnDrawLabel(CDC* pDC, CRect rect, BOOL bCalcOnly)
{
//	TRACE("ENTER CCustomToolTipCtrl::OnDrawLabel bCalcOnly=%d\n", bCalcOnly);
	ASSERT_VALID(pDC);

	// my special tooltip drawing system for context sensitive tooltips 
	// in view (track)
	POINT cursor;
	GetCursorPos(&cursor);
	GetActiveView()->ScreenToClient(&cursor);
	CString labelText, descriptionText;
	GetActiveView()->GetToolTipLabelText(cursor, labelText, descriptionText);

	CSize sizeText(0, 0);

	BOOL bDrawDescr = m_Params.m_bDrawDescription && !m_strDescription.IsEmpty();

	CFont* pOldFont = (CFont*) pDC->SelectObject(m_Params.m_bBoldLabel && 
		bDrawDescr ? &afxGlobalData.fontBold : &afxGlobalData.fontTooltip);

	if (labelText.Find(_T('\n')) >= 0) // Multi-line text
	{
		UINT nFormat = DT_NOPREFIX;
		if (bCalcOnly)
		{
			nFormat |= DT_CALCRECT;
		}

		if (m_pRibbonButton != NULL)
		{
			nFormat |= DT_NOPREFIX;
		}

		int nHeight = pDC->DrawText(labelText, rect, nFormat);
		sizeText = CSize(rect.Width(), nHeight);
	}
	else
	{
		if (bCalcOnly)
		{
			sizeText = pDC->GetTextExtent(labelText);
		}
		else
		{
			UINT nFormat = DT_LEFT | DT_NOCLIP | DT_SINGLELINE;

			if (!bDrawDescr)
			{
				nFormat |= DT_VCENTER;
			}

			if (m_pRibbonButton != NULL)
			{
				nFormat |= DT_NOPREFIX;
			}

			sizeText.cy = pDC->DrawText(labelText, rect, nFormat);
			sizeText.cx = rect.Width();
		}
	}

	pDC->SelectObject(pOldFont);

	SetDescription (descriptionText);

	return sizeText;
}

The code below gets the current absolute cursor position, then converts it to a point relative to the current view.

Then GetToolTipLabelText fills in the two cstrings with text based on the location of the cursor in the view window.

C++
//
// my special tooltip drawing system for context sensitive tooltips in view (track)
POINT cursor;
GetCursorPos(&cursor);
GetActiveView()->ScreenToClient(&cursor);
CString labelText, descriptionText;
GetActiveView()->GetToolTipLabelText(cursor, labelText, descriptionText);

This line draws the text for the top part of the tooltip:

C++
//
pDC->DrawText(labelText, rect, nFormat)

This line draw the text for the bottom part of the tooltip:

C++
//
SetDescription (descriptionText);

Now, how to hook it up to your application. In the view's constructor:

C++
// Create the ToolTip control.
m_ToolTip.Create(this);
m_ToolTip.Activate(TRUE);

m_ToolTip is of type CCustomToolTipCtrl:

In the view's OnInitialUpdate:

C++
//
CMFCToolTipInfo params;
params.m_bVislManagerTheme = TRUE;
m_ToolTip.SetParams (¶ms);
m_ToolTip.AddTool (this, _T("BASE LABLE"));
m_ToolTip.SetDelayTime(3000);		// 3 seconds before tooltips pop up in view

You will need a PreTranslateMessage to force events to get routed to the tooptip class (this is the critical bit of the whole thing):

C++
//
BOOL CTabTraxView::PreTranslateMessage(MSG* pMsg)
{
   	switch (pMsg->message)
	{
	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_RBUTTONUP:
	case WM_MBUTTONUP:
	case WM_MOUSEMOVE:
		m_ToolTip.RelayEvent(pMsg);
		break;
	}

	return CScrollView::PreTranslateMessage(pMsg);
}

Finally, at the end of my view's OnMouseMove, I need to get rid of the tooltip (not sure why it doesn't do it automatically but this works).

C++
//
m_ToolTip.Pop();

And that's about it, less than 100 lines of code and it uses the built in features in MFC.

Points of Interest

I should point out that I'm not really an expert in MFC programming. I just figured this out by debugging the DlgToolTip app so I can't guarantee that this is the best or safest way to do it, but for me it seems to work fine.

History

  • 28th May, 2011: Initial version
  • 9th June, 2011: Uploaded demo project 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThanks for the demo code. Pin
drector10-Feb-12 6:34
drector10-Feb-12 6:34 
It was nice to see this example to get me started on my own similar project.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.