RTF-Based Tooltips

This code demonstrates using rich text in tooltips, as seen in Query Analyser utility of MS SQL Server 7.

It is more like a proof-of-concept then a finished code, and is heavily based on two classes from CodeGuru : TFXDataTip by S. Wilson and CAutoRichEditCtrl by Jeremy Iverson

First class was modifyed to hold a hidden AutoRichEdit control as a static member and use it for rendering the RTF text to the window. Function of AutoRichEdit are used to load text into the control.

Most of the magic behind the code is in the OnPaint handler of the tooltip window. The idea is to utilise RichEdit printing functions to copy the picture to screen DC instead of printer.

void TFXDataTip::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

    CRect rect;
    GetClientRect(&rect);

    dc.SetBkColor(::GetSysColor(COLOR_INFOBK));
    //dc.SetTextColor(::GetSysColor(COLOR_INFOTEXT));
	//dc.SetMapMode(MM_TEXT);

	if(_richCtrl)
	{
		_richCtrl->SetRTF(m_tip);

		FORMATRANGE fr;
		fr.hdc = dc;
		fr.hdcTarget = dc;
		fr.rc = CRect((rect.Width( ) / 2), (_border / 2) ,m_size.cx*15, m_size.cy*15);
		fr.rcPage = CRect(0,0,0,0);
		fr.chrg.cpMin = 0;
		fr.chrg.cpMax = -1;
		
		_richCtrl->FormatRange( &fr );
	}

}

Using it from the dialog is also rather simple :

void CRich1Dlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	CWnd *pwnd = ChildWindowFromPoint(point);
	if(pwnd)
	{
		int nID = pwnd->GetDlgCtrlID();

		switch(nID)
		{
			case IDC_RICH_PLACEHOLDER:
				m_datatip.Set(point, m_tip1);
				break;
			case IDC_TEXT:
				m_datatip.Set(point, m_tip2);
				break;
			case IDC_IMAGE_PLACEHOLDER:
				m_datatip.Set(point, m_tip3);
				break;
			default:
				break;
		}
	}
	CDialog::OnMouseMove(nFlags, point);
}


