VC中給樹形控制元件的圖示加上工具提示 (轉)

gugu99發表於2007-08-17
VC中給樹形控制元件的圖示加上工具提示 (轉)[@more@]VC中給樹形的圖示加上工具提示



我從沒有在任何一個應用中看到過圖示的工具提示。有時候查遍了整個幫助
文件也沒有明白某個圖示是什麼意思。如果能在自己的程式中為圖示加上工具提
示,一定會使介面的友好性大大增加。本文中以樹形控制元件為例,詳細介紹了在VC
中使用MFC提供的機制來實現圖示工具提示的方法。

---- 第一步:使控制元件可以顯示工具提示

---- EnableTool(TRUE)使一個視窗可以顯示工具提示。在什麼地方插入
這條程式碼最好呢?在類的PreSubclassWindow()中。因為不管一個控制元件如何被建立
,MFC都會呼叫此。而其他的函式則不一定會被呼叫。以OnCreate()為例,如
果呼叫Create()或CreateEx()建立一個控制元件,OnCreate()會被呼叫,而如果一個
控制元件是從對話方塊資源建立,OnCreate()就不會被呼叫。

實現程式碼如下:
void CTreeCtrlX::PreSubclassWindow()
{
CTreeCtrl::PreSubclassWindow();

EnableToolTips(TRUE);
}

---- 第二步:過載虛擬函式OnToolHitTest()
---- MFC呼叫函式來確定在某個點是否應該顯示工具提示。MSDN建議如果滑鼠落
在應該顯示工具提示的點上,返回值1。這並不完全正確。這個函式應該返回不同
的值來區分視窗中不同的應該顯示提示的區域。

---- 在這個函式中,本文只處理滑鼠落在節點圖示或節點狀態圖示上的情況。讀
者可以按照自己的情況向樹的其他元素上新增工具提示。在兩種情況下,都要計
算圖示的區域,並且把TOOLINFO的uID設為滑鼠所在點的樹節點的控制程式碼。注意,盡
管對於節點圖示和節點狀態圖示,使用了相同的id,但返回值並不相同。不同的
返回值迫使MFC工具提示。

---- 雖然我們可以在此函式中給出工具提示,但因為滑鼠的每次移動都會呼叫此
函式,太多的處理並不是一個好注意,所以我們在其他的函式中處理應該顯示什
麼提示的問題。

類宣告中的程式碼如下所示:
// Overrs
// ClassWizard generated
virtual function overrides
//{{AFX_VIRTUAL(CTreeCtrlX)
protected:

virtual int OnToolHitTest
( CPoint point, TOOLINFO* pTI ) const;
//}}AFX_VIRTUAL

實現程式碼如下所示:
int CTreeCtrlX::OnToolHitTest
(CPoint point, TOOLINFO * pTI) const
{
RECT rect;

UINT nFlags;
HTREEITEM hitem = HitTest( point, &nFlags );
if( nFlags & TVHT_ONITEMICON )
{
CImageList *pImg = GetImageList( TVSIL_NORMAL );
IMAGEINFO imageinfo;
pImg- >GetImageInfo( 0, &imageinfo );

GetItemRect( hitem, &rect, TRUE );
rect.right = rect.left - 2;
rect.left -= (imageinfo.rcImage.right + 2);

pTI- >hwnd = m_hWnd;
pTI- >uId = (UINT)hitem;
pTI- >lpszText = LPSTR_TEXTCALLBACK;
pTI- >rect = rect;
return pTI- >uId;
}
else if( nFlags & TVHT_ONITEMSTATEICON )
{
CImageList *pImg = GetImageList( TVSIL_NORMAL );
IMAGEINFO imageinfo;
pImg- >GetImageInfo( 0, &imageinfo );

GetItemRect( hitem, &rect, TRUE );
rect.right = rect.left -
(imageinfo.rcImage.right + 2);

pImg = GetImageList( TVSIL_STATE );
rect.left = rect.right - imageinfo.rcImage.right ;

pTI- >hwnd = m_hWnd;
pTI- >uId = (UINT)hitem;
pTI- >lpszText = LPSTR_TEXTCALLBACK;
pTI- >rect = rect;

// 返回與節點圖示不同的值
return pTI- >uId*2;
}
return -1;
}

