MSFlexGrid 功能強大但預設唯讀。最簡單實現編輯的方法是視覺假象:滑鼠點選儲存格 → 在該位置精確覆蓋一個 CEdit 或 CComboBox → 編輯完成 → 寫回儲存格 → 隱藏控件。本文提供完整實作邏輯與程式碼。
// 對話框類別成員
CMSFlexGrid m_FlexGrid; // 表格控件
CEdit m_Edit; // 文字編輯控件 (初始不可見)
CComboBox m_Combo; // 下拉選擇控件 (初始不可見)
CString m_strEditText; // 與 m_Edit 關聯的 DDX 變數
void CMyDialog::OnClickFlexGrid()
{
long lRow = m_FlexGrid.GetRowSel();
long lCol = m_FlexGrid.GetColSel();
// 無效區域:標題列 (Row 0) 或超出資料範圍
if (lRow == 0 || lRow > m_nMaxDataRow) return;
// 1. 計算儲存格螢幕座標 (Twips → 像素)
CRect rectGrid;
m_FlexGrid.GetWindowRect(&rectGrid);
ScreenToClient(&rectGrid);
CDC* pDC = GetDC();
int nTwipsPerPixelX = 1440 / pDC->GetDeviceCaps(LOGPIXELSX);
int nTwipsPerPixelY = 1440 / pDC->GetDeviceCaps(LOGPIXELSY);
ReleaseDC(pDC);
long x = m_FlexGrid.GetColPos(lCol) / nTwipsPerPixelX;
long y = m_FlexGrid.GetRowPos(lRow) / nTwipsPerPixelY;
long w = m_FlexGrid.GetColWidth(lCol) / nTwipsPerPixelX + 1;
long h = m_FlexGrid.GetRowHeight(lRow) / nTwipsPerPixelY + 1;
CRect rcCell(x, y, x + w, y + h);
rcCell.OffsetRect(rectGrid.left + 1, rectGrid.top + 1); // 相對對話框座標
// 2. 取得儲存格現有文字
CString strValue = m_FlexGrid.GetTextMatrix(lRow, lCol);
// 3. 判斷該欄使用 Edit 還是 ComboBox (此處略過判斷邏輯)
// 假設第 1 欄用 ComboBox,其他用 Edit
m_Combo.ResetContent();
if (lCol == 1) {
m_Combo.AddString(_T("選項一"));
m_Combo.AddString(_T("選項二"));
m_Combo.AddString(_T("選項三"));
}
if (m_Combo.GetCount() > 0) {
// 使用 ComboBox
m_Combo.MoveWindow(&rcCell);
m_Combo.SelectString(-1, strValue);
m_Combo.SetFocus();
m_Combo.ShowWindow(SW_SHOW);
} else {
// 使用 Edit
m_Edit.MoveWindow(&rcCell);
m_Edit.SetWindowText(strValue);
m_Edit.SetSel(0, -1); // 全選
m_Edit.SetFocus();
m_Edit.ShowWindow(SW_SHOW);
}
// 記錄目前編輯的儲存格位置 (供失焦時寫回)
m_nEditingRow = lRow;
m_nEditingCol = lCol;
}
// Edit 失焦
void CMyDialog::OnKillfocusEdit()
{
UpdateData(TRUE); // DDX 取得 m_strEditText
m_FlexGrid.SetTextMatrix(m_nEditingRow, m_nEditingCol, m_strEditText);
m_Edit.ShowWindow(SW_HIDE);
UpdateData(FALSE);
}
// ComboBox 失焦
void CMyDialog::OnKillfocusCombo()
{
CString str;
m_Combo.GetWindowText(str);
m_FlexGrid.SetTextMatrix(m_nEditingRow, m_nEditingCol, str);
m_Combo.ShowWindow(SW_HIDE);
}
| 細節 | 處理方式 |
|---|---|
| Twips 單位轉換 | 1440 twips = 1 英吋,用 GetDeviceCaps(LOGPIXELSX/Y) 計算像素比 |
| 儲存格座標精確對齊 | GetColPos/RowPos、GetColWidth/RowHeight 取得 twips 座標 |
| 控件覆蓋順序 | MoveWindow 定位 → SetWindowText/SelectString 內容 → SetFocus → ShowWindow(SW_SHOW) |
| 全選方便修改 | Edit 用 SetSel(0,-1),Combo 用 SelectString(-1, str) |
| 失焦觸發寫回 | OnKillfocus 訊息對應 EN_KILLFOCUS/CBN_KILLFOCUS |
CEdit/CComboBox/CDateTimeCtrl 等,依欄位屬性切換。SetFocus 回編輯控件並提示。Enter/Tab/Esc 鍵在儲存格間移動。CListCtrl + LVS_EX_LABELTIP。「視覺假象」法以最小程式碼成本實現 MSFlexGrid 編輯功能,適合中小型表格編輯需求。核心在於Twips 座標精確轉換、控件即時覆蓋、失焦寫回三步驟。專案中可直接複製修改欄位判斷邏輯即用。