MFC 笔记(一) 简单绘图

看了孙鑫老师C++教授用MFC绘图的视频,学到了很多,此篇博客来做个小小的总结
首先建立一个 MFC 单文档或多文档应用程序(孙鑫老师在视频中用的是 VC ,我学的时候用的VS)
编译环境:VS 2010
MFC 应用程序
首先来个结果预览:

一、绘图

  1. 先在菜单栏上添加菜单项并更改ID号,我添加的如下图1所示:
    MFC 笔记(一) 简单绘图_第1张图片
  2. 然后再增加全局变量:
m_nform=-1;//标记要画什么
m_bDraw=false;//选中“钢笔"时,标记绘画开始与结束
m_ntool=0;//标记是文本还是图形
m_strLine="";
m_LineWidth=1;
m_LineStyle=0;
m_clr=RGB(0,0,0);

添加全局变量的时候可以在类视图中,在选中被添加的类,右键:
MFC 笔记(一) 简单绘图_第2张图片
可以选择添加变量,或者用类向导添加。

  1. 在刚才添加的菜单项上逐项右击添加事件处理程序如下图2所示:
    MFC 笔记(一) 简单绘图_第3张图片
void CGouHailong_ImageView::OnDrawfont()
{
	m_nform=0;
	m_ntool=1;
	CClientDC dc(this);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);
	CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);
	// TODO: 在此添加命令处理程序代码
}
void CGouHailong_ImageView::OnDrawpen()
{
	HideCaret();//隐藏光标
	m_ntool=0;
	m_nform=1;
	// TODO: 在此添加命令处理程序代码
}
void CGouHailong_ImageView::OnDrawpoint()
{
	// TODO: 在此添加命令处理程序代码
	m_nform=0;
	HideCaret();//隐藏光标
	m_ntool=0;
}
void CGouHailong_ImageView::OnDrawline()
{
	HideCaret();
	m_ntool=0;
	m_nform=2;
	// TODO: 在此添加命令处理程序代码
}
void CGouHailong_ImageView::OnDrawrect()
{
	HideCaret();
	m_ntool=0;
	m_nform=3;
	// TODO: 在此添加命令处理程序代码
}
void CGouHailong_ImageView::OnDrawellipse()
{
	// TODO: 在此添加命令处理程序代码
	HideCaret();//隐藏光标
	m_ntool=0;
	m_nform=4;
}
  1. 用类向导添加消息响应函数如下图3所示:
    MFC 笔记(一) 简单绘图_第4张图片
void CGouHailong_ImageView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	M_PtOrgin=point;
	if(m_ntool==0&&m_nform==1)
	{
		m_bDraw=true;
	}
	if(m_ntool==1)
	{
		SetCaretPos(point);
		m_strLine.Empty();
		ShowCaret();
	}
	CScrollView::OnLButtonDown(nFlags, point);
}
void CGouHailong_ImageView::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CClientDC dc(this);
	CPen *pen=new CPen(m_LineStyle,m_LineWidth,m_clr);//线型,宽度,颜色_堆中对象
	CBrush *pbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//构造空画刷

	CPen *pOldPen=dc.SelectObject(pen);
	CBrush *pOldBrush=dc.SelectObject(pbrush);
	switch(m_nform)
	{
	case 0://点
		{CPoint ptl=point,ptr=point,ptt=point,ptb=point;
		ptl.x-=5;ptr.x+=5;
		ptb.y-=5;ptt.y+=5;
		dc.MoveTo(ptl);dc.LineTo(ptr);
		dc.MoveTo(ptb);dc.LineTo(ptt);
		//dc.SetPixel(point,m_clr);
		//m_dcMetaFile.SetPixel(point,m_clr);
		break;}
	case 1://钢笔
		m_bDraw=false;
		break;
	case 2:
		dc.MoveTo(M_PtOrgin);
		dc.LineTo(point);
		break;
	case 3://矩形
		//dc.FillRect(CRect(M_PtOrgin,point),&brush);
		dc.Rectangle(CRect(M_PtOrgin,point));//直接画的话有遮挡,默认画刷是白色的
		break;
	case 4:
		dc.Ellipse(CRect(M_PtOrgin,point));
		//m_dcMetaFile.Ellipse(CRect(M_PtOrgin,point));
		break;
	}

	dc.SelectObject(pOldPen);
	dc.SelectObject(pOldBrush);
	CScrollView::OnLButtonUp(nFlags, point);
}
void CGouHailong_ImageView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if(m_ntool==1)
	{
		CClientDC dc(this);
		//font.CreatePointFont(200,"华文行楷",NULL);//创造一种文字类型
		CFont *pOldFont=dc.SelectObject(&m_font);
		TEXTMETRIC tm;
		dc.GetTextMetrics(&tm);
		/*
		HideCaret();
		CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);
		ShowCaret();*/
		if(0x0d==nChar)
		{//回车
			m_strLine.Empty();
			M_PtOrgin.y+=tm.tmHeight;
		}
		else if(0x08==nChar)
		{//backspace
			COLORREF clr=dc.SetTextColor(dc.GetBkColor());//将字体颜色设置为背景色,并保留原本颜色
			dc.TextOutA(M_PtOrgin.x,M_PtOrgin.y,m_strLine);//输出文字
			m_strLine=m_strLine.Left(m_strLine.GetLength()-1);//文本内容减一
			dc.SetTextColor(clr);//将原来的颜色还回去
		}
		else
		{
			m_strLine += (TCHAR)nChar;
		}

		CSize sz=dc.GetTextExtent(m_strLine);
		CPoint pt;
		pt.x=M_PtOrgin.x+sz.cx;
		pt.y=M_PtOrgin.y;

		SetCaretPos(pt);//移动光标位置
		dc.TextOutA(M_PtOrgin.x,M_PtOrgin.y,m_strLine);//输出文字
		//dc.SelectObject(pOldFont);
	}
	CScrollView::OnChar(nChar, nRepCnt, nFlags);
}
  1. 利用现成的类 CColorDialog 、CFontDialog 在“颜色”、“字体”菜单项右击添加事件处理程序:
