程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 有Toolbar功能的可重用類CPopupText

有Toolbar功能的可重用類CPopupText

編輯:關於VC++

背景:我用一個CListBox派生類實現宿主(owner-draw)列表框,這個列表框的項目寬度超過了列表框本身的寬度,因此當鼠標指針指向大寬度的列表框項時,我想顯示一個類似Toolbar的提示窗口,在窗口中顯示完整的列表框項目文本。

起初我想使用CToolTipCtrl::AddTool的第三個參數lpRectTool來實現這個功能,但沒有成功。後來,我采用了自立更生的解決方案,創建了一個可重用窗口類,CPopupText-基類是CWnd。用這個派生類不僅可以在列表框中實現類似Toolbar的提示窗口,還可以在其它的通用控件(如組合框、列表視圖等)中實現類似Toolbar的提示窗口。

CPopupText實現了一個類似Toolbar的彈出式窗口-淺黃色的背景,黑色的文本。

CPopupText的使用方法是:實例化對象並創建窗口。

CPopupText wndText;
wndText.Create(...);

Create 函數的參數為:父窗口,風格,ID以及位置信息CPoint,通常你要創建不可見窗口(即關閉WS_VISIBLE),然後,當你想顯示提示時,先調用 SetWindowText 函數

設置提示文本,接著調用 ShowWindow 函數顯示提示文本。

wndText.SetWindowText("hello, world");
wndText.ShowWindow(SW_SHOWNA);

CPopupText類會根據提示文本的長度自己決定彈出窗口的大小。它的字體默認值與狀態行顯示字體相同(由SystemParametersInfo(SPI_GETNONCLIENTMETRICS)返回的 NONCLIENTMETRICS 結構成員 lfStatusFont 定義),設置 SW_SHOWNA是很重要的,因為你不想使提示窗口為活動窗口,而只是顯示它。另外,CPopupText還提供一個專門的函數CPopupText::ShowDelayed,它的功能是在顯示提示窗口之前設置一個毫秒級延時,如果延時為零,則立刻顯示提示窗口,你可以使用這個特點來替代對ShowWindow的調用。如果要隱藏提示窗口或取消ShowDelayed,調用CPopupText::Cancel。

OK,前面講了關於CPopupText類的創建以及使用方法。下面要講一下對列表框所要做的事情。它是用CListBoxTipHandler類來實現的。這個類的功能是當列表框項目文本寬度超過列表框本身的寬度時,在一個提示窗口中顯示鼠標指針所指的列表框項目的完整文本內容。圖一是本文的例子程序,LCTest。它是一個對話框的例子。

圖一

CListBoxTipHandler類很容易使用,你只要實例化並用Init函數初始化實例就可以了。

class CMyDialog {
 CListBox m_wnd_List; // 普通的 listbox
 CListBoxTipHandler
  m_tipHandler;   // CListBoxTipHandler類實例
......
};
BOOL CMyDialog::OnInitDialog(){
......
 m_tipHandler.Init(&m_wndList);
......
}

就這樣,你的listbox魔法般地獲得了提示特性(圖一)。

CListBoxTipHandler類的設計原則是使它盡量易於使用,它的工作原理又是怎樣的呢?如果你仔細研究一下它的代碼就會明白。CListBoxTipHandler類的基類是CSubclassWnd,這個類在以前的VCKBASE文章中出現過很多次,CSubclassWnd類的作用是不用派生新類便能在MFC中子類化窗口。這一點很重要,如果你從CListBox派生一個新類,假如說是:CListBoxWithTips,那你就不能在自己已經派生的列表框類(如:CMyListBox)中直接使用它。而要作很多修改。這是不可取的。CSubclassWnd完全可以讓CListBoxTipHandler通過實例化來子類你的列表框,而不是通過派生。

當你調用Init函數時,CListBoxTipHandler子類化列表框,然後,截獲發送到列表框的所有消息。而只有一個消息是我們感興趣的,那就是 WM_MOUSEMOVE。

當用戶移動鼠標到列表框時,CListBoxTipHandler實例(提示處理器)便檢查鼠標所指的列表框項目的文字是否比列表框本身的寬度要寬,從而決定是否啟動CPopupText顯示文本提示窗口。其中的處理有兩個技巧。

第一個技巧:如果用戶把鼠標從文本提示窗口上移走,CListBoxTipHandler會調用CPopupText::Cancel 隱藏提示窗。當用戶的鼠標在列表框項目間移動時不會有什麼問題,但如果將鼠標完全移到列表框之外會發生什麼呢?顯然,你無法知道哪一個是最後一個WM_MOUSEMOVE消息。為了避免這種情況,CListBoxTipHandler代表列表框來捕獲鼠標,所以全部的鼠標消息都到了CListBoxTipHandler,當鼠標移到列表框之外的情況發生時,

CListBoxTipHandler釋放鼠標。

第二個技巧:關於提示窗的激活與隱藏。為了正確定位提示窗口,CListBoxTipHandler要計算窗口矩形的大小,並調用SetWindowPos函數。這裡使用 SWP_NOACTIVATE 很關鍵,否則提示窗口將是活動的,而且對話框不活動-對話框標題條變灰。在調用 CPopupText::ShowWindow 時之所以必須用SW_SHOWNA 也是一樣的道理。

例子程序使用了一個最普通的列表框,但 CListBoxTipHandler 應該處理宿主(owner-draw)列表框,另外還要讓 CListBoxTipHandler 獲得列表框項目文本並決定文本寬度。CListBoxTipHandler::OnGetItemInfo 和  CListBoxTipHandler::IsRectCompletelyVisible 是兩個重載的虛函數,如果你想讓CListBoxTipHandler 類也適用於其它類似列表框一樣的控件(如組合框、列表視圖等),這兩個函數是你必須修改的。不要將CListBoxTipHandler 用於樹型控件,因為樹型控件本身就內建有toolbar功能。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved