《無標題對話框的拖動》,示范了如何用鼠標點擊窗口或對話框背景(即客戶區)進行拖動操作,文章中提供的解決方法在沒有上下文菜單的情況下運行很正常,一旦有上下文菜單時,文中所提供的方法便顯現出了缺陷——上下文菜單無法顯示出來。本文將針對這個問題對前一篇提出的方法進行改進。
當初實現拖動的基本思路是改寫 OnNcHitTest 例程,讓鼠標在客戶區中的點擊始終返回 HTCAPTION 而不是 HTCLIENT,從而誘使 Windows 實現拖動操作。沒想到這樣做使上下文菜單的操作出現了混亂,原因是如果強制 OnNcHitTest 在客戶區返回 HTCAPTION,Windows 不會發送 WM_CONTEXTMENU 消息。有一個解決是調用 GetKeyState 函數,在返回 HTCAPTION 之前檢查鼠標右鍵狀態。這個方法要求跟蹤鼠標左右鍵的交換操作。 也就是要自己處理虛擬鍵,而且如果用戶是個左撇子的話,這個方法是否還靈呢?如果有興趣,自己試試吧!除此之外,還有一個方案可以考慮,思路是當 Windows 得到 WM_NCHITTEST 消息時,鼠標按鍵已經釋放。我查閱了 MSDN 有關鼠標消息處理的資料,利用這一間隙,可以通過改寫 OnNcRButtonUp 例程對 WM_NCRBUTTONUP 消息進行處理: // OnNcRButtonUp 函數代碼
void CMyDialog::OnNcRButtonUp(UINT nHitTest, CPoint pt)
{
if (nHitTest==HTCAPTION && PtInClientRect(pt))
SendMessage(WM_CONTEXTMENU, (WPARAM)m_hWnd, MAKELPARAM(pt.x,pt.y));
else
CDialog::OnNcRButtonUp(nHitTest, pt);
}
從代碼中不難看出,如果鼠標命中代碼所反映的鼠標位置為標題欄,而實際位置是在客戶區裡,那麼你必須自己發送 WM_CONTEXTMENU 消息。此為解決問題的關鍵,代碼既要在 OnNcHitTest 中誘使 Windows 把 HTCLIENT 當作 HTCAPTION 處理來實現拖動,又要判斷右鍵發出單擊操作時是否處在客戶區。如果是,則發送 WM_CONTEXTMENU 消息。注意當用戶在標題欄上單擊右鍵時,仍然要顯示系統菜單,這時讓 OnNcRButtonUp 做默認處理即可。下面是本文例子程序運行畫面:
圖一 例子程序運行畫面
詳細的處理細節請下載源代碼。
最後,大家身體健康,編程愉快!
本文配套源碼