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

📄 titletip.shtml.htm

📁 mfc资料集合5
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="Author" CONTENT="Zafir Anjum">
   <TITLE>CListCtrl - Titletip for individual cells</TITLE>
</HEAD>
<body background="../fancyhome/back.gif" tppabs="http://www.codeguru.com/fancyhome/back.gif" bgcolor="#FFFFFF" link="#B50029" vlink="#8E2323" alink="#FF0000" bgproperties="fixed">
<table WIDTH="100%">
<tr WIDTH="100%">
<td><td>
</tr>
</table>


<CENTER>
<H3>
<FONT COLOR="#AOAO99">Titletip for individual cells</FONT></H3></CENTER>

<HR WIDTH="100%">Titletips are somewhat like tooltips. You have already seen it in action in the Developer's Studio ClassView. For listview controls, titletips are used to display text of those cells which are not wide enough to display the text completely. The titletips show up as soon as the mouse moves over the cell.
<p><img src="titletip.gif" tppabs="http://www.codeguru.com/listview/titletip.gif" border="1" width="281" height="48"></p>

<p>To implement titletips we define a custom class for the titletip. This class is responsible for displaying the tips when needed. Within the mouse move handler of the listview control we simply call a member function of the CTitleTip object with the cell rectangle and the text to display within it. The CTitleTip object then determines whether the titletip should display. The title tip destroys itself whenever the mouse moves outside of the cell rectangle passed in as an argument or whenever the application loses focus.

<h4>Step 1: Define CTitleTip class</h4>
The listing for the CTitleTip class is given below. First the header file then the implementation file. This class is very generic and can be used with other controls and in other situations also.

<p>In the constructor of CTitleTip we register the window class if it has not already been registered by another instance of the program. The background brush used for the class is COLOR_INFOBK. This is the same color used by the tooltip.

<p>The Create() function follows the convention of other MFC classes. It is within this function that the window is created. The important thing to notice in this function is the window style. The WS_BORDER style draws a border around the titletip window. The WS_POPUP style is needed because we want the titletip window to be able to extend beyond the boundary of the listview control. If we do not specify this style, the window will be clipped at the control boundary and will not be very useful. The WS_EX_TOOLWINDOW style stops the window from appearing in the task bar. The WS_EX_TOPMOST style makes sure that the titletip is visible.

<p>The Show() function gets repeatedly called by the client control, in this case the listview control. The primary task of Show() is to determine the text extent of the the titletext and display the titletip if the rectangle passed in as an argument is not big enough to display it completely. It also stores a rectangle which is used later to remove the titletip is the mouse moves outside this rectangle.

<p>The handler for WM_MOUSEMOVE - OnMouseMove() - checks whether the mouse is within the cell rectangle that the titletip is being shown for. This rectangle is smaller than the titletip client area rectangle (else there would not have been any need to show the titletip). If the mouse is outside this rectangle, then the titletip is hidden and the WM_MOUSEMOVE or a WM_NCMOUSEMOVE message is passed on to the underlying window.

<p>The tooltip also needs to be dismissed when the user presses a key or a mouse button. We override the PreTranslateMessage() to look for these messages. If any of these messages are received, the titletip is dismissed and an appropriate message passed on to the list view control.


<PRE><TT><FONT COLOR="#990000">#if !defined(AFX_TITLETIP_H__FB05F243_E98F_11D0_82A3_20933B000000__INCLUDED_)
#define AFX_TITLETIP_H__FB05F243_E98F_11D0_82A3_20933B000000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// TitleTip.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CTitleTip window

#define TITLETIP_CLASSNAME _T("ZTitleTip")


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

// Attributes
public:

// Operations
public:

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

// Implementation
public:
	void Show( CRect rectTitle, LPCTSTR lpszTitleText, int xoffset = 0);
	virtual BOOL Create( CWnd *pParentWnd);
	virtual ~CTitleTip();

protected:
	CWnd *m_pParentWnd;
	CRect m_rectTitle;


	// Generated message map functions
