看了孙鑫老师C++教授用MFC绘图的视频,学到了很多,此篇博客来做个小小的总结
首先建立一个 MFC 单文档或多文档应用程序(孙鑫老师在视频中用的是 VC ,我学的时候用的VS)
编译环境:VS 2010
MFC 应用程序
首先来个结果预览:
一、绘图
m_nform=-1;//标记要画什么
m_bDraw=false;//选中“钢笔"时,标记绘画开始与结束
m_ntool=0;//标记是文本还是图形
m_strLine="";
m_LineWidth=1;
m_LineStyle=0;
m_clr=RGB(0,0,0);
添加全局变量的时候可以在类视图中,在选中被添加的类,右键:
可以选择添加变量,或者用类向导添加。
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;
}
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);
}
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();
}
}
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!