首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

美化應用程式外觀:自繪非客戶區實現自訂標題列完整教學

     編輯:關於VC++

Windows 預設標題列、邊框風格千篇一律。本文教學如何在對話框應用程式中完全接管非客戶區繪製,自繪標題列背景、圖示、系統按鈕(關閉、最大化、最小化、說明)並處理滑鼠互動與點擊邏輯,打造獨特視覺風格。

實作架構概覽

  • 基礎:對話框應用程式
  • 核心:重載 DefWindowProc、WM_NCMOUSEMOVE、WM_NCLBUTTONDOWN
  • 資源:10 張系統按鈕位圖(5種按鈕 × 一般/焦點狀態)

關鍵成員變數

CRect m_rtButtExit;   // 關閉按鈕區域
CRect m_rtButtMax;    // 最大化按鈕區域
CRect m_rtButtMin;    // 最小化按鈕區域
CRect m_rtButtHelp;   // 說明按鈕區域
CRect m_rtIcon;       // 圖示區域

核心函數實作

DrawTitleBar - 非客戶區主繪製函數

void CTitleBarDlg::DrawTitleBar(CDC* pDC) {
    if (!m_hWnd) return;
    
    CBrush Brush(RGB(0,100,255));  // 自訂標題列背景色
    CBrush* pOldBrush = pDC->SelectObject(&Brush);
    CRect rtWnd, rtTitle, rtButtons;
    GetWindowRect(&rtWnd);
    
    // ... 計算各區域矩形、繪製背景、按鈕位圖、圖示、標題文字 ...
    // 程式碼較長,完整版請參考原始碼附件
    
    pDC->SelectObject(pOldBrush);
}

DefWindowProc - 訊息過濾觸發重繪

LRESULT CTitleBarDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
    LRESULT lrst = CDialog::DefWindowProc(message, wParam, lParam);
    if (!::IsWindow(m_hWnd)) return lrst;
    
    // 影響非客戶區外觀的訊息觸發重繪
    if (message == WM_MOVE || message == WM_PAINT || message == WM_NCPAINT ||
        message == WM_NCACTIVATE || message == WM_NOTIFY) {
        CDC* pWinDC = GetWindowDC();
        if (pWinDC) {
            DrawTitleBar(pWinDC);
            ReleaseDC(pWinDC);
        }
    }
    return lrst;
}

OnNcMouseMove - 滑鼠移動視覺回饋

void CTitleBarDlg::OnNcMouseMove(UINT nHitTest, CPoint point) {
    CDC* pDC = GetWindowDC();
    if (pDC) {
        // 根據 point 判斷滑鼠在哪個按鈕區域
        // 切換對應按鈕位圖為焦點狀態並重繪
        // ...
    }
    ReleaseDC(pDC);
    CDialog::OnNcMouseMove(nHitTest, point);
}

OnNcLButtonDown - 非客戶區點擊處理

void CTitleBarDlg::OnNcLButtonDown(UINT nHitTest, CPoint point) {
    if (m_rtIcon.PtInRect(point))
        AfxMessageBox("歡迎訪問 FlySnowStdio 主頁");
    else if (m_rtButtHelp.PtInRect(point))
        SendMessage(WM_HELP);
    else if (m_rtButtExit.PtInRect(point))
        SendMessage(WM_CLOSE);
    else if (m_rtButtMin.PtInRect(point))
        SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, MAKELPARAM(point.x, point.y));
    else if (m_rtButtMax.PtInRect(point)) {
        if (IsZoomed())
            SendMessage(WM_SYSCOMMAND, SC_RESTORE, MAKELPARAM(point.x, point.y));
        else {
            SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, MAKELPARAM(point.x, point.y));
            Invalidate();
        }
    }
    else if (!IsZoomed())
        Default();  // 標題列拖曳移動視窗
}

關鍵技術點總結

  • GetWindowDC / ReleaseDC:取得/釋放整個視窗(含非客戶區)DC
  • WM_NCPAINT / WM_NCACTIVATE:非客戶區重繪與啟用狀態變更觸發點
  • PtInRect 擊測:自行計算按鈕區域矩形進行點擊判斷
  • WM_SYSCOMMAND:標準系統命令(最小化、最大化、還原、關閉)
  • Default() 呼叫:保留標題列拖曳移動視窗的預設行為

擴充建議

  • 單文檔架構 (SDI) 原理相同,需額外處理選單列繪製
  • 整合自繪選單 (Owner Draw Menu) 實現整體視覺風格一致
  • 背景支援貼圖、漸層、動畫效果
  • 加入系統按鈕工具提示

測試環境

  • Windows 2000 Advanced Server + VC6 + SP5
  • Windows 98 測試通過

總結

自繪非客戶區是打造獨特視覺風格的終極手段。本文提供完整的訊息處理架構與繪製邏輯框架,開發者可在此基礎上發揮創意,設計專屬的視窗外觀。注意:此技術繞過系統標準繪製機制,需仔細處理相容性與無障礙存取問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved