?
Solved

Tooltips for CListCtrl

Posted on 1998-06-09
6
Medium Priority
?
1,476 Views
Last Modified: 2013-11-20
I want to support tooltips for CListCtrl window like it is done for CTreeCtrl.
The parent window of CListCtrl is derived from CToolBar, which was created with style CBRS_TOOLTIPS.
My CListCtrl contains only labels, which I want to extend by tooltip if they are cut by the border of parent window.

My attempt to do this is based on overiding OnToolHitTest () method. Until now I got no success.
Please check code below or suggest other way of supporting tooltips for CListCtrl.

Parent C3DErrorWnd is derived from CRollUpFrame, which is derived from SECControlBar (from Stingray Objective Toolkit library), which is derived from CToolBar.
m_List is CListCtrl, which is child of C3DErrorWnd.
Note: SendMessage (TB_GETTOOLTIPS, 0, 0) for C3DErrorWnd returns NULL.
EnableToolTips (TRUE) for C3DErrorWnd does not change anything and probably should not.

int C3DErrorWnd::OnToolHitTest( CPoint point, TOOLINFO* pTI ) const
{
      // check child windows first by calling CRollUpFrame
       int nHit = CRollUpFrame::OnToolHitTest(point, pTI);
      if (nHit != -1)
            return nHit;
//      UINT  nHitFlags = 0;
      CPoint pt = point;
      ClientToScreen (&pt);
      m_List.ScreenToClient (&pt);

//      Searching for CListCtrl item that corresponds to point

//      nHit = m_List.HitTest(pt, &nHitFlags); // Does not work properly for some reason, was replaced by the following block

      int nItem = 0;
      CRect ItemRect;
      while ((nItem = m_List.GetNextItem (-1, LVNI_ALL)) != -1)
      {
            m_List.GetItemRect( nItem, &ItemRect, LVIR_LABEL);
            if (ItemRect.PtInRect (pt))
            {
                  nHit = nItem;
                  break;
            }
      }

//      Setting TOOPINFO structure

      if (nHit != -1)
      {
            CString str = m_List.GetItemText (nHit,0);
pTI->hwnd=m_hWnd;
            RECT Rect;
            m_List.GetItemRect( nHit, &Rect, LVIR_LABEL );
            pTI->rect=Rect;
            pTI->uId=(UINT)m_List.m_hWnd;
            pTI->lpszText=_tcsdup((LPCTSTR)str);
      }
      return nHit;
}

0
Comment
Question by:tflex
[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
  • 2
  • 2
  • 2
6 Comments
 
LVL 1

Accepted Solution

by:
motigust earned 800 total points
ID: 1316425
I think you went in the wrong way, I have a better approch: (Actually I'm using it).

Instead of using the TooltipCtrl and the HitTest function, Create your own Tooltip class and activate it from the ListCtrl whenever you need it.

In order to implement that:
1. Derive a tooltip window from CWnd Obeject and implement the tooltip window

2. Derive a CListCtrl class, and implement the calls to the tooltip window there.

I'm attaching here 3 files :

1. CMyToolTip.h
2. CMyToolTip.cpp
3. CMyListCtrl.cpp (I Belive you can generate the h file
yourself)

   have fun,
   Moti.


Here is the sample code :


-------------------- CMyToolTip class (H file)-----------

#if !defined(AFX_CMyTitleTip_H__01FF1483_3A6C_11D1_858F_00A0C9412964__INCLUDED_)
#define AFX_CMyTitleTip_H__01FF1483_3A6C_11D1_858F_00A0C9412964__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#define TITLETIP_CLASSNAME _T("MyTitleTip")

enum TitleTipPosition {TitleOnSpot,TitleAbove};


class CMyTitleTip : public CWnd
{
// Construction
public:
      CMyTitleTip();

// Attributes
public:

// Operations
public:

// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CMyTitleTip)
      public:
      virtual BOOL PreTranslateMessage(MSG* pMsg);
      protected:
      //}}AFX_VIRTUAL

// Implementation
public:
      virtual ~CMyTitleTip();
    void      Show( CRect rectTitle, LPCTSTR lpszTitleText,int leftoffset,int rightoffset, BOOL showAnyway=FALSE, CFont *font=NULL, TitleTipPosition pos=TitleOnSpot);
    virtual BOOL Create( CWnd *pParentWnd);


      // Generated message map functions
protected:
    CWnd *m_pParentWnd;
    CRect m_rectTitle;
      TitleTipPosition position;

      //{{AFX_MSG(CMyTitleTip)
      afx_msg void OnMouseMove(UINT nFlags, CPoint point);
      afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
      afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
      afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
      afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
      afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CMyTitleTip_H__01FF1483_3A6C_11D1_858F_00A0C9412964__INCLUDED_)



-------------------- CMyToolTip class (CPP file)-----------





#include "stdafx.h"
#include "Tip.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CMyTitleTip::CMyTitleTip()
{
        WNDCLASS wndcls;
        HINSTANCE hInst = AfxGetInstanceHandle();
        if(!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls)))
        {
                // otherwise we need to register a new class
                wndcls.style = CS_SAVEBITS | CS_DBLCLKS ;
                wndcls.lpfnWndProc = ::DefWindowProc;
                wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
                wndcls.hInstance = hInst;
                wndcls.hIcon = NULL;
                wndcls.hCursor = LoadCursor( hInst, IDC_ARROW );
                wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);
                wndcls.lpszMenuName = NULL;
                wndcls.lpszClassName = TITLETIP_CLASSNAME;
                if (!AfxRegisterClass(&wndcls))
                        AfxThrowResourceException();
        }

}

