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

VC++ 實作類似 Visual Studio 編輯器的斷點邊欄與行號顯示

     編輯:VC 教學

前言

開發除錯工具或程式碼編輯器時,左側邊欄顯示行號與斷點標記是基本需求。MFC 的 `CEditView` 預設不支援此功能。本文示範如何繼承 `CEditView`,利用左邊距繪製行號與紅色斷點圓點,並處理滑鼠點擊切換斷點、熱鍵(F9)切換當前行斷點、捲動同步重繪等核心邏輯,打造輕量級程式碼編輯視窗。

一、建立專案與基礎設定

  1. AppWizard 建立 **SDI** 專案,視圖類別選 **CEditView**。
  2. 在 `OnInitialUpdate()` 設定左邊距預留繪製空間並取得行高:
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` 儲存已設定斷點的行號(1-based):

#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);
}

四、關鍵訊息處理

1. 滑鼠左鍵點擊邊欄切換斷點

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);
}

2. 熱鍵 F9 切換當前行斷點

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);
}

3. 捲動、視窗大小變更、覆寫時重繪邊欄


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 熱鍵生效,捲動時斷點位置自動追隨。

六、擴充建議

  • 行號文字繪製:在 `PaintLeftMargin` 中加入 `TextOut` 繪製行號,需計算寬度動態調整 `SetMargins`。
  • 語法高亮:需改用 `CRichEditView` 或自行實作 `OnDraw` 逐行解析上色。
  • 書籤/錯誤標記:擴充 `m_lstBreakPoints` 為結構體,包含類型(斷點/書籤/錯誤)與顏色。
  • 高 DPI:使用 `GetDeviceCaps(LOGPIXELSX)` 縮放行高與邊距。

七、結語

僅繼承 `CEditView`、覆寫少量訊息處理,即可實現專業級編輯器的斷點邊欄核心功能。本範例代碼精簡、邏輯清晰,適合作為自訂編輯器、腳本除錯工具、教學用 IDE 的起始架構。關鍵在於:預留左邊距、維護行號集合、捲動同步重繪三大原則。

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