Issues and possible enhancements :

  • More 'standard' tooltip behaviour, such as ability to assign text to control IDs etc.
  • Some framework for dynamically producing RTF based on a template could be nice
  • Images included in RTF files doesn't show up.
  • Any explanation for '15' constant in rc member of a FORMATRANGE struct ? What units are used there ?
  • Possibly cache rendered text to avoid having to load it into RichEdit control every time.

    Download demo project - 10 KB

    Download source - 26 KB



  • Comments

    • Picture Not Showing

      Posted by Legacy on 01/23/2004 12:00am

      Originally posted by: gush

      why is the picture not showing in the tooltip?

      Reply
    • How to do this with a Html Edit Control?

      Posted by Legacy on 12/20/2003 12:00am

      Originally posted by: Appstmd

      Hi!

      Is it possible to do the same thing with the Microsoft Html Edit ActiveX Control?

      What are the equivalent printing functions for this control?

      Thks in advance.

      Reply
    • How to feed text to Richedit control

      Posted by Legacy on 02/08/2003 12:00am

      Originally posted by: Vikas

      I have a string which has some rtf text to be printed. I have created a richedit control and then I feed the string to the control using WM_SETTEXT message. The problem that I am facing is that Richedit control only consumes the text worth of one paragraph instead of the whole text. How can I make this text consume the whole text?

      Reply
    • I know why 15, but 15 is uncertain!

      Posted by Legacy on 10/13/2001 12:00am

      Originally posted by: Edwin Zhang

      MSDN says very clearly that:
      for rc and rcPage in FORMATRANGE, their unit should be measured in twips, and we all know 1 inch is 1440 twips,
      so you can write as:

      ...
      long lWidth = ::MulDiv(rect.Width(), 1440, dc.GetDeviceCaps(LOGPIXELSX));
      long lHeight = ::MulDiv(rect.Height(), 1440, dc.GetDeviceCaps(LOGPIXELSY));

      CRect rcPage(0, 0, lWidth, lHeight);
      fr.rc = rcPage;
      fr.rcPage = rcPage;
      ...

      For dc.GetDeviceCaps(LOGPIXELSX) usually equals 96, so 1440 / 96 = 15. but you know you can not use 15 for safety reason.

      Reply
    • RE: concerning the '15' constant

      Posted by Legacy on 07/17/2001 12:00am

      Originally posted by: JMB

      concerning the '15' constant

      ...
      I have no idea about your CRTfxxx project,

      but 15 sounds to me as the VB TxipPerPixels? constants
      (? being X or Y, in a std 'small fonts' environment)

      Please refer to MSDN/VB docs for the definition of the TWIP as a device-independent[???] unit )

      Maybe this might be a hint - no other ambition implied

      Rgds

      --JMB


      Reply
    • Auto complete prompting

      Posted by Legacy on 05/21/2001 12:00am

      Originally posted by: Shrinivas

      Hi,

      I'm trying to do the Atocomplete prompting in my MDI application with CRichEditView.
      Atocomplete prompting - In MS Word if you type Janu, a yellow tooltip kind of box pops up above the current caret position with word "January" in it and now if you hit Enter key half typed Janu gets replaced by word January.
      I want to do the similar kind of functionality in my application for some selected words. Is it anything to do with the tool tips?

      Any pointer to this is highly appreciated.

      thanks,
      Shrini

      Reply
    • Some little modifications

      Posted by Legacy on 07/24/1999 12:00am

      Originally posted by: FRED

      This control like a lot we can find on this site is great. But, poor
      
      programer we can't thinks about all! Me the first one!!
      I've tryed successfully to implement this control on my code.
      But, i've some problem with the init size of 0. The result was a little
      and large tooltip.

      This is because the program calculate the size of the window like this

      void TFXDataTip::Display( )
      {
      ...
      // OLD CODE
      if(m_size == CSize(0,0))
      {
      dc.SelectObject(&_font);
      m_size = dc.GetTextExtent(m_tip);
      }

      now after this code :
      if (wndRect.right > dc.GetDeviceCaps(HORZRES)) {
      wndRect.OffsetRect(-wndRect.Width(), 0);
      } else {
      wndRect.OffsetRect(m_offset);
      }

      -->REPLACE IT bY ADDING this one:
      int cx = wndRect.Width(), cy = wndRect.Height();
      if(_richCtrl)
      {
      _richCtrl->SetRTF(m_tip);

      CRect rect;
      GetClientRect(&rect);

      FORMATRANGE fr;
      fr.hdc = dc;
      fr.hdcTarget = dc;
      fr.rc = CRect((rect.Width( ) / 2), (_border / 2) ,m_size.cx*15, m_size.cy*15);
      fr.rcPage = CRect(0,0,0,0);
      fr.chrg.cpMin = 0;
      fr.chrg.cpMax = -1;

      // BEGIN UPDATE
      _richCtrl->FormatRange(&fr, FALSE); // Specify FALSE to not redraw

      // Now resize the window
      cx = ((fr.rc.right-fr.rc.left)/15)+15; // We add 15 to not round inf
      cy = ((fr.rc.bottom - fr.rc.top)/15)+15;
      }

      THEN Modify the SetWindowPos FUNCTion

      // update window position and display
      SetWindowPos(&wndTop,
      wndRect.left,
      wndRect.top,
      cx, // UPDATE replace Width
      cy, // UPDATE replace
      SWP_SHOWWINDOW | SWP_NOACTIVATE);

      IN CONCLUSION :
      in the OnPaint Function remove the line who make:
      _richCtrl->SetRTF(m_tip);
      now there is no reason to let it here because we have assigned this value
      in the Display Function

      To use this control correctly you must have in mind that your choice must be the width
      or the height not the both. In this sample my choice was the width.

      Thanks,
      FRED

      Reply
    • Rect coordinates in the FORMATRANGE struct

      Posted by Legacy on 04/23/1999 12:00am

      Originally posted by: Bartosz Bien

      As VC6 MSDN library says, rectangles of rendering area and entire "page" area are in twips (which is 1/1440 of an inch). I'm not sure if the '15' is universal for all devices/devmodes.

      Reply
    Leave a Comment
    • Your email address will not be published. All fields are required.

    Top White Papers and Webcasts

    • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

    • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

    Most Popular Programming Stories

    More for Developers

    RSS Feeds