CMyTitleTip::~CMyTitleTip()
{
}


BEGIN_MESSAGE_MAP(CMyTitleTip, CWnd)
      //{{AFX_MSG_MAP(CMyTitleTip)
      ON_WM_MOUSEMOVE()
      ON_WM_LBUTTONDBLCLK()
      ON_WM_LBUTTONDOWN()
      ON_WM_LBUTTONUP()
      ON_WM_RBUTTONDOWN()
      ON_WM_RBUTTONUP()
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CMyTitleTip::PreTranslateMessage(MSG* pMsg)
{
      // TODO: Add your specialized code here and/or call the base class

        CWnd *pWnd;
        int hittest ;
        //switch( pMsg->message )
        switch(pMsg->message) {
            case WM_LBUTTONDOWN:
            case WM_LBUTTONUP:
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_MBUTTONDOWN:
                POINTS pts = MAKEPOINTS( pMsg->lParam );
                POINT  point;
                point.x = pts.x;
                point.y = pts.y;
                ClientToScreen( &point );
                pWnd = WindowFromPoint( point );
                if( pWnd == this )
                        pWnd = m_pParentWnd;

                hittest = (int)pWnd->SendMessage(WM_NCHITTEST,
                                        0,MAKELONG(point.x,point.y));


                        if (hittest == HTCLIENT) {
                        pWnd->ScreenToClient( &point );
                        pMsg->lParam = MAKELONG(point.x,point.y);
                } else {
                        switch (pMsg->message) {
                        case WM_LBUTTONDOWN:
                                pMsg->message = WM_NCLBUTTONDOWN;
                                break;
                        case WM_LBUTTONUP:
                                pMsg->message = WM_NCLBUTTONUP;
                                break;
                        case WM_RBUTTONDOWN:
                                pMsg->message = WM_NCRBUTTONDOWN;
                                break;
                        case WM_RBUTTONUP:
                                pMsg->message = WM_NCRBUTTONUP;
                                break;
                        case WM_MBUTTONDOWN:
                                pMsg->message = WM_NCMBUTTONDOWN;
                                break;
                                    
                        }
                        pMsg->wParam = hittest;
                        pMsg->lParam = MAKELONG(point.x,point.y);
                }
                ReleaseCapture();
                        ShowWindow( SW_HIDE );
                m_pParentWnd->PostMessage( pMsg->message, pMsg->wParam, pMsg->lParam );
               return TRUE;            
        case WM_KEYDOWN:
        case WM_SYSKEYDOWN:
                ReleaseCapture();
                        ShowWindow( SW_HIDE );
                m_pParentWnd->PostMessage( pMsg->message, pMsg->wParam, pMsg->lParam );
                return TRUE;
        }
        if( GetFocus() == NULL )
        {
                ReleaseCapture();
                ShowWindow( SW_HIDE );
                return TRUE;
        }

      return CWnd::PreTranslateMessage(pMsg);
}