void CGouHailong_ImageView::OnColor1()
{//更改颜色
	CColorDialog dlg;
	dlg.m_cc.Flags|=CC_RGBINIT;
	dlg.m_cc.rgbResult=m_clr;
	if(IDOK==dlg.DoModal())
	{
		m_clr=dlg.m_cc.rgbResult;
	}
}
void CGouHailong_ImageView::OnFont()
{//变换字体
	CFontDialog dlg;
	if(IDOK==dlg.DoModal())
	{
		if(m_font.m_hObject)
			m_font.DeleteObject();
		m_font.CreateFontIndirectA(dlg.m_cf.lpLogFont);
		m_fontName=dlg.m_cf.lpLogFont->lfFaceName;
		Invalidate();
	}
}

  1. 在资源视图->Dialog 中添加画笔设置的 dialog 如下图4所示
    MFC 笔记(一) 简单绘图_第5张图片
    需要将“实线”的属性"Group"改成true,这样三个radio button就成了一组的了。然后添加全局变量m_clr 和 与编辑框和radio关联的变量如下图5所示:
    MFC 笔记(一) 简单绘图_第6张图片
    在构造函数中给这些变量赋初值:
m_linewidth = 0;
m_lineStyle = -1;
m_clr=RGB(0,0,0);

添加相应的事件处理程序:

void ColorDlg::OnBnClickedZdyys()
{//实现窗口大小的变化
	CString str;
	if(GetDlgItemText(ID_ZDYYS,str),str=="自定义颜色<<收缩")
	{
		SetDlgItemText(ID_ZDYYS,"自定义颜色>>扩展");
	}
	else
	{
		SetDlgItemText(ID_ZDYYS,"自定义颜色<<收缩");
	}
	static CRect rectLarge;
	static CRect rectSmall;

	if(rectLarge.IsRectNull())
	{
		CRect rectS;
		GetWindowRect(&rectLarge);
		GetDlgItem(IDC_SEP)->GetWindowRect(&rectS);

		rectSmall.left=rectLarge.left;
		rectSmall.top=rectLarge.top;
		rectSmall.right=rectS.right;
		rectSmall.bottom=rectLarge.bottom;
	}
	if(str=="自定义颜色<<收缩")
	{
		SetWindowPos(NULL,0,0,rectSmall.Width(),rectSmall.Height(),
			SWP_NOMOVE|SWP_NOZORDER);
	}
	else
	{
		SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),
			SWP_NOMOVE|SWP_NOZORDER);
	}
}

void ColorDlg::OnChangeEdit1()
{
	// TODO:  如果该控件是 RICHEDIT 控件,它将不
	// 发送此通知,除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask(),
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。

	// TODO:  在此添加控件通知处理程序代码
	Invalidate();
}
void ColorDlg::OnClickedRadio1()
{
	// TODO: 在此添加控件通知处理程序代码
	Invalidate();
}
void ColorDlg::OnRadio2()
{
	// TODO: 在此添加命令处理程序代码
	Invalidate();
}
void ColorDlg::OnRadio3()
{
	// TODO: 在此添加命令处理程序代码
	Invalidate();
}
void ColorDlg::OnPaint()
{//实现线的预览
	CPaintDC dc(this); // device context for painting
	// TODO: 在此处添加消息处理程序代码
	UpdateData();
	CPen pen(m_lineStyle,m_linewidth,m_clr);
	dc.SelectObject(&pen);
	CRect rect;
	GetDlgItem(IDC_EXAMPLE)->GetWindowRect(&rect);
	ScreenToClient(&rect);
	dc.MoveTo(rect.left+20,rect.top+rect.Height()/2);
	dc.LineTo(rect.right-20,rect.top+rect.Height()/2);
	// 不为绘图消息调用 CDialogEx::OnPaint()
}

