图形的保存与重绘(2)

逻辑坐标与设备坐标的相互转换

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); 
    //将位图贴到客户区当中
 

}

posted on 2012-09-04 22:08  龙猫先生  阅读(197)  评论(0编辑  收藏  举报

导航