void CMyTitleTip::OnMouseMove(UINT nFlags, CPoint point)
{
            CPoint tmp=point;
            ClientToScreen(&point);
            m_pParentWnd->ScreenToClient(&point);
        if (!m_rectTitle.PtInRect(point)) {
                  ReleaseCapture();
                  ShowWindow( SW_HIDE );

                  // Forward the message
                  m_pParentWnd->ClientToScreen( &point );
                  CWnd *pWnd = WindowFromPoint( point );
                  if ( pWnd == this )
                          pWnd = m_pParentWnd;
                  int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,
                                                0,MAKELONG(point.x,point.y));
                  if (hittest == HTCLIENT) {
                           pWnd->ScreenToClient( &point );
                           pWnd->PostMessage( WM_MOUSEMOVE, nFlags,
                                                MAKELONG(point.x,point.y) );
                  } else {
                           pWnd->PostMessage( WM_NCMOUSEMOVE, hittest,
                                                MAKELONG(point.x,point.y) );
                  }
         }
      
      CWnd::OnMouseMove(nFlags, point);
}


BOOL CMyTitleTip::Create(CWnd * pParentWnd)
{
        ASSERT_VALID(pParentWnd);

        DWORD dwStyle = WS_BORDER | WS_POPUP;
        DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
        m_pParentWnd = pParentWnd;
        return CreateEx( dwExStyle, TITLETIP_CLASSNAME, NULL, dwStyle, 0, 0, 0, 0,
                NULL, NULL, NULL );
}
void CMyTitleTip::Show( CRect rectTitle, LPCTSTR lpszTitleText,int leftoffset,
                                    int rightoffset,BOOL showAnyway,
                                    CFont *font, TitleTipPosition pos)
{

            ASSERT(leftoffset > 0);  
            ASSERT(rightoffset > 0);  
            ASSERT( ::IsWindow( m_hWnd ) );
        ASSERT( !rectTitle.IsRectEmpty() );

        // If titletip is already displayed, don't do anything.
        if( IsWindowVisible() )
                return;

        // Do not display the titletip is app does not have focus
        if( GetFocus() == NULL )
                return;
        m_rectTitle = rectTitle;
            // Determine the width of the text
        m_pParentWnd->ClientToScreen( rectTitle );

        CClientDC dc(this);
        CString strTitle(lpszTitleText);
            CFont *pFont = (font) ? font: m_pParentWnd->GetFont();         // use same font as ctrl
        CFont *pFontDC = dc.SelectObject( pFont );

        CRect rectDisplay = rectTitle;
        CSize size = dc.GetTextExtent( strTitle );
            int stringExtent=size.cx;
            stringExtent +=leftoffset+rightoffset;
            int rectW=rectTitle.Width();
            if(!showAnyway && stringExtent < rectW)
                return;
            position = pos;
            rectDisplay.right = rectDisplay.left + size.cx + leftoffset +rightoffset;
            if(pos==TitleAbove)
                  SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top-(rectDisplay.Height()),
                        rectDisplay.Width(), rectDisplay.Height(),
                                    SWP_SHOWWINDOW|SWP_NOACTIVATE );
            else if(pos==TitleOnSpot){
                  SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top,
                        rectDisplay.Width(), rectDisplay.Height(),
                      SWP_SHOWWINDOW|SWP_NOACTIVATE );
            }

        dc.SetBkMode( TRANSPARENT );
            dc.TextOut(leftoffset, 0, strTitle );
        dc.SelectObject( pFontDC );

        SetCapture();

}

void CMyTitleTip::OnLButtonDblClk(UINT nFlags, CPoint point)
{
      ReleaseCapture();
      ShowWindow( SW_HIDE );
      ClientToScreen(&point);
      m_pParentWnd->ScreenToClient(&point);
      m_pParentWnd->PostMessage(WM_LBUTTONDBLCLK,nFlags,MAKELONG(point.x,point.y));
}