protected:
	//{{AFX_MSG(CTitleTip)
	afx_msg void OnMouseMove(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_TITLETIP_H__FB05F243_E98F_11D0_82A3_20933B000000__INCLUDED_)







////////////////////////////////////////////////////////////////////////////
// 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

/////////////////////////////////////////////////////////////////////////////
// CTitleTip

CTitleTip::CTitleTip()
{
	// 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();
	}
}

CTitleTip::~CTitleTip()
{
}


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


/////////////////////////////////////////////////////////////////////////////
// CTitleTip message handlers

BOOL CTitleTip::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 );
}


// Show 		- Show the titletip if needed
// rectTitle		- The rectangle within which the original 
//			  title is constrained - in client coordinates
// lpszTitleText	- The text to be displayed
// xoffset		- Number of pixel that the text is offset from
//			  left border of the cell
void CTitleTip::Show(CRect rectTitle, LPCTSTR lpszTitleText, int xoffset /*=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;

	// Define the rectangle outside which the titletip will be hidden.
	// We add a buffer of one pixel around the rectangle
	m_rectTitle.top = -1;
	m_rectTitle.left = -xoffset-1;
	m_rectTitle.right = rectTitle.Width()-xoffset;
	m_rectTitle.bottom = rectTitle.Height()+1;

	// Determine the width of the text
	m_pParentWnd->ClientToScreen( rectTitle );

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

	CRect rectDisplay = rectTitle;
	CSize size = dc.GetTextExtent( strTitle );
	rectDisplay.left += xoffset;
	rectDisplay.right = rectDisplay.left + size.cx + 3;

	// Do not display if the text fits within available space
	if( rectDisplay.right <= rectTitle.right-xoffset )
		return;

	// Show the titletip
	SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top, 
			rectDisplay.Width(), rectDisplay.Height(), 
			SWP_SHOWWINDOW|SWP_NOACTIVATE );

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

	SetCapture();
}

void CTitleTip::OnMouseMove(UINT nFlags, CPoint point) 
{
	 if (!m_rectTitle.PtInRect(point)) {
		  ReleaseCapture();
		  ShowWindow( SW_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 CTitleTip::PreTranslateMessage(MSG* pMsg) 
{
	CWnd *pWnd;
	int hittest ;
	switch( pMsg->message )
	{
	case WM_LBUTTONDOWN:
	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 );
		pWnd->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);
}
</FONT></TT></PRE>

<h4>Step 2: Define helper function CellRectFromPoint()</h4>
This function is primarily used to get the rectangle of the cell under the cursor. It also returns the row index of the cell. The basic strategy that this function uses is to first determine the row that the point falls in. Then it goes through each cell in that row to find which cell the point falls in.

<PRE><TT><FONT COLOR="#990000">// CellRectFromPoint	- Determine the row, col and bounding rect of a cell
// Returns		- row index on success, -1 otherwise
// point		- point to be tested.
// cellrect		- to hold the bounding rect
// col			- to hold the column index, can be NULL
int CMyListCtrl::CellRectFromPoint(CPoint & point, RECT * cellrect, int * col) const
{
	int colnum;

	// 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 columns
	CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
	int nColumnCount = pHeader->GetItemCount();

	// 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 );
		if( rect.PtInRect(point) )
		{
			// Now find the column
			for( colnum = 0; colnum < nColumnCount; colnum++ )
			{
				int colwidth = GetColumnWidth(colnum);
				if( point.x >= rect.left && 
						point.x <= (rect.left + colwidth ) )
				{
					// Found the column
					RECT rectClient;
					GetClientRect( &rectClient );
					if( point.x > rectClient.right )
						return -1;
					if( col ) 
						*col = colnum;
					rect.right = rect.left + colwidth;
					if( rect.right > rectClient.right ) 
						rect.right = rectClient.right;
					*cellrect = rect;
					return row;
				}
				rect.left += colwidth;
			}
		}
	}
	return -1;
}
</FONT></TT></PRE>

⌨️ 快捷键说明

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