逻辑坐标与设备坐标的相互转换
DMM_TEXT映射方式下逻辑坐标与设备坐标的相互转换
接下来,在CGraphic2View类上添加一个虚函数,编辑:
void CGraphic2View::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
SetScrollSizes(MM_TEXT,CSize(1000,800));//设置一个滚动条
}
运行,可以发现多了滚动条,当把窗口滚动条拖到最下方时,再画一图形,切换窗口,再切回来,发现图形上移,下面解决这个问题。
视口和窗口原点的改变
关于图形错位的说明
解决方法
在CGraphic2View::OnLButtonUp中编辑:
//CGraph graph(m_nDrawType,m_ptOrigin,point);//构造一个对象
//注:此时graph是一个局部变量,为它分配的内存在栈中,当这个函数结束时,对象也会被析构
//m_ptrArray.Add(&graph);//将graph对象保存到集合类的对象m_ptArray当中
OnPrepareDC(&dc);//调整图形设备显示
dc.DPtoLP(&m_ptOrigin);//将设备点转换成逻辑点
dc.DPtoLP(&point);//将设备点转换成逻辑点
CGraph *pGraph;//这也是一个局部的指针变量,内存在栈中
pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);
//这一句调用它的构造函数为pGraph指针类型的变量在堆中分配一个内存空间,构造一个CGraph类的对象
//因为用new所分配的内存都是在堆中分配的,在堆中分配的对象的内存,如果不去显示的调用Delete去释放
//这个对象内存,那么这个对象的生命周期是和应用程序保持一致的
m_ptrArray.Add(pGraph);//将之前在堆中构造的CGraph类的对象地地址索引保存到集合类的对象m_ptArray当中
说明:OnPrepareDC会随时根据滚动窗口的位置来调整视口的原点。
5.保存图形和重绘图形的另两种方式
先在CGraphic2View类上添加一个私有的成员变量CMetaFileDC
m_dcMetaFile; ,
然后在构造函数当中:
CGraphic2View::CGraphic2View()
{
m_nDrawType=0;
m_ptOrigin=0;
m_dcMetaFile.Create();//创建一个内存的CMetaFileDC对象
}
然后在CGraphic2View::OnLButtonUp函数中修改:
void CGraphic2View::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//创建透明画刷
//dc.SelectObject(pBrush);
m_dcMetaFile.SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
//dc.SetPixel(point,RGB(0,0,0));
m_dcMetaFile.SetPixel(point,RGB(0,0,0));//m_dcMetaFile元文件
//m_dcCompatible.SetPixel(point,RGB(0,0,0));//m_dcCompatible兼容DC
break;
case 2:
//dc.MoveTo(m_ptOrigin);
//dc.LineTo(point);
m_dcMetaFile.MoveTo(m_ptOrigin);
m_dcMetaFile.LineTo(point);
//m_dcCompatible.MoveTo(m_ptOrigin);
//m_dcCompatible.LineTo(point);
break;
case 3:
//dc.Rectangle(CRect(m_ptOrigin,point));
m_dcMetaFile.Rectangle(CRect(m_ptOrigin,point));
//m_dcCompatible.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
//dc.Ellipse(CRect(m_ptOrigin,point));
m_dcMetaFile.Ellipse(CRect(m_ptOrigin,point));
//m_dcCompatible.Ellipse(CRect(m_ptOrigin,point));
break;
}
CView::OnLButtonUp(nFlags, point);
}
并在CGraphic2View::OnDraw函数中修改:
void CGraphic2View::OnDraw(CDC* pDC)
{
CGraphic2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
HMETAFILE hmetaFile;
hmetaFile=m_dcMetaFile.Close();//关闭元文件DC,并获得它的句柄
pDC->PlayMetaFile(hmetaFile);//播放元文件
m_dcMetaFile.Create();//再次创建一个元文件
m_dcMetaFile.PlayMetaFile(hmetaFile);//去播放先前的元文件,在元文件DC中绘制
DeleteMetaFile(hmetaFile);//删除元文件
}
运行,绘制图形,改变窗口大小后,图形显示出来了。
6.将绘制的元文件保存到元文件当中和打开保存的元文件
方式一:利用元文件
先给IDR_MAINFRAME菜单的保存和打开子项添加命令响应,编辑:
void CGraphic2View::OnFileSave()
{
//保存元文件
HMETAFILE hmetaFile;
hmetaFile=m_dcMetaFile.Close();
CopyMetaFile(hmetaFile,"meta.wmf");//拷贝元文件
m_dcMetaFile.Create();//重新创建元文件,以便下一次绘画
DeleteMetaFile(hmetaFile);//删除元文件
}
void CGraphic2View::OnFileOpen()
{
//打开元文件
HMETAFILE hmetaFile;
hmetaFile=GetMetaFile("meta.wmf");//得到元文件句柄
m_dcMetaFile.PlayMetaFile(hmetaFile);//播放元文件
DeleteMetaFile(hmetaFile);//删除元文件句柄
Invalidate();//引起窗口的重画
}
方式二:利用兼容DC
首先在CGraphic2View类当中增加一个私有成员变量 CDC
m_dcCompatible; 然后在CGraphic2View::OnLButtonUp函数中修改:
void CGraphic2View::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//创建透明画刷
//dc.SelectObject(pBrush);
m_dcMetaFile.SelectObject(pBrush);
if(!m_dcCompatible.m_hDC)//判断兼容DC是否被创建
{
m_dcCompatible.CreateCompatibleDC(&dc);//创建一个与当前DC兼容的兼容DC
CRect rect;
GetClientRect(&rect);//获取客户区域大小
CBitmap bitmap;//创建一个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的设备表拷贝到兼容DC
m_dcCompatible.SelectObject(pBrush);//将透明的画刷选到兼容DC中
}
switch(m_nDrawType)
{
case 1:
//dc.SetPixel(point,RGB(0,0,0));
//m_dcMetaFile.SetPixel(point,RGB(0,0,0));//m_dcMetaFile元文件
m_dcCompatible.SetPixel(point,RGB(0,0,0));//m_dcCompatible兼容DC
break;
case 2:
//dc.MoveTo(m_ptOrigin);
//dc.LineTo(point);
//m_dcMetaFile.MoveTo(m_ptOrigin);
//m_dcMetaFile.LineTo(point);
m_dcCompatible.MoveTo(m_ptOrigin);
m_dcCompatible.LineTo(point);
break;
case 3:
//dc.Rectangle(CRect(m_ptOrigin,point));
//m_dcMetaFile.Rectangle(CRect(m_ptOrigin,point));
m_dcCompatible.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
//dc.Ellipse(CRect(m_ptOrigin,point));
//m_dcMetaFile.Ellipse(CRect(m_ptOrigin,point));
m_dcCompatible.Ellipse(CRect(m_ptOrigin,point));
break;
}
CView::OnLButtonUp(nFlags, point);
}
并在CGraphic2View::OnDraw函数中编辑:
void CGraphic2View::OnDraw(CDC* pDC)
{
CGraphic2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rect;
GetClientRect(&rect);//得到客户的大小
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);
//将位图贴到客户区当中
}