void CMyTitleTip::OnLButtonDown(UINT nFlags, CPoint point)
{
      ReleaseCapture();
      ShowWindow( SW_HIDE );
      ClientToScreen(&point);
      m_pParentWnd->ScreenToClient(&point);
      m_pParentWnd->PostMessage(WM_LBUTTONDOWN,nFlags,MAKELONG(point.x,point.y));
}
void CMyTitleTip::OnLButtonUp(UINT nFlags, CPoint point)
{
      ReleaseCapture();
      ShowWindow( SW_HIDE );
      ClientToScreen(&point);
      m_pParentWnd->ScreenToClient(&point);
      m_pParentWnd->PostMessage(WM_LBUTTONUP,nFlags,MAKELONG(point.x,point.y));
}

void CMyTitleTip::OnRButtonDown(UINT nFlags, CPoint point)
{
      ReleaseCapture();
      ShowWindow( SW_HIDE );
      ClientToScreen(&point);
      m_pParentWnd->ScreenToClient(&point);
      m_pParentWnd->PostMessage(WM_RBUTTONDOWN,nFlags,MAKELONG(point.x,point.y));
}
void CMyTitleTip::OnRButtonUp(UINT nFlags, CPoint point)
{
      ReleaseCapture();
      ShowWindow( SW_HIDE );
      ClientToScreen(&point);
      m_pParentWnd->ScreenToClient(&point);
      m_pParentWnd->PostMessage(WM_RBUTTONUP,nFlags,MAKELONG(point.x,point.y));
}



------------------------------ CMyListCtrl (Cpp) ----------




CMyListCtrl::CMyListCtrl()
{
            ASSERT(m_titletip = new CMyTitleTip());
            if(m_titletip->m_hWnd == NULL)
                  m_titletip->Create( this );
}

CMyListCtrl::~CMyListCtrl()
{
      if(m_titletip){
            delete m_titletip;
            m_titletip = NULL;
      }
}


BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
      //{{AFX_MSG_MAP(CMyListCtrl)
      ON_WM_MOUSEMOVE()
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyListCtrl message handlers

void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
    int row, col;
    RECT cellrect;
      row = CellRectFromPoint(point, &cellrect, &col );
    if( row != -1 && col >=0 && 
            point.y != cellrect.bottom && point.y != cellrect.top && 
            point.x != cellrect.left && point.x != cellrect.right )
    {
                  int offset= ((col==0) ? OFFSET_FIRST:OFFSET_OTHER);
                  m_titletip->Show(cellrect, GetItemText( row, col), offset,offset,
                        FALSE,NULL);
    }
}


int CMyListCtrl::CellRectFromPoint(CPoint & point, RECT * cellrect, int * physicalCol) const
{

        // Make sure that the ListView is in LVS_REPORT
        if( (GetStyle() & LVS_TYPEMASK) != LVS_REPORT )
                return -1;

        // Get the top and bottom row visible
        int row = GetTopIndex();
        int bottom = row + GetCountPerPage();
        if( bottom > GetItemCount() )
                bottom = GetItemCount();
       
        // Get the number of physicalColumns
        CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
        int columnCount = pHeader->GetItemCount();
            CRect tmpr;
            GetItemRect( row, &tmpr, LVIR_LABEL );
            int leftOffset = tmpr.left;
            GetItemRect( row, &tmpr, LVIR_BOUNDS );
            leftOffset = leftOffset - tmpr.left;
        // Loop through the visible rows
        for( ;row <=bottom;row++)
        {
                // Get bounding rect of item and check whether point falls in it.
                CRect rect;
                GetItemRect( row, &rect, LVIR_BOUNDS );
                        rect.left += leftOffset;
                if( rect.PtInRect(point) )
                {
                        // Now find the physicalColumn
                        for( int physicalColnum = 0; physicalColnum < columnCount; physicalColnum++ )
                        {
                                int physicalColwidth = GetColumnWidth(physicalColnum);
                                                if(physicalColnum==0)
                                                      physicalColwidth -= leftOffset;
                                if( point.x >= rect.left && 
                                                point.x <= (rect.left + physicalColwidth ) )
                                {
                                        // Found the physicalColumn
                                        RECT rectClient;
                                        GetClientRect( &rectClient );
                                        if( point.x > rectClient.right )
                                                return -1;
                                        if( physicalCol )
                                                *physicalCol = physicalColnum;
                                        rect.right = rect.left + physicalColwidth;
                                        if( rect.right > rectClient.right )
                                                rect.right = rectClient.right;
                                        *cellrect = rect;
                                        return row;
                                }
                                rect.left += physicalColwidth;
                        }
                }
        }
        return -1;
}




