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

VC++ 自繪視窗打造炫酷介面:標題列、邊框、系統按鈕完整實作

     編輯:VC++

前言

像 QuickTime、金山詞霸等軟體擁有獨特視覺風格,核心在於自繪非客戶區:標題列、邊框、系統按鈕 (最小化/最大化/關閉) 全由程式繪製。本文分享自繪視窗核心原理與實作細節。

核心原理

攔截 WM_NCPAINT (非客戶區重繪)、WM_NCLBUTTONDOWN (非客戶區滑鼠按下)、WM_NCMOUSEMOVE (滑鼠移動)、WM_SIZE (大小改變) 等訊息,完全接管視窗外觀繪製與互動邏輯。

美術資源準備

需提供以下位圖資源 (紅框標示區域):

  • 標題列左/中/右段 (含圖示區、標題文字區)
  • 系統按鈕三態 (正常、滑鼠懸停、按下) × 3 個按鈕
  • 邊框左/右/底邊
  • 狀態列背景 (可選)

自繪區域示意圖

VC++ 繪圖基礎技術

void DrawBitmap(CDC* pDC, int x, int y, UINT nResID)
{
    CBitmap bmp; bmp.LoadBitmap(nResID);
    BITMAP bm; bmp.GetBitmap(&bm);
    
    CDC memDC; memDC.CreateCompatibleDC(pDC);
    CBitmap* pOld = memDC.SelectObject(&bmp);
    pDC->BitBlt(x, y, bm.bmWidth, bm.bmHeight, &memDC, 0, 0, SRCCOPY);
    memDC.SelectObject(pOld);
}

關鍵訊息處理實作

1. 重繪非客戶區 (WM_NCPAINT)

void CMyDialog::OnNcPaint()
{
    CWindowDC dc(this);
    CRect rcWindow; GetWindowRect(&rcWindow);
    CRect rcClient; GetClientRect(&rcClient);
    ClientToScreen(&rcClient);
    
    // 計算非客戶區矩形
    CRect rcTitle(0, 0, rcWindow.Width(), GetSystemMetrics(SM_CYCAPTION));
    CRect rcLeftBorder(0, rcTitle.bottom, GetSystemMetrics(SM_CXFRAME), rcWindow.Height() - rcTitle.bottom - GetSystemMetrics(SM_CYFRAME));
    // ... 類似計算右邊框、底邊框、系統按鈕區域
    
    // 繪製標題列背景 (左中右三段)
    DrawBitmap(&dc, rcTitle.left, rcTitle.top, IDB_TITLE_LEFT);
    for (int x = rcTitle.left + LEFT_W; x < rcTitle.right - RIGHT_W; x += MID_W)
        DrawBitmap(&dc, x, rcTitle.top, IDB_TITLE_MID);
    DrawBitmap(&dc, rcTitle.right - RIGHT_W, rcTitle.top, IDB_TITLE_RIGHT);
    
    // 繪製系統按鈕 (依滑鼠狀態選擇位圖)
    // 繪製邊框 ...
}

2. 滑鼠互動 (WM_NCLBUTTONDOWN / WM_NCMOUSEMOVE)

void CMyDialog::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
    // 判斷點擊位置:關閉/最大化/最小化按鈕
    // 設定按鈕狀態為「按下」,Invalidate 觸發重繪
    // 若點擊標題列非按鈕區域,呼叫 Default() 讓系統處理拖曳移動
}

void CMyDialog::OnNcMouseMove(UINT nHitTest, CPoint point)
{
    // 追蹤滑鼠是否進入系統按鈕區域
    // 更新按鈕狀態 (正常/懸停/按下),局部重繪
}

3. 視窗大小改變 (WM_SIZE)

void CMyDialog::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);
    // 重新計算客戶區內控制項位置大小
    RepositionControls(cx, cy);
}

完整範例介面

自繪視窗成品

實作重點提醒

  • 對話框資源編輯器中,只勾選 Title Bar,其餘邊框、系統選單等取消
  • 訊息處理函式需手動加入 (ClassWizard 不支援 WM_NCPAINT 等)
  • 座標轉換關鍵:ClientToScreen、ScreenToClient、GetWindowRect、GetClientRect 正確運用
  • 釋放 DC 記得 ReleaseDC,記憶體 DC 需 DeleteDC

下一步挑戰

將自繪邏輯子類化為可重用基類,支援多視窗統一風格、控制項自動佈局、隨視窗縮放調整。敬請期待續集。

作者聯繫:QQ 34544052 / Email: Song_0962@sina.com

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