開發除錯工具或程式碼編輯器時,左側邊欄顯示行號與斷點標記是基本需求。MFC 的 `CEditView` 預設不支援此功能。本文示範如何繼承 `CEditView`,利用左邊距繪製行號與紅色斷點圓點,並處理滑鼠點擊切換斷點、熱鍵(F9)切換當前行斷點、捲動同步重繪等核心邏輯,打造輕量級程式碼編輯視窗。
void CMyEditView::OnInitialUpdate()
{
CEditView::OnInitialUpdate();
CEdit& edit = GetEditCtrl();
SIZE sz;
GetTextExtentPoint32(GetDC()->GetSafeHdc(), _T("A"), 1, &sz);
m_nLineHeight = sz.cy; // 行高
// 左邊距 = 行高 + 6 像素緩衝,足夠畫行號與斷點
edit.SetMargins(m_nLineHeight + 6, 0);
edit.SetLimitText(10 * 1024); // 限制 10KB
}
使用 `std::list
#include
typedef std::list IntList;
IntList m_lstBreakPoints;
void AddRemoveBreakPoint(int nLine)
{
IntList::iterator it = std::find(m_lstBreakPoints.begin(), m_lstBreakPoints.end(), nLine);
if (it != m_lstBreakPoints.end())
m_lstBreakPoints.erase(it); // 已存在 → 移除
else
m_lstBreakPoints.push_back(nLine); // 新增
}
void CMyEditView::PaintLeftMargin()
{
CEdit& edit = GetEditCtrl();
CDC* pDC = GetWindowDC(); // 整個視窗 DC,含非客戶區
CRect rcClient;
GetClientRect(&rcClient);
// 1. 填充背景色(淺黃)
CBrush brushBkg(RGB(245, 245, 230));
CRect rcMargin(rcClient.left + 2, rcClient.top + 2,
rcClient.left + m_nLineHeight + 7, rcClient.bottom + 2);
pDC->FillRect(&rcMargin, &brushBkg);
// 2. 取得第一可見行
int nFirstVis = edit.GetFirstVisibleLine();
// 3. 繪製斷點紅圓
CBrush brushRed(RGB(255, 0, 0));
CBrush* pOldBrush = pDC->SelectObject(&brushRed);
for (int line : m_lstBreakPoints)
{
if (line > nFirstVis)
{
int y = (line - 1 - nFirstVis) * m_nLineHeight + 3;
if (y < rcClient.bottom - m_nLineHeight)
{
// 畫圓:左上 (left+5, y) 右下 (left+lineH+4, y+lineH)
pDC->Ellipse(rcClient.left + 5, y,
rcClient.left + m_nLineHeight + 4, y + m_nLineHeight);
}
}
}
pDC->SelectObject(pOldBrush);
ReleaseDC(pDC);
}
void CMyEditView::OnLButtonDown(UINT nFlags, CPoint point)
{
if (point.x < m_nLineHeight + 6) // 點擊在左邊距區域
{
CEdit& edit = GetEditCtrl();
// 將點擊座標轉為字元索引,再取行號
point.x += 20; // 微調補償邊距
int nChar = edit.CharFromPos(point);
int nLine = HIWORD(nChar) + 1; // 1-based
AddRemoveBreakPoint(nLine);
PaintLeftMargin(); // 立即重繪
return;
}
CEditView::OnLButtonDown(nFlags, point);
}
BOOL CMyEditView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (nID == ID_EDIT_TOGGLE_BREAKPOINT && nCode == CN_COMMAND) // 對應資源中定義的 F9 命令
{
CEdit& edit = GetEditCtrl();
int nLine = edit.LineFromChar(-1) + 1; // 當前游標行
AddRemoveBreakPoint(nLine);
PaintLeftMargin();
return TRUE;
}
return CEditView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
void CMyEditView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CEditView::OnVScroll(nSBCode, nPos, pScrollBar);
PaintLeftMargin();
}
void CMyEditView::OnSize(UINT nType, int cx, int cy)
{
CEditView::OnSize(nType, cx, cy);
PaintLeftMargin();
}
void CMyEditView::OnPaint()
{
CPaintDC dc(this);
CEditView::OnPaint();
PaintLeftMargin(); // 確保邊欄隨內容重繪
}

左側顯示行號區域背景,紅色圓點標示斷點,點擊切換,F9 熱鍵生效,捲動時斷點位置自動追隨。
僅繼承 `CEditView`、覆寫少量訊息處理,即可實現專業級編輯器的斷點邊欄核心功能。本範例代碼精簡、邏輯清晰,適合作為自訂編輯器、腳本除錯工具、教學用 IDE 的起始架構。關鍵在於:預留左邊距、維護行號集合、捲動同步重繪三大原則。