0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1316426
go to www.codeguru.com

there is code there for doing what you want

0
 

Author Comment

by:tflex
ID: 1316427
Motigust,
Your code works fine. One small item you forgot to send probably because of excluding h file - definition for OFFSET_FIRST and OFFSET_OTHER. I put 3 for both, but I guess this is not correct. Please, advise.

Ronslow,
www.codeguru.com is very slow from my location. I spent one hour seeking for code with no success. If it is not big problem, please, advise in what part of this site I can find this source code.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 10

Expert Comment

by:RONSLOW
ID: 1316428
Here is title tip class from code guru (perhaps edited by me ... not sure if I touched it or not .. I changed the name to QTitleTip becuase that is my class naming convention for my 'own' classes - but I also think I fixed a bug or two).

// TitleTip.h : header file
//
#ifndef _QTitleTip_
#define _QTitleTip_
// QTitleTip window
class AFX_EXT_CLASS QTitleTip : public CWnd {
  // Construction
public:
  QTitleTip();
  // Attributes
public:
  // Operations
public:
  // Overrides
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(QTitleTip)
public:
  virtual BOOL PreTranslateMessage(MSG* pMsg);
  //}}AFX_VIRTUAL
  // Implementation
public:
  void Show( CRect rectTitle, LPCTSTR lpszTitleText, int xoffset = 0);
  void Hide();
  virtual BOOL Create( CWnd *pParentWnd);
  virtual ~QTitleTip();
protected:
  CWnd *m_pParentWnd;
  CRect m_rectTitle;
  // Generated message map functions
protected:
  //{{AFX_MSG(QTitleTip)
  afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
};
#endif


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

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TITLETIP_CLASSNAME _T("QTitleTip")

QTitleTip::QTitleTip() {
  // Register the window class if it has not already been registered.
  WNDCLASS wndcls;
  HINSTANCE hInst = AfxGetInstanceHandle();
  if (!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls))) {
    // otherwise we need to register a new class
    wndcls.style = CS_SAVEBITS ;
    wndcls.lpfnWndProc = ::DefWindowProc;
    wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
    wndcls.hInstance = hInst;
    wndcls.hIcon = NULL;
    wndcls.hCursor = LoadCursor( hInst, IDC_ARROW );
    wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);
    wndcls.lpszMenuName = NULL;
    wndcls.lpszClassName = TITLETIP_CLASSNAME;
    if (!AfxRegisterClass(&wndcls)) AfxThrowResourceException();
  }
}

QTitleTip::~QTitleTip() {}

BEGIN_MESSAGE_MAP(QTitleTip, CWnd)
//{{AFX_MSG_MAP(QTitleTip)
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

// QTitleTip message handlers

BOOL QTitleTip::Create(CWnd * pParentWnd) {
  ASSERT_VALID(pParentWnd);
  DWORD dwStyle = WS_BORDER | WS_POPUP;
  DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
  m_pParentWnd = pParentWnd;
  return CreateEx(dwExStyle,TITLETIP_CLASSNAME,NULL,dwStyle,0,0,0,0,NULL,NULL,NULL);
}

void QTitleTip::Show(CRect rectTitle, LPCTSTR lpszTitleText, int xoffset /*=0*/) {
  ASSERT(::IsWindow(m_hWnd));
  ASSERT(!rectTitle.IsRectEmpty());
  if (IsWindowVisible()) return;
  m_rectTitle.right = rectTitle.Width()-xoffset;
  m_rectTitle.bottom = rectTitle.Height();
  m_rectTitle.top = -1;
  m_rectTitle.left = -xoffset;
  m_pParentWnd->ClientToScreen( rectTitle );
  CClientDC dc(this);
  CString strTitle(lpszTitleText);
  CFont *pFont = m_pParentWnd->GetFont();
  CFont *pFontDC = dc.SelectObject( pFont );
  CRect rectDisplay = rectTitle;
  CSize size = dc.GetTextExtent( strTitle );
  rectDisplay.left += xoffset;
  rectDisplay.right = rectDisplay.left + size.cx + 5;
  // Do not display if the text fits within available space
  if ( rectDisplay.right <= rectTitle.right-xoffset) return;
  SetWindowPos(&wndTop,
    rectDisplay.left,rectDisplay.top,
    rectDisplay.Width(),rectDisplay.Height(),
    SWP_SHOWWINDOW|SWP_NOACTIVATE
  );
  dc.SetBkMode( TRANSPARENT );
  dc.TextOut( 0, -1, strTitle );
  dc.SelectObject( pFontDC );
  SetCapture();
}

