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

打造可編輯的 MSFlexGrid 表格控件:視覺假象法實作全解析

     編輯:VC 教學

前言

MSFlexGrid 是經典的唯讀表格控件,若需支援儲存格編輯,常見做法是「視覺假象法」:在使用者點擊儲存格時,精準疊加一個 CEdit 或 CComboBox 控件於儲存格上方,編輯完成後將內容寫回並隱藏控件。本文完整解析此技術的座標換算、控件切換、焦點管理等關鍵細節。

核心架構與成員變數


class CChartInfoEditDlg : public CDialog
{
    // 隱藏的編輯控件,初始不可見
    CEdit       m_EditCtrl;        // 文字編輯
    CComboBox   m_ComboCtrl;       // 下拉選單編輯
    CString     m_strEditText;     // 與 CEdit 關聯的 DDX 變數
    MSFlexGrid  m_Grid;            // 表格控件
    // ... 其他變數
};

關鍵步驟:儲存格座標精準換算 (Twips 轉 Pixel)

MSFlexGrid 內部座標單位為 Twips (1/1440 英吋),必須轉換為螢幕像素才能正確定位疊加控件。


void CChartInfoEditDlg::OnClickGrid()
{
    long lRow = m_Grid.GetRowSel();
    long lCol = m_Grid.GetColSel();

    // 1. 邊界檢查:忽略標題列 (Row 0) 與超出資料範圍的點擊
    if (lRow == 0 || lRow > m_MaxDataRow) return;

    // 2. 取得 Grid 視窗矩形 (螢幕座標) -> 轉為用戶區座標
    CRect rcGrid;
    m_Grid.GetWindowRect(&rcGrid);
    ScreenToClient(&rcGrid);

    // 3. 計算 Twips -> Pixel 轉換比例
    CDC* pDC = GetDC();
    int nTwipsPerPixelX = 1440 / pDC->GetDeviceCaps(LOGPIXELSX);
    int nTwipsPerPixelY = 1440 / pDC->GetDeviceCaps(LOGPIXELSY);
    ReleaseDC(pDC);

    // 4. 計算目標儲存格左上角與寬高 (像素)
    long x = m_Grid.GetColPos(lCol) / nTwipsPerPixelX;
    long y = m_Grid.GetRowPos(lRow) / nTwipsPerPixelY;
    long w = m_Grid.GetColWidth(lCol) / nTwipsPerPixelX + 1; // +1 修正邊界
    long h = m_Grid.GetRowHeight(lRow) / nTwipsPerPixelY + 1;

    // 5. 形成相對對話框的矩形區域
    CRect rcCell(x, y, x + w, y + h);
    rcCell.OffsetRect(rcGrid.left + 1, rcGrid.top + 1); // 微調對齊

    // 6. 取得儲存格現有文字
    CString strCellText = m_Grid.GetTextMatrix(lRow, lCol);

    // 7. 依欄位屬性決定使用 CEdit 或 CComboBox (此處略過判斷邏輯)
    bool useCombo = ShouldUseComboBox(lCol); // 自訂判斷函式

    if (useCombo)
    {
        m_ComboCtrl.ResetContent();
        FillComboBoxItems(lCol, m_ComboCtrl); // 填入選項
        m_ComboCtrl.MoveWindow(&rcCell);
        m_ComboCtrl.SelectString(-1, strCellText);
        m_ComboCtrl.ShowWindow(SW_SHOW);
        m_ComboCtrl.SetFocus();
        m_EditCtrl.ShowWindow(SW_HIDE);
    }
    else
    {
        m_EditCtrl.MoveWindow(&rcCell);
        m_EditCtrl.SetWindowText(strCellText);
        m_EditCtrl.SetSel(0, -1); // 全選
        m_EditCtrl.ShowWindow(SW_SHOW);
        m_EditCtrl.SetFocus();
        m_ComboCtrl.ShowWindow(SW_HIDE);
    }
}

編輯完成後的資料回寫與控件隱藏

透過 EN_KILLFOCUS (CEdit) 與 CBN_KILLFOCUS (CComboBox) 訊息處理:


// CEdit 失去焦點
void CChartInfoEditDlg::OnKillFocusEdit()
{
    UpdateData(TRUE); // DDX 取得 m_strEditText
    m_Grid.SetTextMatrix(m_Grid.GetRowSel(), m_Grid.GetColSel(), m_strEditText);
    m_EditCtrl.ShowWindow(SW_HIDE);
    UpdateData(FALSE);
}

// CComboBox 失去焦點
void CChartInfoEditDlg::OnKillFocusCombo()
{
    CString str;
    m_ComboCtrl.GetWindowText(str);
    m_Grid.SetTextMatrix(m_Grid.GetRowSel(), m_Grid.GetColSel(), str);
    m_ComboCtrl.ShowWindow(SW_HIDE);
}

進階擴充建議

  • 多欄位多樣式:預建多組 CEdit/CComboBox/CDateTimeCtrl 等,依欄位型別動態切換。
  • 輸入驗證:在 OnKillFocus 中加入格式檢查 (數字、日期、長度),失敗時保持焦點並提示。
  • 鍵盤導航:處理 WM_KEYDOWN (Enter/Tab/Escape) 實現類 Excel 的儲存格跳轉體驗。
  • 效能優化:大量資料時採用虛擬模式或分頁載入,避免一次性填充導致卡頓。

常見坑點與避雷指南

問題原因解決方案
編輯控件位置偏移Twips/Pixel 換算遺漏、未考慮邊框/捲軸嚴格依照 GetColPos/GetRowPos 換算,並實測微調 +1 像素
焦點閃爍或無法輸入ShowWindow/Swap 控件順序錯誤、未呼叫 SetFocus先 MoveWindow 再 ShowWindow 再 SetFocus,確保 Z-Order 正確
ComboBox 選項不顯示未呼叫 ResetContent、或 Items 為空每次 OnClick 重新填充選項,確保內容最新
編輯後資料未寫回KillFocus 事件未正確映射、或 Grid 索引錯誤使用 GetRowSel()/GetColSel() 取得當前編輯儲存格

結語

「視覺假象法」雖非原生編輯支援,但實作彈性高、相容性好,是 MFC 時代延伸 MSFlexGrid 功能的經典方案。掌握座標換算、焦點管理、控件切換三大核心,即可輕鬆打造專業級可編輯表格。若專案允許,現代開發建議改用 CGridCtrl (CodeProject)、BCGControlBar 或 Qt/QML 等原生支援編輯的表格元件,開發效率更高。

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