無框架對話框(移除標題列與邊框)常用於啟動畫面、媒體播放器、自訂 UI。但失去標題列後,使用者無法拖曳移動視窗。本文介紹兩種專業解法:WM_NCHITTEST 模擬標題列點擊、HTTRANSPARENT 穿透視圖類別,並解決靜態控制項透明點擊、CFormView 適用性等細節。
核心邏輯:滑鼠在客戶區內時返回 HTCAPTION,欺騙系統以為點擊標題列。
UINT CMyDialog::OnNcHitTest(CPoint pt)
{
CRect rc; GetClientRect(&rc);
ClientToScreen(&rc); // 轉螢幕座標
return rc.PtInRect(pt) ? HTCAPTION : CDialog::OnNcHitTest(pt);
}
效果:
原理:Windows 以 Z-order 判斷點擊目標。非靜態控制項會攔截滑鼠訊息;靜態控制項 (
SS_ICON,SS_BITMAP,SS_SIMPLE等) 對話框視為透明,訊息繼續傳遞給對話框OnNcHitTest。
文件/視圖架構中,視圖位於框架視窗內。視圖優先接收 WM_NCHITTEST,需將其設為穿透:
// CMyView 衍生類別
UINT CMyView::OnNcHitTest(CPoint pt)
{
return HTTRANSPARENT; // 完全穿透,讓父框架處理
}
// 或條件式穿透:僅特定區域可拖曳
UINT CMyView::OnNcHitTest(CPoint pt)
{
return PointInDraggableRegion(pt) ? HTTRANSPARENT : CView::OnNcHitTest(pt);
}
父框架 (CMainFrame) 則實作方案一的邏輯:客戶區返回 HTCAPTION。
參考文章「MFC 框架程式全螢幕顯示特性實現」,結合 WM_NCHITTEST 穿透鏈,可實現:
| 問題 | 原因 | 解決 |
|---|---|---|
| 拖曳時視窗閃爍 | 系統預設「拖曳顯示視窗內容」 | SystemParametersInfo(SPI_GETDRAGFULLWINDOWS) 檢查,或接受預設行為 |
| 特定控制項無法點擊 | 控制項 Z-order 遮蓋 | 調整 Tab Order,或在控制項 OnNcHitTest 返回 HTTRANSPARENT |
| CFormView 內嵌對話框模板 | 視圖類別非 CFormView | 確認視圖類別繼承 CFormView,對話框模板風格含 WS_CHILD |
WM_NCHITTEST + HTCAPTION 是無標題列視窗拖曳的標準解法,程式碼極簡(3 行核心邏輯)且相容性極佳。配合 HTTRANSPARENT 可延伸至文件/視圖架構、巢狀視圖、自訂標題列等複雜場景。這是 MFC 開發者必備的視窗管理技巧之一。