void QTitleTip::Hide() {
  ReleaseCapture();
  ShowWindow(SW_HIDE);
}

void QTitleTip::OnMouseMove(UINT nFlags, CPoint point) {
  if (!m_rectTitle.PtInRect(point)) {
    Hide();
    // Forward the message
    ClientToScreen( &point );
    CWnd *pWnd = WindowFromPoint( point );
    if ( pWnd == this ) pWnd = m_pParentWnd;
    int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
    if (hittest == HTCLIENT) {
      pWnd->ScreenToClient( &point );
      pWnd->PostMessage( WM_MOUSEMOVE, nFlags, MAKELONG(point.x,point.y) );
    } else {
      pWnd->PostMessage( WM_NCMOUSEMOVE, hittest, MAKELONG(point.x,point.y) );
    }
  }
}

BOOL QTitleTip::PreTranslateMessage(MSG* pMsg) {
  switch (pMsg->message) {
  case WM_LBUTTONDOWN:
  case WM_RBUTTONDOWN:
  case WM_MBUTTONDOWN:
    {
      Hide();
      POINTS pts = MAKEPOINTS( pMsg->lParam );
      POINT point; point.x = pts.x; point.y = pts.y;
      ClientToScreen( &point );
      CWnd *pWnd = WindowFromPoint( point );
      if (pWnd == this) pWnd = m_pParentWnd;
      int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
      if (hittest == HTCLIENT) {
        pWnd->ScreenToClient( &point );
        pMsg->lParam = MAKELONG(point.x,point.y);
      } else {
        switch (pMsg->message) {
        case WM_LBUTTONDOWN: pMsg->message = WM_NCLBUTTONDOWN; break;
        case WM_RBUTTONDOWN: pMsg->message = WM_NCRBUTTONDOWN; break;
        case WM_MBUTTONDOWN: pMsg->message = WM_NCMBUTTONDOWN; break;
        }
        pMsg->wParam = hittest;
        pMsg->lParam = MAKELONG(point.x,point.y);
      }
      pWnd->PostMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
    }
    return TRUE;
  case WM_KEYDOWN:
  case WM_SYSKEYDOWN:
    Hide();
    m_pParentWnd->PostMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
    return TRUE;
  }
  if (GetFocus() == NULL) {
    Hide();
    return TRUE;
  }
  return CWnd::PreTranslateMessage(pMsg);
}


To use make a new m_pTitleTip in you list control class constructor (and delete it in the destructor)
In your PreSubclassWindow call m_pTitleTip->Create(this);

In the mouse move, call m_pTitleTip->Show(cellrect,text,offset); where cellrect is the rect for the row/col cell, text is the text of the label is an offset (which depends on checkbox present etc.

In my code I use
  int col; CRect cellrect;
  int item = HitTestEx(point,&col,cellrect);
  if (item != -1 && !cellrect.IsRectEmpty()) {
    // The offset of the text from the left border
    // of column is usually 5 pixels
    int offset = 5;
    // For first column, the offset should account for image
    if (col == 0) {
      if ((GetExStyle() & LVS_EX_CHECKBOXES) != 0) {
         offset += 14;
      } else {
         offset--;      // move to the left a bit
      }
    }
    CString text = GetItemText(item,col);
    int sw = GetStringWidth(text)+offset;
    if (sw > cellrect.Width()) {
      m_pTitleTip->Show(cellrect,text,offset);
    }
  }

But this code uses a helper routine (HitTextEx) .. If you aren't using multiple columns (report mode), then a simpler hit test would be ok (mine detects the column the point is in as well as the row and also returns the cell rect for that row/col

0
 

Author Comment

by:tflex
ID: 1316429
Thanks a lot!!!
0
 
LVL 1

Expert Comment

by:motigust
ID: 1316430
Sorry about that:


#define OFFSET_FIRST      2
#define OFFSET_OTHER      6

0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
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.
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…
Suggested Courses

743 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