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

自繪按鈕完整實現指南:從設計到 XP 風格 CXPButton 類別

     編輯:關於VC++

想讓程式介面脫離標準控制項框架?自繪功能是關鍵。本文完整記錄從零建立 XP 風格 CXPButton 類別的過程,涵蓋設計思路、核心難點突破、使用方法與完整原始碼結構,是學習 MFC 自繪控制項的最佳範例。

按鈕五大狀態視覺設計

自繪按鈕必須定義各狀態外觀:

  • Normal:初始顯示狀態
  • Over:滑鼠懸停時的熱追蹤效果
  • Down:按下時的下壓視覺回饋(文字右下微位移)
  • Focus:擁有焦點時的虛線框指示
  • Disable:停用狀態的灰顯效果

參考 Windows XP 原生按鈕風格設計,確保視覺一致性。

核心實現原理:四大支柱

  1. 啟用 Owner Draw:在 PreSubclassWindow() 設定 BS_OWNERDRAW 樣式,觸發 DrawItem() 重繪機制
  2. 滑鼠追蹤機制:透過 WM_MOUSEMOVE 呼叫 TrackMouseEvent() 註冊 TME_LEAVE | TME_HOVER,觸發 WM_MOUSELEAVE/WM_MOUSEHOVER 實現懸停/離開偵測
  3. DrawItem 繪圖核心:根據 LPDRAWITEMSTRUCT 提供的狀態、矩形、DC 等資訊,執行實際繪圖邏輯
  4. 資源管理:繪圖物件(筆刷、筆、字型)用完即釋放,避免 GDI 物件洩漏

兩大技術難點突破

難點一:非標準訊息 WM_MOUSELEAVE/HOVER 的處理

這兩個訊息無法透過類別精靈加入,需手動:

// 在 .h 檔宣告
afx_msg LRESULT OnMouseLeave(WPARAM, LPARAM);
afx_msg LRESULT OnMouseHover(WPARAM, LPARAM);

// 在 .cpp 訊息對應表
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)

// WM_MOUSEMOVE 中啟用追蹤
void CXPButton::OnMouseMove(UINT nFlags, CPoint point) {
    if (!m_bTracking) {
        TRACKMOUSEEVENT tme = {sizeof(tme), TME_LEAVE | TME_HOVER, m_hWnd, 1};
        m_bTracking = _TrackMouseEvent(&tme);
    }
    CButton::OnMouseMove(nFlags, point);
}

難點二:DRAWITEMSTRUCT 結構深度解析

此結構是自繪的資訊中樞:

成員用途
itemState控制項狀態旗標(ODS_SELECTED、ODS_FOCUS、ODS_HOTLIGHT 等)
rcItem控制項矩形區域(座標原點為控制項左上角)
hDC繪圖裝置內容句柄
itemAction繪圖行為(ODA_DRAWENTIRE、ODA_FOCUS、ODA_SELECT)

掌握此結構,即可根據狀態組合繪製任意視覺效果。

類別使用步驟

  1. 對話框加入按鈕控制項(ID 如 IDC_BUTTON1)
  2. 類別精靈加入變數 m_btnNormal,類型選 CXPButton
  3. 若直接引入原始碼檔案,需刪除專案 .clw 檔並重開專案,選擇「Yes」→「Add All」重建類別資訊

自繪按鈕開發標準流程總結

  1. 確定視覺設計方案
  2. 初始化:設定 BS_OWNERDRAW、指定固定字型防系統字型影響
  3. 加入必要訊息處理函數(滑鼠追蹤、鍵盤焦點等)
  4. 實作 DrawItem():繪圖順序建議「外框→底色→文字→內框」
  5. 嚴格管理 GDI 物件生命週期

附錄:DRAWITEMSTRUCT 完整欄位對照表

文件包含 CtlType(ODT_BUTTON、ODT_MENU 等)、itemState(ODS_HOTLIGHT、ODS_DEFAULT 等)、itemAction 等所有旗標的詳細中文說明,可作為開發時的快速查閱手冊。

總結

CXPButton 不僅是一個可用的按鈕類別,更是一份完整的 MFC 自繪控制項開發教學案例。原始碼開放,可直接整合專案或作為客製化控制項的起點。

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