前面画图步骤直接上略了,因为跟第十讲的步骤是一样的,这里不再累赘
1.创建4个菜单,为其添加消息响应,用成员变量保存绘画类型。添加LButtonDown和Up消息。
2.当窗口重绘时,如果想再显示原先画的数据,则需要保存数据。为此创建一个新类来记录绘画类型和两个点。
class CGraph
{
public:
CPoint m_ptOrigin;//起点
CPoint m_ptEnd;//终点
UINT m_nDrawType;//绘画类型
CGraph();
CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd);//此为构造函数。
virtual ~CGraph();};
然后在void
CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)中加入如下代码
//CGraph graph(m_nDrawType,m_ptOrigin,point);//不能用局部变量
//m_ptrArray.Add(&graph);//加入这种指针数组中
/* OnPrepareDC(&dc);//这个函数中可以重新设置窗口原点,对于滚动条中,保存数据前要调用此函数
dc.DPtoLP(&m_ptOrigin);//将设备坐标转换为逻辑坐标
dc.DPtoLP(&point);//
CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);//在堆中创建新的对象
m_ptrArray.Add(pGraph);*///加入到指针数组中
在GraphicView.h中有如下代码
CPtrArray m_ptrArray;
在OnDraw中重画时调出数据
for(int i=0;i<m_ptrArray.GetSize();i++)
3.在CView::OnPaint()调用了OnDraw(),但在void
CGraphicView::OnPaint()中MFC的Wizard没有调用OnDraw(),要注意这个区别。如果你此时想调用,必须手动添加代码。
OnDraw(&dc);
4.让窗口具有滚动条的功能。
第1.将CGraphicView的头文件中的CView全部替换成CSrollView
第2.添加如下的代码
void CGraphicView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
// TOD Add your specialized code here and/or call the base class
SetScrollSizes(MM_TEXT,CSize(800,600));//设置映射模式,设定窗口大小。OK!
}
5.坐标系的转换,此处不再详细介绍,需要时请查阅相关资料。
6.解决重绘时线跑到上面的问题。为什么会错位?因为逻辑坐标和设备坐标没有对应起来。
解决方法:
在OnLButtonDown画完图后,保存之前。调用
/* OnPrepareDC(&dc);//重新设置逻辑坐标的原点!!!
dc.DPtoLP(&m_ptOrigin);//设备坐标转化为逻辑坐标
dc.DPtoLP(&point);
CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);
m_ptrArray.Add(pGraph);*/
7.另外两种方法来保存数据。
一种是用CMetaFileDC
另一种是利用兼容DC,重绘时利用
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);
void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
/*CClientDC ccdc(this);
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
ccdc.SelectObject(cbrush);
switch(m_leixing)
{
case 0:
ccdc.SetPixel(point,RGB(0,0,0));
break;
case 1:
ccdc.MoveTo(m_yuandian);
ccdc.LineTo(point);
break;
case 2:
ccdc.Rectangle(&CRect(m_yuandian,point));
break;
case 3:
ccdc.Ellipse(&CRect(m_yuandian,point));
break;
default:
break;
}*/
//CHUATU huatu(m_leixing,m_yuandian,point);//对象的声明周期在右大括号结束之后就销毁了,所以不可行
//m_carray.Add(&huatu);
CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);//使用指针,在堆栈分配了空间,与整个程序的声明周期一致,可行
m_carray.Add(huatu);
Invalidate();
CView::OnLButtonUp(nFlags, point);
}
void CHuiTuBaoView::OnDraw(CDC* pDC)
{
CHuiTuBaoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(cbrush);
for(int i=0;i<m_carray.GetSize();++i)
{
switch(((CHUATU*)m_carray.GetAt(i))->m_cleixing)
{
case 0:
pDC->SetPixel(((CHUATU*)m_carray.GetAt(i))->m_czhondian,RGB(255,0,0));
break;
case 1:
pDC->MoveTo(((CHUATU*)m_carray.GetAt(i))->m_cyuandian);
pDC->LineTo(((CHUATU*)m_carray.GetAt(i))->m_czhondian);
break;
case 2:
pDC->Rectangle(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
break;
case 3:
pDC->Ellipse(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
break;
default:
break;
}
}
}
上面使用CPtrArray来保存CHUATU的指针,那能不能使用我们熟悉的Vector动态数组来操作呢。试试便知
试验证明是可以的。
在CXXView头文件中写上
include<vector>
using namespace std;
然后定义成员变量
vector<CHUATU*>vv;
void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
/*CClientDC ccdc(this);
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
ccdc.SelectObject(cbrush);
switch(m_leixing)
{
case 0:
ccdc.SetPixel(point,RGB(0,0,0));
break;
case 1:
ccdc.MoveTo(m_yuandian);
ccdc.LineTo(point);
break;
case 2:
ccdc.Rectangle(&CRect(m_yuandian,point));
break;
case 3:
ccdc.Ellipse(&CRect(m_yuandian,point));
break;
default:
break;
}*/
//CHUATU huatu(m_leixing,m_yuandian,point);
//m_carray.Add(&huatu);
/*CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
m_carray.Add(huatu);
Invalidate();*/
CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
vv.push_back(huatu);
Invalidate();
CView::OnLButtonUp(nFlags, point);
}
void CHuiTuBaoView::OnDraw(CDC* pDC)
{
CHuiTuBaoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(cbrush);
/*for(int i=0;i<m_carray.GetSize();++i)
{
switch(((CHUATU*)m_carray.GetAt(i))->m_cleixing)
{
case 0:
pDC->SetPixel(((CHUATU*)m_carray.GetAt(i))->m_czhondian,RGB(255,0,0));
break;
case 1:
pDC->MoveTo(((CHUATU*)m_carray.GetAt(i))->m_cyuandian);
pDC->LineTo(((CHUATU*)m_carray.GetAt(i))->m_czhondian);
break;
case 2:
pDC->Rectangle(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
break;
case 3:
pDC->Ellipse(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));
break;
default:
break;
}
}*/
for(vector<CHUATU*>::iterator itera=vv.begin();itera!=vv.end();++itera)
{
switch((*itera)->m_cleixing)
{
case 0:
pDC->SetPixel((*itera)->m_czhondian,RGB(255,0,0));
break;
case 1:
pDC->MoveTo((*itera)->m_cyuandian);
pDC->LineTo((*itera)->m_czhondian);
break;
case 2:
pDC->Rectangle(&CRect((*itera)->m_cyuandian,(*itera)->m_czhondian));
break;
case 3:
pDC->Ellipse(&CRect((*itera)->m_cyuandian,(*itera)->m_czhondian));
break;
}
}
}
可以使用很多方法解决,不要丢了我们前面学习的C++知识喔。
下面是有关GDI映射的问题,具体也可以看我的Windows32GDI映射的博客
OnPrepareDC会随时根据滚动窗口的位置来调整视口的原点
下面是一个关于设置坐标位置的例子。
手动设置滚动条
1class CXXView : public CView--->class CXXView : public CScrollView
2把cpp文件中的CView全部替换成CScrollView
3设置滚动条的属性
void SetScrollSizes( int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault );
在CXXView中添加一个虚函数OnInitUpdate函数
4添加一条代码,这个函数是在调用OnDraw之前调用的
void CHuiTuBaoView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
SetScrollSizes(MM_TEXT,CSize(800,600));
}
然后就可以显示滚动条了:
然后用老师讲的方法,可以解决坐标映射问题,上面的PPT有讲问题的现象和解决方法
void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
/*CClientDC ccdc(this);
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
ccdc.SelectObject(cbrush);
switch(m_leixing)
{
case 0:
ccdc.SetPixel(point,RGB(0,0,0));
break;
case 1:
ccdc.MoveTo(m_yuandian);
ccdc.LineTo(point);
break;
case 2:
ccdc.Rectangle(&CRect(m_yuandian,point));
break;
case 3:
ccdc.Ellipse(&CRect(m_yuandian,point));
break;
default:
break;
}*/
//CHUATU huatu(m_leixing,m_yuandian,point);
//m_carray.Add(&huatu);
/*CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
m_carray.Add(huatu);
Invalidate();*/
CClientDC ccdc(this);
OnPrepareDC(&ccdc);
ccdc.DPtoLP(&m_yuandian);
ccdc.DPtoLP(&point);
CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);
vv.push_back(huatu);
Invalidate();
CScrollView::OnLButtonUp(nFlags, point);
}
这样就完美解决了。
OnPaint中调用了OnprepareDC和OnDraw函数,OnprepareDC就是用来调整(设备环境)视口的
使用原文件上下文保存图像,CMetaFileDC
在OnLButtonUp中,CMetaFileDC yuanwenjian是成员变量,构造函数中Create
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
yuanwenjiandc.SelectObject(cbrush);
switch(m_leixing)
{
case 0:
yuanwenjiandc.SetPixel(point,RGB(0,0,0));
break;
case 1:
yuanwenjiandc.MoveTo(m_yuandian);
yuanwenjiandc.LineTo(point);
break;
case 2:
yuanwenjiandc.Rectangle(&CRect(m_yuandian,point));
break;
case 3:
yuanwenjiandc.Ellipse(&CRect(m_yuandian,point));
break;
default:
break;
}
在OnDraw中
void CHuiTuBaoView::OnDraw(CDC* pDC)
{
CHuiTuBaoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(cbrush);
HMETAFILE hmetafile;
hmetafile=yuanwenjiandc.Close();
pDC->PlayMetaFile(hmetafile);
yuanwenjiandc.Create();
DeleteMetaFile(hmetafile);}//一定要关闭,否则出错
如果还想要保存原来的图画,这这样
void CHuiTuBaoView::OnDraw(CDC* pDC)
{
CHuiTuBaoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(cbrush);
HMETAFILE hmetafile;
hmetafile=yuanwenjiandc.Close();
pDC->PlayMetaFile(hmetafile);
yuanwenjiandc.Create();
yuanwenjiandc.PlayMetaFile(hmetafile);//保存上一次绘画的图案
DeleteMetaFile(hmetafile);
}
CMetaFile只是保存的是绘图的命令,而不是文件
下面给打开和保存添加事件
void CHuiTuBaoView::OnFileSave()
{
// TODO: Add your command handler code here
HMETAFILE hmetafile;
hmetafile=yuanwenjiandc.Close();
CopyMetaFile(hmetafile,"meta.wmf");
yuanwenjiandc.Create();
DeleteMetaFile(hmetafile);
}
void CHuiTuBaoView::OnFileOpen()
{
// TODO: Add your command handler code here
HMETAFILE hmetafile;
hmetafile=GetMetaFile("meta.wmf");
yuanwenjiandc.PlayMetaFile(hmetafile);
DeleteMetaFile(hmetafile);
Invalidate();
}
使用另外一种方法保存,兼容DC
在OnLButtonUp中
CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CClientDC ccdc(this);
if(!compatibledc)
{
compatibledc.CreateCompatibleDC(&ccdc);
CRect rect;
GetClientRect(&rect);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&ccdc,rect.Width(),rect.Height());
compatibledc.SelectObject(&bitmap);
compatibledc.SelectObject(cbrush);
compatibledc.BitBlt(0,0,rect.Width(),rect.Height(),&ccdc,0,0,SRCCOPY);//兼容位图跟普通不一样
}
yuanwenjiandc.SelectObject(cbrush);
switch(m_leixing)
{
case 0:
compatibledc.SetPixel(point,RGB(0,0,0));
break;
case 1:
compatibledc.MoveTo(m_yuandian);
compatibledc.LineTo(point);
break;
case 2:
compatibledc.Rectangle(&CRect(m_yuandian,point));
break;
case 3:
compatibledc.Ellipse(&CRect(m_yuandian,point));
break;
default:
break;
}
OnDraw中
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&compatibledc,0,0,SRCCOPY);
分享到:
相关推荐
第十一课:图形的 保存和重绘 第十二课:文件操作 第十三课:文档与串行化 第十四课:网络相关知识 第十五课:多线程与聊天室程序的创建 第十六课:线程同步与异步套接字编程 第十七课:进程间通信 第十八课:ActiveX控件 第...
孙鑫c++视频总结,入门学习,包括算法,数据结构,编译原理
C++学习教程,适合刚入门的朋友,零基础的也可以看这个,我就是学习完这套资源后才学会这个编程,并让我爱上了编程
孙鑫C++教程(全20讲)PPT讲义,如果下载了视频,讲义也不可少哦
孙鑫C++教程(全20讲)PPT讲义
孙鑫pdf文档,入门C++的好帮手,MFC类库,vc6.0,虽然版本比较老,但是在很多地方使用得仍然比较多。参考性大
孙鑫C++教程(全20讲)PPT讲义-11-20.rar
孙鑫C++教程(全20讲)PPT讲义.ppt
孙鑫C++视频教程配套讲义,教程B站上有,Windows运行原理方面讲解十分详细,年代有点久远但仍然可以学到很多东西。
利用vs2015,对孙鑫mfc进行了代码编写 时间,能力原理,有些部分没有进行优化
孙鑫 VC++ 深入详解书中源码
C++学习资料,孙鑫老师的教课内容深入浅出,特别适合初学者。
C++最好的软件教程课件
C++笔记 适合MFC初学者 自己看孙鑫MFC深入详解的视频的时候边看边写的 ~~~
该资源由内附孙鑫讲解的vc++编程1-20课的PPT讲解和详细实现代码,另附c++入门基础的课程,是每位c++编程爱好者必学的课程资源c++编程进阶的必经之路。
孙鑫老师c++教程,比较全面,系统的c++教程视频。
孙鑫C++视频教程总结(内功=算法+数据结构+编译原理+操....doc
孙鑫老师的视频配套源代码,比较实用,希望对大家有用处。
孙鑫视频源码,初学者的指路灯,里面含有二十个章节的所有代码,从C++的最初到最后的钩子原理,为我们更深刻的了解C++起了很好的作用
我自己做的mfc绘图程序,参照孙鑫的视频讲解,功能完善,界面良好,课程设计的题目,在老师那儿拿的优秀