Solved

Tool tip for subclassed CButton

Posted on 2003-10-23
11
1,853 Views
Last Modified: 2013-11-20
Hi there,

I have subclassed CButton and want to have a tooltip on it.

I have previously got tooltips working for several controls in a CWnd, controlled by the CWnd, but I want this CButton to have all the code for its own tooltips, not its parent window.  I have tried transplanting the code that worked for the CWnd, but using this instead of the controls in AddTool, ie:

in MyButton::OnCreate:
      EnableToolTips(TRUE);
      m_tooltip.Create(this, TTS_NOPREFIX| TTS_ALWAYSTIP);
      m_tooltip.Activate(TRUE);
      m_tooltip.AddTool(this, _T("text"));

I've overloaded PreTranslateMessage to have m_tooltip.RelayEvent(pMsg);

This isn't working.  I don't know whether I'm going about this right but making a mistake somewhere, or whether I need a completely different approach. What should I be doing?

Thank you





0
Comment
Question by:wilsonian
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
11 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 9611078
One normally handles the tooltips in the parent.  There is some good code here:

     http:/MFC/Q_10037333.html

And it is covered nicely in MDSN.

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 9611092
It is also possible to do it in the button itself, but the technique description differs depending upon how you are creating the button.  If you place a breakpoint in your OnCreate fn, does it get executed?

-- Dan
0
 

Author Comment

by:wilsonian
ID: 9611165
Heh, you'd think I'd check something like that.  No, OnCreate is not getting called. What function should the tooltip code live in, or do I have to write one that I call explicitly?

The buttons are member variables of a couple of different types of CWnd (CDialog and CPropertyPage at the moment)

I don't want to handle the tooltips in the parent because the buttons appear in different contexts and it would save doing it more than once, also the tool tips really are part of the functionality of the button itself (they're not serving the normal purpose of tool tips).
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 49

Accepted Solution

by:
DanRollins earned 125 total points
ID: 9611429
Heres' the header:
#pragma once

/////////////////////////////////////////////////////////////////////////////
// CMyButton window

class CMyButton : public CButton
{
// Construction
public:
      CMyButton();
      virtual ~CMyButton();

      BOOL PreTranslateMessage(MSG* pMsg);

      CString m_sTipText;
      void SetTipText( LPCSTR sz ) { m_sTipText= sz; };

      CToolTipCtrl m_tooltip;

      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CMyButton)
      protected:
      virtual void PreSubclassWindow();
      //}}AFX_VIRTUAL


      // Generated message map functions
protected:
      //{{AFX_MSG(CMyButton)
      //}}AFX_MSG

      DECLARE_MESSAGE_MAP()
};
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
here's the CPP file:

// MyButton.cpp : implementation file
//
#include "stdafx.h"
#include "MyButton.h"

CMyButton::CMyButton() { }
CMyButton::~CMyButton() { }

BEGIN_MESSAGE_MAP(CMyButton, CButton)
      //{{AFX_MSG_MAP(CMyButton)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CMyButton::PreSubclassWindow()
{
      CButton::PreSubclassWindow();
      if (m_sTipText > "" ) {
            EnableToolTips( TRUE );
            m_tooltip.Create(this, TTS_NOPREFIX| TTS_ALWAYSTIP );
            m_tooltip.AddTool(this, (LPCSTR)m_sTipText );
            m_tooltip.Activate(TRUE);
      }
}
//-------------------------------------------------------------
BOOL CMyButton::PreTranslateMessage(MSG* pMsg)
{
      switch(pMsg->message) {
            case WM_LBUTTONDOWN:
            case WM_LBUTTONUP:
            case WM_MOUSEMOVE:
                  if ( m_tooltip.m_hWnd ) {
                        m_tooltip.RelayEvent(pMsg);
                  }
            break;
      }
      return CButton::PreTranslateMessage(pMsg);
}
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
here's an example impementation (partial):

void CD18Dlg::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CD18Dlg)
      DDX_Control(pDX, IDPB_MyButton, m_ctlMyButton);
      //}}AFX_DATA_MAP
}

.... etc...

BOOL CD18Dlg::OnInitDialog()
{
      m_ctlMyButton.SetTipText("this is the tip text");

      CDialog::OnInitDialog();

.... etc...

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
You could use other method to set the tip text... my implementation is not dynamic, but this should get you going.

It seems to boil down to
   provide a CToolTip member for the CButton-derived object
   Create the tooltip in PreSubclassWindow
   Handle PreTranslateMessage and use .RelayEvent on certain msgs

-- Dan
0
 

Author Comment

by:wilsonian
ID: 9611761
I now get an assert failure in the following line:

      m_tooltip.Create(this, TTS_NOPREFIX| TTS_ALWAYSTIP);

in AfxHookWindowCreate.  It's on line 627 and says:

ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);

Any idea what's going on here?
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 9611798
Myabe it's something you are doing in your OnCreate fn.  I did not use one.

-- Dan
0
 

Author Comment

by:wilsonian
ID: 9611853
I deleted OnCreate when I put the PreSubclassWindow function in, so that can't be it.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 9611938
I'm pretty certain that that ASSERT indicates that some window is being created while another window is still in the process of being created.  Does that narrow it down?  

I assure you that the code I posted does work in a minimal AppWizard-generated Dialog-based program.

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 9618294
Be sure to call
   m_tooltip.Create( this, ...
when the 'this' pointer identifies a CWnd-derived object that has already been created (that is, its m_hWnd member is valid).

-- Dan
0
 

Author Comment

by:wilsonian
ID: 9636964
Sorry, my email was playing up and I didn't get your message.

I'll check it out on Friday when I'm next at work.
0
 

Author Comment

by:wilsonian
ID: 9661533
It's still not working, but I'm sure it's some weird unrelated thing I'm doing.  I'm awarding you the points.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

735 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question