⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 titletip.shtml.htm

📁 mfc资料集合5
💻 HTM
📖 第 1 页 / 共 2 页
字号:

<h4>Step 3: Add handler for WM_MOUSEMOVE</h4>
The OnMouseMove() code uses the CellRectFromPoint() function to determine the row and column index and the sub-item rectangle. It then passes the rectangle and the item text information to the titletip object. It is the titletip object that decides whether it needs to be displayed.

<p>The label text is always displayed with a small offset from the left edge of the cell. In the case of the first column this offset is equal to the width of one space character from the item image. In the case of other columns, this offset is twice the width of a space character. Of course, if the column is wide enough, the offset could be more depending on the text justification. I have used a hard coded value in the code below. It is better to compute and save this value in a member variable. This variable would have to be updated whenever the font changes.

<PRE><TT><FONT COLOR="#990000">void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
	if( nFlags == 0 )
	{
		// To enable Title Tips
		int row, col;
		RECT cellrect;
		row = CellRectFromPoint(point, &cellrect, &col );
		if( row != -1 )
		{
			// offset is equal to TextExtent of 2 space characters.
			// Make sure you have the right font selected into the
			// device context before calling GetTextExtent.
			// You can save this value as a member variable.
			// offset = pDC->GetTextExtent(_T(" "), 1 ).cx*2;
			int offset = 6;
			if( col == 0 ) 
			{
				CRect rcLabel;
				GetItemRect( row, &rcLabel, LVIR_LABEL );
				offset = rcLabel.left - cellrect.left + offset / 2;
			}
			cellrect.top--;
			m_titletip.Show( cellrect, GetItemText( row, col ), offset-1 );
		}
	}

	CListCtrl::OnMouseMove(nFlags, point);
}
</FONT></TT></PRE>

<h4>Step 4: Create the titletip object</h4>
First add a member variable of the type CTitleTip to the class CListView or CListCtrl derived class. If you are using a CListCtrl derived class, override the PreSubclassWindow() function and add the code shown below. If you are using a CListView derived class instead, you can add this code to OnCreate() or OnInitialUpdate().

<PRE><TT><FONT COLOR="#990000">void CMyListCtrl::PreSubclassWindow() 
{
	CListCtrl::PreSubclassWindow();

	// Add initialization code
	m_titletip.Create( this );
}
</FONT></TT></PRE>




<h3>Update for users of the new control (IE4)</h3>
The new listview control with IE4 among other things, supports dragging of the 
columns to rearrange their sequence. If you use that feature, the above code does
not work. <A HREF="mailto:mfindlay@seanet.com">Mark Findlay</A> ran acroos this
problem and was kind enough to send us a fix. Here goes -


<P>Handling title tips for list controls that support drag and drop
using "Titletip for individual cells" by Zafir Anjum as a starting point.

<P>The new CListCtrl allows for the drag and drop of columns. While this is
a cool new feature, it also introduces a little more programmer 
responsibility to keep track of the column position. Fortunately
the Column header item helps by maintaining the current column position
as well as the original column position. 

<P>We will use this information to display title tips for columns which
have been dragged to a new position. 

<P>Using the "Titletip for individual cells" by Zafir Anjum, we add 2 additional
functions: 
<P>                GetTrueItemText() and GetTrueColumnWidth().


<P>Add the following function prototypes anywhere they will be accessible to the 
OnMouseMove() and CellRectFromPoint() functions. 

<P>Note that you might need to modify the implementations of these functions 
if you place them in a non-CListView derived class as I have coded them.
<PRE><TT><FONT COLOR="#990000">    
    CString GetTrueItemText( int row, int col );
    int GetTrueColumnWidth(int nCurrentPosition);
</FONT></TT></PRE>



<P>Add the following function implementations for the prototypes:

<P>First - the GetTrueItemText