---- 第三步:處理TTN_NEEDTEXT訊息;
---- 加入一個函式處理TTN_NEEDTEXT訊息通知。當工具處理控制需要知道應該顯
示什麼資訊時,這條訊息被髮出。由於上一步中我們給TOOLINFO的lpszText賦值
為LPSTR_TEXTCALLBACK,所以我們要處理這個訊息VC的ClassWizard並不支援這條
訊息被對映,所以只有我們自己加入這條訊息的對映機制加入到MESSAGE_MAP中去
。我們不得不處理這個訊息的兩個版本,TTN_NEEDTEXTA和TTN_NEEDTEXTA。訊息
對映的程式碼如下所示:

BEGIN_MESSAGE_MAP(CTreeCtrlX, CTreeCtrl)
//{{AFX_MSG_MAP(CTreeCtrlX)

//}}AFX_MSG_MAP
ON_NOTIFY_EX_RANGE
(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
ON_NOTIFY_EX_RANGE
(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
END_MESSAGE_MAP()

下面的程式碼是加到類宣告中:
protected:
//{{AFX_MSG(CTreeCtrlX)

//}}AFX_MSG
afx_msg BOOL OnToolTipText
( UINT id, NMHDR * pNMHDR, LRESULT * pResult );
DECLARE_MESSAGE_MAP()

---- 現在討論這個函式本身的實現。為了適應不同的語言字符集,ANSI字符集和
UNICODE字符集都必須被處理,處理過程會有些不同。此處對樹形控制元件的本身產生
的ToolTip訊息不予處理,過濾掉上述訊息的原則是樹形控制元件本身產生的訊息的ID
是樹形控制元件視窗的控制程式碼,並且有TTF_IDISHWND標誌。根據滑鼠位置可以確定應該
給出節點圖示還是狀態圖示的工具提示。本文根據筆者畫的圖顯示了一些無關緊
要的提示,讀者做這一步時應該加入一些有意義的提示。當然,本文假定控制元件包
含節點圖示和狀態圖示。如不包含,計算滑鼠位置時要注意 不要計算錯誤。

BOOL CTreeCtrlX::OnToolTipText
( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
// 需要處理ANSI和UNICODE兩種格式
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
CString strTipText;
UINT nID = pNMHDR- >idFrom;

// 不必處理樹自己發出的ToolTip訊息
if( nID == (UINT)m_hWnd &&
(( pNMHDR- >code == TTN_NEEDTEXTA &&
pTTTA- >uFlags & TTF_IDISHWND ) ||
( pNMHDR- >code == TTN_NEEDTEXTW &&
pTTTW- >uFlags & TTF_IDISHWND ) ) )
return FALSE;

// 得到滑鼠位置
const MSG* pMessage;
CPoint pt;
pMessage = GetCurrentMessage();
ASSERT ( pMessage );
pt = pMessage- >pt;
ScreenToClient( &pt );

UINT nFlags;
HTREEITEM hitem = HitTest( pt, &nFlags );
if( nFlags & TVHT_ONITEMICON )
{
int nImage, nSelImage;
GetItemImage( (HTREEITEM ) nID, nImage, nSelImage );
switch(nImage)
{
case 0:
strTipText = "叉";
break;
case 1:
strTipText = "加號";
break;
case 2:
strTipText = "菱形";
break;
}
}
else
{
if( (GetItemState( (HTREEITEM ) nID,
TVIS_STATEIMAGEMASK ) > >12 ) == 2 )
strTipText.Format( "此節點被選中" );
else
strTipText.Format( "此節點未被選中" );
}

#ifndef _UNICODE
if (pNMHDR- >code == TTN_NEEDTEXTA)
lstrcpyn(pTTTA- >szText, strTipText, 80);
else
_mbstowcsz(pTTTW- >szText, strTipText, 80);
#else
if (pNMHDR- >code == TTN_NEEDTEXTA)
_wcstombsz(pTTTA- >szText, strTipText, 80);
else
lstrcpyn(pTTTW- >szText, strTipText, 80);
#endif
*pResult = 0;

return TRUE; // 訊息處理完畢
}

---- 本文程式在,VC6.0下透過。




來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-963072/,如需轉載,請註明出處,否則將追究法律責任。

相關文章