Solved

Tooltips for CListCtrl

Posted on 1998-06-09
6
1,435 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
  • 2
  • 2
  • 2
6 Comments
 
LVL 1

Accepted Solution

by:
motigust earned 200 total points
Comment Utility
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
Comment Utility
go to www.codeguru.com

there is code there for doing what you want

0
 

Author Comment

by:tflex
Comment Utility
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 Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
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
Comment Utility
Thanks a lot!!!
0
 
LVL 1

Expert Comment

by:motigust
Comment Utility
Sorry about that:


#define OFFSET_FIRST      2
#define OFFSET_OTHER      6

0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
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.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

763 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now