<PRE><TT><FONT COLOR="#990000">
//**************************************************
CString CMyListView::GetTrueItemText(int row, int col)
{
    CListCtrl& ctlList = GetListCtrl();

    // Get the header control 
	CHeaderCtrl* pHeader = (CHeaderCtrl*)ctlList.GetDlgItem(0);
    _ASSERTE(pHeader);

    // get the current number of columns 
    int nCount = pHeader->GetItemCount();

    // find the actual column requested. We will compare
    // against hi.iOrder
    for (int x=0; x< nCount; x++)
    {
        HD_ITEM hi = {0};
        hi.mask = HDI_ORDER;

        BOOL bRet = pHeader->GetItem(x,&hi);
        _ASSERTE(bRet);
        if (hi.iOrder == col)
        {
            // Found it, get the associated text
            return ctlList.GetItemText(row,x);
        }
    }

    _ASSERTE(FALSE);
    return "We better never fall through to here!";

}
</FONT></TT></PRE>


<P>Next the GetTrueColumnWidth

<PRE><TT><FONT COLOR="#990000">
//**************************************************************
int CMyListView::GetTrueColumnWidth(int nCurrentPosition)
{
    CListCtrl& ctlList = GetListCtrl();

	CHeaderCtrl* pHeader = (CHeaderCtrl*)ctlList.GetDlgItem(0);
    _ASSERTE(pHeader);

    int nCount = pHeader->GetItemCount();

    for (int x=0; x< nCount; x++)
    {
        HD_ITEM hi = {0};
        hi.mask = HDI_WIDTH | HDI_ORDER;

        BOOL bRet = pHeader->GetItem(x,&hi);
        _ASSERTE(bRet);
        if (hi.iOrder == nCurrentPosition)
            return hi.cxy;
    }

    _ASSERTE(FALSE);
    return 0; // We would never fall through to here!

}
</FONT></TT></PRE>



<P>Then all we need to do is 

<P>1) modify the CMyListCtrl::OnMouseMove() function:
<br>    replace the call to GetItemText() with GetTrueItemText().
    
<P>2) modify the CMyListCtrl::OnMouseMove() function:
<br>    comment out the following code:
<PRE><TT><FONT COLOR="#990000">
			/*if( col == 0 ) 
			{
				CRect rcLabel;
				ctlList.GetItemRect( row, &rcLabel, LVIR_LABEL );
				offset = rcLabel.left - cellrect.left + offset / 2;
			}*/
</FONT></TT></PRE>

<P>3) modify the CellRectFromPoint() function:
<br>    replace the GetColumnWidth() call with GetTrueColumnWidth().

 







<br>
<br>
<br>
<br>
<H3>Handle double click in TitleTips</H3>
Here is another enhancement that Mark Findlay sent in.

<P>The TitleTips helper written by Zafir Anjum is a cool tool that allows
you to show titletips for individual CListCtrl cells. The CTitleTip
PreTranslateMessage handler traps mouse clicks for tip display
purposes but this stifles the mouse double-click message since each
individual mouse click is handled.

<P>With a minor modification the CTitleTips helper can also support 
mouse double-clicks (WM_LBUTTONDBLCLK) messages.



<P>To modify the CTitleTips helper:

<P>1) Create a member variable in the CTitleTips header file
<PRE><TT><FONT COLOR="#990000">
    DWORD m_dwLastLButtonDown
</FONT></TT></PRE>

<P>2) In the CTitleTips constructor, initialize m_dwLastLButtonDown to zero.

<P>3) Add the following #define  to the CTitleTip::PreTranslateMessage function:
<PRE><TT><FONT COLOR="#990000">    #define DBLCLICK_MILLISECONDS 150
</FONT></TT></PRE>

<P>The DBLCLICK_MILLISECONDS specifies the duration between single mouse clicks 
that CTitleTips should handle as a double-click instead of 2 single clicks.
The 150 is a pretty good setting (.15 of a second between clicks will constitute
a double-click) but you can change this to suit your needs/taste

<P>4) Add the following local variables to the beginning of the 
CTitleTip::PreTranslateMessage function:
<PRE><TT><FONT COLOR="#990000">
    // Used to qualify WM_LBUTTONDOWN messages as double-clicks
    DWORD dwTick=0;
    BOOL  bDoubleClick=FALSE;
