在MFC中用c++设计一个简单画图程序。要求能擦出所画的内容。并给出详细代码。并且有具体操作步骤。可以让一个新手简单操作成功
时间: 2023-07-16 15:13:41 浏览: 173
以下是一个简单的 MFC 画图程序,支持绘制直线、矩形、椭圆和自由曲线,并且支持擦除功能。
1. 创建一个 MFC 应用程序,命名为 "MyPaint"。
2. 在 "MyPaintView.h" 文件中添加如下代码:
```c++
class CMyPaintView : public CView
{
protected: // 仅从序列化创建
CMyPaintView() noexcept;
DECLARE_DYNCREATE(CMyPaintView)
// 特性
public:
CMyPaintDoc* GetDocument() const;
// 操作
public:
// 重写
public:
virtual void OnDraw(CDC* pDC); // 重写以绘制该视图
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
// 实现
public:
virtual ~CMyPaintView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
BOOL m_bDrawing;
CPoint m_ptOrigin;
CPoint m_ptPrev;
int m_nShapeType;
CObArray m_shapeList;
int m_nLineWidth;
COLORREF m_crLineColor;
BOOL m_bEraser;
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnLine();
afx_msg void OnRect();
afx_msg void OnEllipse();
afx_msg void OnFree();
afx_msg void OnLineWidth();
afx_msg void OnLineColor();
afx_msg void OnEraser();
afx_msg void OnUpdateLine(CCmdUI* pCmdUI);
afx_msg void OnUpdateRect(CCmdUI* pCmdUI);
afx_msg void OnUpdateEllipse(CCmdUI* pCmdUI);
afx_msg void OnUpdateFree(CCmdUI* pCmdUI);
afx_msg void OnUpdateLineWidth(CCmdUI* pCmdUI);
afx_msg void OnUpdateLineColor(CCmdUI* pCmdUI);
afx_msg void OnUpdateEraser(CCmdUI* pCmdUI);
DECLARE_MESSAGE_MAP()
};
```
3. 在 "MyPaintView.cpp" 文件中添加如下代码:
```c++
IMPLEMENT_DYNCREATE(CMyPaintView, CView)
BEGIN_MESSAGE_MAP(CMyPaintView, CView)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_COMMAND(ID_SHAPE_LINE, &CMyPaintView::OnLine)
ON_COMMAND(ID_SHAPE_RECT, &CMyPaintView::OnRect)
ON_COMMAND(ID_SHAPE_ELLIPSE, &CMyPaintView::OnEllipse)
ON_COMMAND(ID_SHAPE_FREE, &CMyPaintView::OnFree)
ON_COMMAND(ID_LINE_WIDTH, &CMyPaintView::OnLineWidth)
ON_COMMAND(ID_LINE_COLOR, &CMyPaintView::OnLineColor)
ON_COMMAND(ID_ERASER, &CMyPaintView::OnEraser)
ON_UPDATE_COMMAND_UI(ID_SHAPE_LINE, &CMyPaintView::OnUpdateLine)
ON_UPDATE_COMMAND_UI(ID_SHAPE_RECT, &CMyPaintView::OnUpdateRect)
ON_UPDATE_COMMAND_UI(ID_SHAPE_ELLIPSE, &CMyPaintView::OnUpdateEllipse)
ON_UPDATE_COMMAND_UI(ID_SHAPE_FREE, &CMyPaintView::OnUpdateFree)
ON_UPDATE_COMMAND_UI(ID_LINE_WIDTH, &CMyPaintView::OnUpdateLineWidth)
ON_UPDATE_COMMAND_UI(ID_LINE_COLOR, &CMyPaintView::OnUpdateLineColor)
ON_UPDATE_COMMAND_UI(ID_ERASER, &CMyPaintView::OnUpdateEraser)
END_MESSAGE_MAP()
CMyPaintView::CMyPaintView() noexcept
{
m_bDrawing = FALSE;
m_ptOrigin = CPoint(0, 0);
m_ptPrev = CPoint(0, 0);
m_nShapeType = SHAPE_LINE;
m_nLineWidth = 1;
m_crLineColor = RGB(0, 0, 0);
m_bEraser = FALSE;
}
CMyPaintView::~CMyPaintView()
{
}
BOOL CMyPaintView::PreCreateWindow(CREATESTRUCT& cs)
{
return CView::PreCreateWindow(cs);
}
void CMyPaintView::OnDraw(CDC* pDC)
{
CMyPaintDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
for (int i = 0; i < m_shapeList.GetSize(); i++)
{
CShape* pShape = (CShape*)m_shapeList.GetAt(i);
pShape->Draw(pDC);
}
}
#ifdef _DEBUG
void CMyPaintView::AssertValid() const
{
CView::AssertValid();
}
void CMyPaintView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CMyPaintDoc* CMyPaintView::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyPaintDoc)));
return (CMyPaintDoc*)m_pDocument;
}
#endif //_DEBUG
void CMyPaintView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bDrawing = TRUE;
m_ptOrigin = point;
m_ptPrev = point;
CClientDC dc(this);
if (m_bEraser)
{
dc.PatBlt(point.x - 10, point.y - 10, 20, 20, WHITENESS);
SetCapture();
}
}
void CMyPaintView::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bDrawing)
return;
CClientDC dc(this);
CPen pen(m_bEraser ? PS_SOLID : PS_DOT, m_nLineWidth, m_bEraser ? RGB(255, 255, 255) : m_crLineColor);
CPen* pOldPen = dc.SelectObject(&pen);
dc.SetROP2(R2_NOTXORPEN);
switch (m_nShapeType)
{
case SHAPE_LINE:
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptPrev);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptPrev = point;
break;
case SHAPE_RECT:
dc.Rectangle(m_ptOrigin.x, m_ptOrigin.y, m_ptPrev.x, m_ptPrev.y);
dc.Rectangle(m_ptOrigin.x, m_ptOrigin.y, point.x, point.y);
m_ptPrev = point;
break;
case SHAPE_ELLIPSE:
dc.Ellipse(m_ptOrigin.x, m_ptOrigin.y, m_ptPrev.x, m_ptPrev.y);
dc.Ellipse(m_ptOrigin.x, m_ptOrigin.y, point.x, point.y);
m_ptPrev = point;
break;
case SHAPE_FREE:
dc.MoveTo(m_ptPrev);
dc.LineTo(point);
m_ptPrev = point;
break;
default:
break;
}
dc.SelectObject(pOldPen);
}
void CMyPaintView::OnLButtonUp(UINT nFlags, CPoint point)
{
if (!m_bDrawing)
return;
CClientDC dc(this);
CPen pen(m_bEraser ? PS_SOLID : PS_DOT, m_nLineWidth, m_bEraser ? RGB(255, 255, 255) : m_crLineColor);
CPen* pOldPen = dc.SelectObject(&pen);
dc.SetROP2(R2_COPYPEN);
switch (m_nShapeType)
{
case SHAPE_LINE:
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptPrev);
dc.LineTo(point);
break;
case SHAPE_RECT:
dc.Rectangle(m_ptOrigin.x, m_ptOrigin.y, m_ptPrev.x, m_ptPrev.y);
dc.Rectangle(m_ptOrigin.x, m_ptOrigin.y, point.x, point.y);
break;
case SHAPE_ELLIPSE:
dc.Ellipse(m_ptOrigin.x, m_ptOrigin.y, m_ptPrev.x, m_ptPrev.y);
dc.Ellipse(m_ptOrigin.x, m_ptOrigin.y, point.x, point.y);
break;
case SHAPE_FREE:
dc.MoveTo(m_ptPrev);
dc.LineTo(point);
break;
default:
break;
}
dc.SelectObject(pOldPen);
if (m_bEraser)
{
ReleaseCapture();
}
else
{
CShape* pShape = NULL;
switch (m_nShapeType)
{
case SHAPE_LINE:
pShape = new CLine(m_ptOrigin, point, m_nLineWidth, m_crLineColor);
break;
case SHAPE_RECT:
pShape = new CRectShape(m_ptOrigin, point, m_nLineWidth, m_crLineColor);
break;
case SHAPE_ELLIPSE:
pShape = new CEllipse(m_ptOrigin, point, m_nLineWidth, m_crLineColor);
break;
case SHAPE_FREE:
pShape = new CPolyline(m_ptPrev, point, m_nLineWidth, m_crLineColor);
break;
default:
break;
}
if (pShape)
{
m_shapeList.Add(pShape);
}
}
m_bDrawing = FALSE;
}
void CMyPaintView::OnLine()
{
m_nShapeType = SHAPE_LINE;
}
void CMyPaintView::OnRect()
{
m_nShapeType = SHAPE_RECT;
}
void CMyPaintView::OnEllipse()
{
m_nShapeType = SHAPE_ELLIPSE;
}
void CMyPaintView::OnFree()
{
m_nShapeType = SHAPE_FREE;
}
void CMyPaintView::OnLineWidth()
{
CLineWidthDlg dlg(m_nLineWidth);
if (dlg.DoModal() == IDOK)
{
m_nLineWidth = dlg.GetLineWidth();
}
}
void CMyPaintView::OnLineColor()
{
CColorDialog dlg(m_crLineColor);
if (dlg.DoModal() == IDOK)
{
m_crLineColor = dlg.GetColor();
}
}
void CMyPaintView::OnEraser()
{
m_bEraser = !m_bEraser;
}
void CMyPaintView::OnUpdateLine(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_nShapeType == SHAPE_LINE);
}
void CMyPaintView::OnUpdateRect(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_nShapeType == SHAPE_RECT);
}
void CMyPaintView::OnUpdateEllipse(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_nShapeType == SHAPE_ELLIPSE);
}
void CMyPaintView::OnUpdateFree(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_nShapeType == SHAPE_FREE);
}
void CMyPaintView::OnUpdateLineWidth(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!m_bEraser);
}
void CMyPaintView::OnUpdateLineColor(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!m_bEraser);
}
void CMyPaintView::OnUpdateEraser(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_bEraser);
}
```
4. 在 "MyPaintDoc.h" 文件中添加如下代码:
```c++
class CMyPaintDoc : public CDocument
{
protected: // 仅从序列化创建
CMyPaintDoc() noexcept;
DECLARE_DYNCREATE(CMyPaintDoc)
// 特性
public:
// 操作
public:
// 重写
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
#ifdef SHARED_HANDLERS
virtual void InitializeSearchContent();
virtual void OnDrawThumbnail(CDC& dc, LPRECT lprcBounds);
#endif // SHARED_HANDLERS
// 实现
public:
virtual ~CMyPaintDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
};
```
5. 在 "MyPaintDoc.cpp" 文件中添加如下代码:
```c++
IMPLEMENT_DYNCREATE(CMyPaintDoc, CDocument)
BEGIN_MESSAGE_MAP(CMyPaintDoc, CDocument)
END_MESSAGE_MAP()
CMyPaintDoc::CMyPaintDoc() noexcept
{
}
CMyPaintDoc::~CMyPaintDoc()
{
}
BOOL CMyPaintDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
return TRUE;
}
void CMyPaintDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
}
else
{
}
}
#ifdef SHARED_HANDLERS
// 缩略图的绘制由实现此功能的程序负责。
void CMyPaintDoc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
{
// 修改此代码以绘制文档数据
dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));
CString strText = _T("TODO: implement thumbnail drawing here");
LOGFONT lf;
CFont* pOldFont = dc.SelectObject(&theApp.m_fontPrint);
lf = *theApp.m_fontPrint.GetLogFont();
lf.lfHeight = -12;
CFont font;
font.CreateFontIndirect(&lf);
CFont* pOldFont2 = dc.SelectObject(&font);
dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX);
dc.SelectObject(pOldFont);
dc.SelectObject(pOldFont2);
}
// 搜索处理程序的实现由实现此功能的程序负责。
void CMyPaintDoc::InitializeSearchContent()
{
CString strSearchContent;
// 从文档数据设置搜索内容。
// 以下内容不应包含任何未保存的信息、
// 临时信息或对话框字段。
strSearchContent = _T("TODO: implement searchable content in the document");
SetSearchContent(strSearchContent);
}
void CMyPaintDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_SHARED_HANDLERS
```
6. 在 "MyPaint.h" 文件中添加如下代码:
```c++
class CMyPaintApp : public CWinApp
{
public:
CMyPaintApp() noexcept;
// 重写
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
// 实现
public:
afx_msg void OnAppAbout();
DECLARE_MESSAGE_MAP()
private:
CFont m_fontPrint;
};
extern CMyPaintApp theApp;
```
7. 在 "MyPaint.cpp" 文件中添加如下代码:
```c++
CMyPaintApp theApp;
BEGIN_MESSAGE_MAP(CMyPaintApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, &CMyPaintApp::OnAppAbout)
END_MESSAGE_MAP()
CMyPaintApp::CMyPaintApp() noexcept
{
}
BOOL CMyPaintApp::InitInstance()
{
// 初始化 MFC 和打印机并初始化应用程序字体
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
// 创建应用程序字体
LOGFONT lf;
memset(&lf, 0, sizeof(lf));
lf.lfHeight = 12;
lf.lfWeight = FW_NORMAL;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
_tcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Arial"));
m_fontPrint.CreateFontIndirect(&lf);
// 初始化标准文档管理器
// TODO: 可以根据应用程序的特定需要添加一些附加的文档类型。 例如:
// CMultiDocTemplate* pDocTemplate;
// pDocTemplate = new CMultiDocTemplate(IDR_MyPaintTYPE,
// RUNTIME_CLASS(CMyPaintDoc),
// RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
// RUNTIME_CLASS(CMyPaintView));
// if (!pDocTemplate)
// return FALSE;
// AddDocTemplate(pDocTemplate);
// 分析标准 SHELL 命令、DDE、打开文件操作
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// 分析标准 shell 命令、DDE、打开文件操作命令行
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 主窗口已初始化,因此显示它并对其进行更新
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
int CMyPaintApp::ExitInstance()
{
AfxOleTerm(FALSE);
return CWinApp::ExitInstance();
}
//“关于”菜单命令
void CMyPaintApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
```
8. 添加 "MyPaint.rc" 资源文件,并在其中添加菜单、工具栏和对话框资源。
9. 运行程序,即可看到一个简单的画图程序。通过选择不同的绘图形
阅读全文