然后在回到view类中添加“画笔设置”菜单项的响应函数:

void CGouHailong_ImageView::OnPen()
{//设置画笔
	ColorDlg codlg;
	codlg.m_clr=m_clr;
	codlg.m_linewidth=m_LineWidth;
	codlg.m_lineStyle=m_LineStyle;
	if(IDOK==codlg.DoModal())
	{
		m_LineWidth=codlg.m_linewidth;
		m_LineStyle=codlg.m_lineStyle;
	}
}

通过以上代码基本上可以实现图形的绘制,但是有个问题,改变窗口尺寸,刚才绘制的图形就不见了。原来,改变窗口尺寸的过程中,窗口会被重绘,被白色的画刷给擦除了。所以要添加一个全局的集合类变量:

public:
	CPtrArray m_ptrArray;

再添加一个普通类 Graphic
头文件:

#pragma once
#include "afxext.h"
#include "afxwin.h"
class Graphic
{
public:
	Graphic(void);
	Graphic(int m_nDrawType,CPoint m_ptBegin,CPoint m_ptEnd,CPen* pm_pen);
	~Graphic(void);
	int m_nDrawType;
	CPoint m_ptBegin;
	CPoint m_ptEnd;
	CPen* pm_pen;
};

源文件:

#include "StdAfx.h"
#include "Graphic.h"


Graphic::Graphic(void)
	: m_nDrawType(0)
{
}

Graphic::Graphic(int m_nDrawType,CPoint m_ptBegin,CPoint m_ptEnd,CPen* pm_pen)
{
	this->m_nDrawType=m_nDrawType;
	this->m_ptBegin=m_ptBegin;
	this->m_ptEnd=m_ptEnd;
	this->pm_pen=pm_pen;
}

Graphic::~Graphic(void)
{
}

回到view类中的 LButtonUp 函数中在下面添加:

OnPrepareDC(&dc);
dc.DPtoLP(&M_PtOrgin);//设备坐标转换为逻辑坐标
dc.DPtoLP(&point);
Graphic *pGraphic=new Graphic(m_nform,M_PtOrgin,point,pen);//堆中 对象
m_ptrArray.Add(pGraphic);

同时添加消息响应函数 OnDraw :

void CGouHailong_ImageView::OnDraw(CDC* pDC)
{
	CGouHailong_ImageDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	CBrush *pbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//构造空画刷
	CBrush *pOldBrush=pDC->SelectObject(pbrush);
	for(int i=0;im_nDrawType)
		{
		case 0://点
			{//pDC->SetPixel(((Graphic*)m_ptrArray.GetAt(i))->m_ptEnd,m_clr);
			CPoint point=((Graphic*)m_ptrArray.GetAt(i))->m_ptEnd;
			CPoint ptl=point,ptr=point,ptt=point,ptb=point;
			ptl.x-=5;ptr.x+=5;
			ptb.y-=5;ptt.y+=5;
			pDC->MoveTo(ptl);pDC->LineTo(ptr);
			pDC->MoveTo(ptb);pDC->LineTo(ptt);
			break;}
		case 2:
			pDC->SelectObject(((Graphic*)m_ptrArray.GetAt(i))->pm_pen);
			pDC->MoveTo(((Graphic*)m_ptrArray.GetAt(i))->m_ptBegin);
			pDC->LineTo(((Graphic*)m_ptrArray.GetAt(i))->m_ptEnd);
			break;
		case 3://矩形
			pDC->SelectObject(((Graphic*)m_ptrArray.GetAt(i))->pm_pen);
			pDC->Rectangle(CRect(((Graphic*)m_ptrArray.GetAt(i))->m_ptBegin,((Graphic*)m_ptrArray.GetAt(i))->m_ptEnd));
			break;
		case 4:
			pDC->SelectObject(((Graphic*)m_ptrArray.GetAt(i))->pm_pen);
			pDC->Ellipse(CRect(((Graphic*)m_ptrArray.GetAt(i))->m_ptBegin,((Graphic*)m_ptrArray.GetAt(i))->m_ptEnd));
			break;
		}
	}
	pDC->SelectObject(pOldBrush);
}

OK!

你可能感兴趣的:(Draw,#,C,MFC,画图)