一、 所画图形的重绘: 在第十讲所用的工程上继续: 1、新增一个类CGraph,用来存储图形的信息,以便在重绘时使用。在类中添加如下成员变量:UINT m_LineWidth; int m_LineStyle; COLORREF m_clr; UINT m_nDrawType; CPoint m_ptOrigin; CPoint m_ptEnd; 再增加一个构造函数,用来传递参数: CGraph::CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd, int m_LineStyle,UINT m_LineWidth,COLORREF m_clr) { this->m_nDrawType=m_nDrawType; this->m_ptOrigin=m_ptOrigin; this->m_ptEnd=m_ptEnd; this->m_LineStyle=m_LineStyle; this->m_LineWidth=m_LineWidth; this->m_clr=m_clr; } 2、在View类中,添加一个公有成员变量:CPtrArray m_ptrArray;这是一个对象的数组类,用来存储对象的首地址。 3、在OnLButtonUp()中,添加如下语句: CGraph*pGraph=new CGraph(m_nDrawType,m_ptOrigin,point,m_LineStyle,m_LineWidth,m_clr); m_ptrArray.Add(pGraph); (注:这里一定要用指针,并且分配一个堆内存,如果直接用对象的话,会被析构掉,导致重绘失败!) 4、因为窗口重绘时,会调用OnDraw()函数,所以要在这个函数中,用存储的图形的信息,把图形再重新画一遍,如下: void CGraphic10View::OnDraw(CDC* pDC) { CGraphic10Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here CFont *pOldFont=pDC->SelectObject(&m_font); pDC->TextOut(0,0,m_str); pDC->SelectObject(pOldFont); CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); pDC->SelectObject(pBrush); for(int i=0;i<m_ptrArray.GetSize();i++) { CPen pen(((CGraph *)m_ptrArray.GetAt(i))->m_LineStyle, ((CGraph *)m_ptrArray.GetAt(i))->m_LineWidth, ((CGraph *)m_ptrArray.GetAt(i))->m_clr); CPen *pOldPen=pDC->SelectObject(&pen); switch(((CGraph *)m_ptrArray.GetAt(i))->m_nDrawType) { case 1: pDC->SetPixel(((CGraph *)m_ptrArray.GetAt(i))->m_ptOrigin,RGB(0,0,0)); break; case 2: pDC->MoveTo(((CGraph *)m_ptrArray.GetAt(i))->m_ptOrigin); pDC->LineTo(((CGraph *)m_ptrArray.GetAt(i))->m_ptEnd); break; case 3: pDC->Rectangle(CRect(((CGraph *)m_ptrArray.GetAt(i))->m_ptOrigin, ((CGraph *)m_ptrArray.GetAt(i))->m_ptEnd)); break; case 4: pDC->Ellipse(CRect(((CGraph *)m_ptrArray.GetAt(i))->m_ptOrigin, ((CGraph *)m_ptrArray.GetAt(i))->m_ptEnd)); break; } pDC->SelectObject(pOldPen); } } 二、 解决窗口重绘时,出现的坐标之间的转换问题: 1、 将View类中的基类都换成CScrollView类,转换完成之后,添加一个虚函数:OnInitialUpdate(),在其中设置滚动窗口的信息,如下: void CGraphic10View::OnInitialUpdate() { CScrollView::OnInitialUpdate(); // TODO: Add your specialized code here and/or call the base class SetScrollSizes(MM_TEXT,CSize(1000,1000)); } 2、 在OnLButtonUp()函数中,在定义CGraph对象的指针之前,添加如下语句: void CGraphic10View::OnLButtonUp(UINT nFlags, CPoint point) { …… OnPrepareDC(&dc);//改变视口的原点坐标 dc.DPtoLP(&m_ptOrigin); dc.DPtoLP(&point);//将设备坐标转换为逻辑坐标 //CGraph graph(m_nDrawType,m_ptOrigin,point); CGraph*pGraph=new CGraph(m_nDrawType,m_ptOrigin,point,m_LineStyle,m_LineWidth,m_clr); m_ptrArray.Add(pGraph); CScrollView::OnLButtonUp(nFlags, point); } (注:我自己实在是不知道该怎么说,附上这个图片吧) 三、 另一种图形重绘的方法与图形的保存和打开操作: 1、 在View类中,添加一个私有变量:CMetaFileDC m_dcMetaFile,CMetaFileDC类是接受所画图形的命令,而不是图形的数据的类。 2、 在OnLButtonUp()函数中作如下修改: void CGraphic10View::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CClientDC dc(this); CPen pen(m_LineStyle,m_LineWidth,m_clr); CPen *pOldPen=m_dcMetaFile.SelectObject(&pen); CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); CBrush *pOldBrush=m_dcMetaFile.SelectObject(pBrush); switch(m_nDrawType) { case 1: m_dcMetaFile.SetPixel(point,m_clr); break; case 2: m_dcMetaFile.MoveTo(m_ptOrigin); m_dcMetaFile.LineTo(point); break; case 3: m_dcMetaFile.Rectangle(CRect(m_ptOrigin,point)); break; case 4: m_dcMetaFile.Ellipse(CRect(m_ptOrigin,point)); break; default: break; } dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); } 3、 在OnDraw()函数中添加如下语句: HMETAFILE hmetafile;//定义一个句柄 hmetafile=m_dcMetaFile.Close();//用Close()函数关闭这个DC,并且返回这个DC的句柄。 pDC->PlayMetaFile(hmetafile);//用这个函数,执行m_dcMetaFile中的绘图命令。 m_dcMetaFile.Create();//重新开启画板,用以接受新的绘图命令。 m_dcMetaFile.PlayMetaFile(hmetafile);//将上次所存储的命令再次保存。 DeleteMetaFile(hmetafile);//释放这个句柄 4、 在菜单栏中的“保存”和“打开”菜单项,分别添加命令响应函数,如下: void CGraphic10View::OnFileSave() { // TODO: Add your command handler code here HMETAFILE hmetafile; hmetafile=m_dcMetaFile.Close(); CopyMetaFile(hmetafile,"suolpiao.wmf");//关键是该函数的调用 m_dcMetaFile.Create(); DeleteMetaFile(hmetafile); } void CGraphic10View::OnFileOpen() { // TODO: Add your command handler code here HMETAFILE hmetafile; hmetafile=GetMetaFile("suolpiao.wmf");//关键是该函数的调用 m_dcMetaFile.PlayMetaFile(hmetafile); DeleteMetaFile(hmetafile); Invalidate(); } 四、 有一种图形重绘的方法:(利用兼容的DC) 1、 在OnLButtonUp()函数中,添加如下操作: if(!m_dcCompatible.m_hDC) { m_dcCompatible.CreateCompatibleDC(&dc);//创建一个和当前DC兼容的兼容DC。 CRect rect; GetClientRect(&rect); CBitmap bitmap; bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height()); //创建一个兼容的位图 m_dcCompatible.SelectObject(&bitmap);//把该位图加载到兼容DC上。 m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY); //一定要有这一句,是把位图的颜色和数据等信息,添加到兼容DC中去。 m_dcCompatible.SelectObject(pBrush); } switch(m_nDrawType) { case 1: m_dcCompatible.SetPixel(point,m_clr); break; case 2: m_dcCompatible.MoveTo(m_ptOrigin); m_dcCompatible.LineTo(point); break; case 3: m_dcCompatible.Rectangle(CRect(m_ptOrigin,point)); break; case 4: m_dcCompatible.Ellipse(CRect(m_ptOrigin,point)); break; default: break; } dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); 2、 在OnDraw()函数中,添加如下操作: CRect rect; GetClientRect(&rect); pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);