</FONT></TT></PRE>

<P>5) Insert the following code for the 1st "case WM_LBUTTONDOWN:" at the 
beginning of the function:

<PRE><TT><FONT COLOR="#990000">
    // Get tick count since last LButtonDown
    dwTick = GetTickCount();
    bDoubleClick = ((dwTick - m_dwLastLButtonDown) <= DBLCLICK_MILLISECONDS);
    m_dwLastLButtonDown = dwTick;
    // NOTE: DO NOT ADD break; STATEMENT HERE! Let code "fall.class" tppabs="http://www.codeguru.com/listview/fall.class" through
</FONT></TT></PRE>


<P>6) Just above the case WM_KEYDOWN handler, alter the pWnd->PostMessage
function:

<PRE><TT><FONT COLOR="#990000">
        // If this is the 2nd WM_LBUTTONDOWN in x milliseconds,
        // post a WM_LBUTTONDBLCLK message instead of a single click.
		pWnd->PostMessage(
            bDoubleClick ? WM_LBUTTONDBLCLK : pMsg->message,
            pMsg->wParam,
            pMsg->lParam);

</FONT></TT></PRE>

That's all there is to it. Below is an example of this.


<PRE><TT><FONT COLOR="#990000">
//************************************************************************
BOOL CTitleTip::PreTranslateMessage(MSG* pMsg) 
{
// Number of elapsed milliseconds between WM_LBUTTONDOWN messages to 
// qualify as a double-click
#define DBLCLICK_MILLISECONDS 150

    // Used to qualify WM_LBUTTONDOWN messages as double-clicks
    DWORD dwTick=0;
    BOOL  bDoubleClick=FALSE;

	CWnd *pWnd;
	int hittest ;
	switch( pMsg->message )
	{

	case WM_LBUTTONDOWN:
        // Get tick count since last LButtonDown
        dwTick = GetTickCount();
        bDoubleClick = ((dwTick - m_dwLastLButtonDown) <= DBLCLICK_MILLISECONDS);
        m_dwLastLButtonDown = dwTick;
        // NOTE: DO NOT ADD break; STATEMENT HERE! Let code "fall.class" tppabs="http://www.codeguru.com/listview/fall.class" through
	case WM_RBUTTONDOWN:
	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_RBUTTONDOWN: 
				pMsg->message = WM_NCRBUTTONDOWN;
				break;
			case WM_MBUTTONDOWN: 
				pMsg->message = WM_NCMBUTTONDOWN;
				break;
			}
			pMsg->wParam = hittest;
			pMsg->lParam = MAKELONG(point.x,point.y);
		}
		ReleaseCapture();
		ShowWindow( SW_HIDE );

        // If this is the 2nd WM_LBUTTONDOWN in x milliseconds,
        // post a WM_LBUTTONDBLCLK message instead of a single click.
		pWnd->PostMessage(
            bDoubleClick ? WM_LBUTTONDBLCLK : 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);
}
</FONT></TT></PRE>



<BR>
<HR>
<TABLE BORDER=0 WIDTH="100%" >
<TR>
<TD WIDTH="33%"><FONT SIZE=-1><A HREF="../index.htm" tppabs="http://www.codeguru.com/">Goto HomePage</A></FONT></TD>

<TD WIDTH="33%">
<CENTER><FONT SIZE=-2>&copy; 1997 Zafir Anjum</FONT>&nbsp;</CENTER>
</TD>

<TD WIDTH="34%">
<DIV ALIGN=right><FONT SIZE=-1>Contact me: <A HREF="mailto:zafir@home.com">zafir@home.com</A>&nbsp;</FONT></DIV>
</TD>
</TR>
</TABLE>
<CENTER><IMG SRC="../cgi/Count.cgi-ft=2&dd=E-df=lv_titletip.cnt" tppabs="http://www.codeguru.com/cgi/Count.cgi?ft=2&dd=E%7cdf=lv_titletip.cnt" ALIGN="BOTTOM" BORDER="0"></CENTER>
</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -