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

VC++ 實作類 QQ 遊戲大廳導航樹控件:自繪、位圖、漸層背景完整指南

     編輯:關於VC++

前言

專案需求:實現類似 QQ 遊戲大廳側邊欄的樹型導航控件,支援自定義項目圖片、展開/摺疊圖示、漸層背景、橫向分隔線、根節點背景等視覺效果。本文記錄 CTreeCtrlBT : public CTreeCtrl 完整設計與實現細節。

類別架構設計

1. 節點資料結構

struct ITEM_MSG {
    HTREEITEM hItem;          // 項目句柄
    CBitmap ItemBitmap;       // 項目圖片
    COLORREF crTransparent;   // 透明色 (預設白色 RGB(255,255,255))
    ITEM_MSG() : hItem(NULL), crTransparent(RGB(255,255,255)) {}
    ~ITEM_MSG() { if (ItemBitmap.GetSafeHandle()) ItemBitmap.DeleteObject(); }
};

typedef std::map<HTREEITEM, ITEM_MSG*> ITEMMSG_MAP;
  • 使用 std::map 以 HTREEITEM 為鍵儲存每個節點的視覺屬性
  • 析構函數自動釋放 CBitmap 資源

2. 核心訊息處理

訊息/虛函數用途
PreSubclassWindow()初始化控件樣式、建立預設圖片清單
WM_SIZE重新計算客戶區大小、捲軸偏移
WM_PAINT完整自繪:背景、節點、展開按鈕、圖片、文字、分隔線
WM_MOUSEMOVE追蹤滑鼠懸停節點、展開按鈕熱區

3. 公共介面函數

// 背景圖片
BOOL SetBackgroudBitmap(UINT nID);
BOOL SetBackgroudBitmap(LPCTSTR lpszRecourceName);

// 節點圖片
void SetItemBitmap(HTREEITEM hItem, UINT nIdBitmap);
void SetItemBitmap(HTREEITEM hItem, LPCTSTR lpszBitmap);

// 展開/摺疊圖示
void SetExpandBitmap(UINT nIdExpand, UINT nIdCollapse, COLORREF crTransparent = RGB(255,255,255));

// 擴充插入項目 (支援圖片與透明色)
HTREEITEM InsertItemEx(HTREEITEM hParent, LPCTSTR lpszItem, UINT nIdBitmap = 0, COLORREF crTransparent = RGB(255,255,255));
HTREEITEM InsertItemEx(HTREEITEM hParent, LPCTSTR lpszItem, LPCTSTR lpszBitmap, COLORREF crTransparent = RGB(255,255,255));

// 視覺選項
void EnableRowLine(BOOL bEnable = TRUE);  // 橫向分隔線
BOOL IsEnableRowLine();
void EnableRootBk(BOOL bEnable = TRUE);   // 根節點背景
BOOL IsEnableRootBk();

// 內部查詢
ITEM_MSG* GetItemMsg(HTREEITEM hItem);

核心繪圖函數實現

1. 漸層背景填充

void CTreeCtrlBT::GradientFillRect(CDC* pDC, CRect& rect, COLORREF col_from, COLORREF col_to, bool vert_grad) {
    TRIVERTEX vert[2] = {
        {rect.left, rect.top, GetRValue(col_from)<<8, GetGValue(col_from)<<8, GetBValue(col_from)<<8, 0xFFFF},
        {rect.right, rect.bottom, GetRValue(col_to)<<8, GetGValue(col_to)<<8, GetBValue(col_to)<<8, 0xFFFF}
    };
    GRADIENT_RECT gRect = {0, 1};
    pDC->GradientFill(vert, 2, &gRect, 1, vert_grad ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
}

2. 背景圖片繪製 (支援透明色)

void CTreeCtrlBT::DrawBackgroudBitmap(CDC* pDC) {
    if (!m_bmpBackground.GetSafeHandle()) return;
    BITMAP bm; m_bmpBackground.GetBitmap(&bm);
    CDC memDC; memDC.CreateCompatibleDC(pDC);
    CBitmap* pOld = memDC.SelectObject(&m_bmpBackground);
    pDC->TransparentBlt(0, 0, m_rectClient.Width(), m_rectClient.Height(),
        &memDC, 0, 0, bm.bmWidth, bm.bmHeight, m_crBkTransparent);
    memDC.SelectObject(pOld);
}

注意:TransparentBlt 需連結 msimg32.lib。

3. 節點項目完整繪製流程

void CTreeCtrlBT::DrawItem(CDC* pDC) {
    // 計算可視範圍、捲軸偏移
    // 遍歷可視節點:
    //   DrawRowLine()          // 底部分隔線
    //   DrawExpand()           // 展開/摺疊按鈕 (± 圖示)
    //   DrawItemBitmap()       // 節點圖片
    //   DrawItemText()         // 節點文字 (選中/未選中色)
}

4. 關鍵繪圖細節

  • 展開按鈕:使用獨立位圖資源,DrawExpand(CRect, state) 根據 state (展開/摺疊/熱區) 繪製對應幀
  • 文字繪製:DrawText 配合 DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS,選中項使用高亮色
  • 座標轉換:樹控件邏輯座標 → 客戶區實體座標需扣除捲軸偏移 GetScrollPos(SB_VERT/HORZ)

計算可視區域與捲軸同步

void CTreeCtrlBT::Calculate() {
    // 取得客戶區矩形 m_rectClient
    // 計算所有節點總高度 → 設定垂直捲軸範圍 SetScrollInfo(SB_VERT, ...)
    // 計算最寬節點寬度 → 設定水平捲軸範圍
    // 記錄首個可見節點索引、可見節點數
}

參考資源與致謝

開發過程參考了 CodeProject 上 VividTree 專案的部分思路:
https://www.codeproject.com/KB/tree/VividTree.aspx

總結

CTreeCtrlBT 透過完全接管 WM_PAINT,實現了高度可定制的樹型導航視覺效果。核心難點在於:

  1. 節點資料與視覺屬性分離儲存 (map)
  2. 捲軸座標與邏輯節點索引同步
  3. 透明位圖繪製 (TransparentBlt + msimg32.lib)
  4. 漸層填充 (GradientFill / TRIVERTEX)

此控件可直接整合至 MFC 專案,支援資源式與檔案式圖片載入,適合需要強品牌視覺識別的導航介面開發。

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