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

MFC 仿 Windows 畫圖板完整實作:繪圖、撤銷重做、縮放、工具箱、調色盤

     編輯:關於VC++

專案簡介

完整複刻 Windows 畫圖板核心功能:自由筆刷、直線/矩形/橢圓、文字輸入、圖塊拖放、多級撤銷重做、畫面縮放、檔案讀存、Base64 圖片介面、工具箱雙欄、調色盤。架構採用 CScrollView + 文檔/視圖,繪圖物件導向設計,適合作為 MFC 繪圖應用教學範本。

核心繪圖架構

圖元基類與具體類別

class CDrawObject : public CObject { // 基類
    virtual void Draw(CDC* pDC) = 0;
    CRect m_rect; // 外接矩形
};

class CDrawPen : public CDrawObject { // 筆/刷 - 手繪折線
    CArray m_points;
    int m_nWidth; COLORREF m_color;
};

class CDrawShape : public CDrawObject { // 幾何圖形
    int m_nShapeType; // 直線/矩形/橢圓...
    int m_nWidth; COLORREF m_color; BOOL m_bFilled;
};

class CDrawText : public CDrawObject { // 文字
    CString m_str; LOGFONT m_lf; COLORREF m_color;
};

文檔類 CDrawDoc 持有 CObList m_objects 管理所有圖元。

雙重緩衝防閃爍

// 1. 禁止系統擦除背景
BOOL CMyView::OnEraseBkgnd(CDC* pDC) { return TRUE; }

// 2. OnDraw 先畫到記憶體 DC
void CMyView::OnDraw(CDC* pDC)
{
    CMemDC memDC(pDC, &rectClip); // RAII 記憶體 DC 包裝類
    memDC.FillSolidRect(rectClip, RGB(255,255,255)); // 白底
    for (pos = m_objects.GetHeadPosition(); pos; )
        m_objects.GetNext(pos)->Draw(&memDC);
    // 尚未確認的暫時圖元 (滑鼠拖曳中) 另行繪製
    if (m_pTempObj) m_pTempObj->Draw(&memDC);
    // CMemDC 解構時自動 BitBlt 回螢幕
}

滑鼠互動流程

事件處理邏輯
OnLButtonDown建立對應圖元物件 (根據當前工具),記錄起始點,加入暫時物件指標
OnMouseMove更新暫時物件幾何資料 (終點/矩形/路徑),Invalidate() 觸發重繪
OnLButtonUp最終化暫時物件,移入文檔正式列表,清空暫時指標,推入撤銷堆疊

多級撤銷/重做實作

class CUndoStack {
    CArray m_history; // 歷史畫面快照 (位圖句柄)
    int m_top;                 // 當前指標
public:
    void PushSnapshot(CDC* pDC, CRect rect) {
        // 截取當前畫面存入位圖
        if (m_top < m_history.GetSize()-1) m_history.RemoveAt(m_top+1, m_history.GetSize()-m_top-1);
        // ... 建立相容位圖、BitBlt 複製 ...
        m_history.Add(hBmp); m_top++;
    }
    HBITMAP Undo() { if (m_top > 0) return m_history[--m_top]; return NULL; }
    HBITMAP Redo() { if (m_top < m_history.GetSize()-1) return m_history[++m_top]; return NULL; }
};

策略:每次筆劃結束存一張全畫面快照。簡單但記憶體隨畫面大小/步數增長。大型專案建議改用 命令模式 (記錄動作而非影像)。

縮放實作:修改 CScrollView 映射模式

CScrollView 預設 MM_TEXT 不支援 SetViewportExt/WindowExt。解法:複製 MFC 原始碼 CScrollView::SetScrollSizes 修改為 MM_ISOTROPIC,封裝為 CADMMScrollView。

void CADMMScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
    CScrollView::OnPrepareDC(pDC, pInfo);
    pDC->SetMapMode(MM_ISOTROPIC);
    int xMm = pDC->GetDeviceCaps(HORZSIZE);
    int yMm = pDC->GetDeviceCaps(VERTSIZE);
    int xPix = pDC->GetDeviceCaps(HORZRES);
    int yPix = pDC->GetDeviceCaps(VERTRES);
    pDC->SetWindowExt(xMm * 100, yMm * 100);
    pDC->SetViewportExt((int)(xPix * m_fZoom), (int)(yPix * m_fZoom));
}

縮放因子 m_fZoom 由工具列按鈕/滑鼠滾輪調整,調整後呼叫 SetScrollSizes 更新捲軸範圍並 Invalidate()。

工具箱 CToolPaletteBar (CToolBar 派生)

  • 按鈕雙欄:設定 TBBS_WRAPPED 樣式於第二欄第一個按鈕。
  • 工具選項面板:工具列上嵌入 CListCtrl (圖示檢視),切換工具時更新列表內容 (如選直線 → 顯示粗細樣式圖示)。
  • 狀態同步:工具箱按鈕按下/彈起狀態與視圖當前工具雙向綁定。

調色盤 CColorPaletteBar (CDialogBar 派生)

  • OnPaint 手繪 16x16 色塊網格 (系統 20 色 + 自訂)。
  • OnLButtonDown:左鍵設前景色,右鍵設背景色,雙擊彈出 CColorDialog 自訂。
  • 色塊邊框高亮顯示當前選中前景/背景色。

游標樣式動態切換

BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (nHitTest == HTCLIENT) // 僅客戶區改游標
    {
        switch (m_currentTool)
        {
            case TOOL_PEN: SetCursor(LoadCursor(NULL, IDC_PENCIL)); break;
            case TOOL_LINE: SetCursor(LoadCursor(NULL, IDC_CROSS)); break;
            case TOOL_TEXT: SetCursor(LoadCursor(NULL, IDC_IBEAM)); break;
            // ...
        }
        return TRUE;
    }
    return CScrollView::OnSetCursor(pWnd, nHitTest, message);
}

Base64 圖片介面 (資料庫/XML 儲存需求)

// 位圖 → Base64 字串
CString BitmapToBase64(HBITMAP hBmp)
{
    // GetDIBits 取得位元資料 → Base64 編碼 (CryptBinaryToString 或自實現)
}

// Base64 字串 → 位圖
HBITMAP Base64ToBitmap(const CString& b64)
{
    // Base64 解碼 → CreateDIBitmap
}

功能對比表

功能本程式Windows 畫圖板備註
基本繪圖工具✅✅
文字輸入 (字型/顏色可設)✅✅本程式支援任意字型
多級撤銷/重做✅❌ (僅 1 步)本程式優勢
縮放 (滑鼠滾輪/工具列)✅✅
Base64 介面✅❌資料庫/XML 整合用
圖塊拖放✅✅

結語

本專案展示 MFC 文檔/視圖架構下完整繪圖應用的工程實踐:圖元物件導向、雙重緩衝、命令快照式撤銷、映射模式縮放、工具箱/調色盤自繪控制項、游標管理、Base64 序列化。代碼結構清晰,可直接作為專案起始模板或教學案例。

本文配套原始碼可供下載。

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