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

CListBox 智慧型水平捲軸:CDJListBox 衍生類自動追蹤最寬字串並顯示/隱藏捲軸

     編輯:關於C語言

問題背景

標準 CListBox 垂直捲軸會自動出現/隱藏並調整大小,但**水平捲軸不會自動管理**。當加入超寬字串或垂直捲軸出現壓縮客戶區寬度時,水平捲軸不自動出現,導致內容被截斷無法檢視。

解決方案:衍生 CDJListBox 覆寫關鍵函式

1. 成員變數


class CDJListBox : public CListBox {
    int m_nMaxExtent;      // 追蹤最大字串像素寬度
    CFont* m_pFont;        // 當前字型指標 (為了應對字型變更)
    // ...
};

2. 覆寫 AddString/InsertString/DeleteString/ResetContent


int CDJListBox::AddString(LPCTSTR lpszItem) {
    int nResult = CListBox::AddString(lpszItem);
    if (nResult >= 0) UpdateHorizontalExtent(lpszItem);
    return nResult;
}

int CDJListBox::InsertString(int nIndex, LPCTSTR lpszItem) {
    int nResult = CListBox::InsertString(nIndex, lpszItem);
    if (nResult >= 0) UpdateHorizontalExtent(lpszItem);
    return nResult;
}

void CDJListBox::DeleteString(UINT nIndex) {
    CString str;
    GetText(nIndex, str); // 刪除前取得文字
    CListBox::DeleteString(nIndex);
    // 刪除可能是最寬字串,需重新掃描全表
    RecalcHorizontalExtent();
}

void CDJListBox::ResetContent() {
    CListBox::ResetContent();
    m_nMaxExtent = 0;
    SetHorizontalExtent(0);
}

3. 核心計算函式 UpdateHorizontalExtent


void CDJListBox::UpdateHorizontalExtent(LPCTSTR lpszText) {
    CClientDC dc(this);
    CFont* pOldFont = dc.SelectObject(GetFont()); // 使用列表框當前字型
    CSize sz = dc.GetTextExtent(lpszText);
    dc.SelectObject(pOldFont);

    // 加上邊界間距 (左右各 3-4 像素)
    int nExtent = sz.cx + 8;

    if (nExtent > m_nMaxExtent) {
        m_nMaxExtent = nExtent;
        SetHorizontalExtent(m_nMaxExtent); // 觸發水平捲軸顯示/調整
    }
}

void CDJListBox::RecalcHorizontalExtent() {
    m_nMaxExtent = 0;
    CClientDC dc(this);
    CFont* pOldFont = dc.SelectObject(GetFont());
    for (int i = 0; i < GetCount(); ++i) {
        CString str; GetText(i, str);
        CSize sz = dc.GetTextExtent(str);
        m_nMaxExtent = max(m_nMaxExtent, sz.cx + 8);
    }
    dc.SelectObject(pOldFont);
    SetHorizontalExtent(m_nMaxExtent);
}

4. 處理字型變更 (WM_SETFONT)


void CDJListBox::OnSetFont(CFont* pFont, BOOL bRedraw) {
    CListBox::OnSetFont(pFont, bRedraw);
    m_pFont = pFont;
    if (bRedraw) RecalcHorizontalExtent(); // 字型變更需重新計算所有項目寬度
}

5. 處理垂直捲軸出現/消失影響寬度 (OnSize)


void CDJListBox::OnSize(UINT nType, int cx, int cy) {
    CListBox::OnSize(nType, cx, cy);
    // 垂直捲軸出現會減少客戶區寬度,可能需要水平捲軸
    // 這裡可選擇強制重新計算或依賴 SetHorizontalExtent 自動處理
    // 若發現內容被截斷,可呼叫 RecalcHorizontalExtent()
}

使用方式

  1. 專案加入 DJListBox.h/.cpp。
  2. 對話框編輯器放置 List Box 控制項,ID 為 IDC_LIST。
  3. 類別精靈新增控制項變數,類型選 CDJListBox (而非 CListBox),變數名 m_list。
  4. 正常使用 m_list.AddString(...),水平捲軸將自動管理。

進階優化

  • 效能: 大量項目 (萬筆以上) 每次 AddString 計算 GetTextExtent 可能較慢。可延遲計算 (標記 dirty flag,OnPaint 或定時器批次更新)。
  • Unicode/雙位元組字元: GetTextExtent 正確處理。
  • 製表符 (\t): GetTextExtent 視為單一字元寬度,若需對齊需自行展開或使用 DrawText DT_EXPANDTABS 計算。
  • 搭配 LBS_OWNERDRAWVARIABLE: 需在 MeasureItem 中同步更新項目寬度邏輯。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved