一、图形的保存与重绘
1,添加一个通常的类(General Class)CGraphic,用于保存图形要素
2,添加成员变量
UINT m_nDrawType;
CPoint m_ptOrigin;
CPoint m_ptEnd;
3,添加构造函数
CGraphic::CGraphic(UNT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd)
{
this->m_nDrawType=m_nDrawType;
this->m_ptOrigin=m_ptOrigin;
this->m_ptEnd=m_ptEnd;
}
4,在View类中定义一个集合类对象CPtrArray m_ptrArray;
5,图形绘制完成后保存其要素;
CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
dc.SetPixel(point,RGB(0,0,0));
break;
case 2:
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
break;
case 3:
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
dc.Ellipse(CRect(m_ptOrigin,point));
break;
default:
break;
}
//CMyGraph graph(m_nDrawType,m_ptOrigin,point); //OnLButtonUp退出时,graph对象析构
//m_ptrArray.Add(&graph);//保存了graph对象的地址,但graph将在函数退出时已经析构
CMyGraph *pGraph;
pGraph=new CMyGraph(m_nDrawType,m_ptOrigin,point);
//用new分配的内存都是在堆上,只有显式调用delete时才会释放,因此对象生命周期延长
m_ptrArray.Add(pGraph);
6,图形重绘(OnDraw中实现)
void CGraphsaveView::OnDraw(CDC* pDC)
{
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(pBrush);
for (int i=0;i<m_ptrArray.GetSize();i++)
{
switch(((CMyGraph *)m_ptrArray.GetAt(i))->m_nDrawType)
{
case 1:
pDC->SetPixel(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd,RGB(0,0,0));
break;
case 2:
pDC->MoveTo(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptOrigin);
pDC->LineTo(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd);
break;
case 3:
pDC->Rectangle(CRect(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptOrigin, ((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd));
break;
case 4:
pDC->Ellipse(CRect(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptOrigin, ((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd));
break;
default:
break;
}
}
}
二、OnPaint 与OnDraw
OnPaint是WM_PAINT的消息处理函数
OnDraw是虚函数,CView的OnDraw函数是在OnPaint中调用的
void CView::OnPaint()
{
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
若对子类的WM_PAINT消息进行捕获,且不调用OnDraw函数就无法执行OnDraw函数
三、坐标空间(查看MSDN:coordinate spaces [Win32])
世界坐标系空间:旋转,斜切,反射
页面空间:
设备空间:
物理设备空间:
SetWorldTransform
页面空间(逻辑空间)到设备空间的转换
逻辑空间中的矩形被称为窗口,设备坐标中的矩形被称为视口
Windows把窗口原点映射到视口原点,把窗口范围映射到视口范围,就完成了这种转换(参看powerpoint)
窗口(逻辑)坐标转换为视口(设备)坐标的两个公式:
xViewport = xWindow-xWinOrg+xViewOrg
yViewport = yWindow-yWinOrg+yViewOrg
视口(设备)坐标转换为窗口(逻辑)坐标的两个公式:
xWindow = xViewport-xViewOrg+xWinOrg
yWindow = yViewport-yViewOrg+yWinOrg
改变窗口/视口原点:SetWindowOrg,SetViewPortOrg
四.CScrollView(滚动窗口的创建)
1.将View类的基类选为CScrollView
2.在虚函数OnInitialUpdate中设置大小(OnInitialUpdate为窗口创建后第一个调用的函数)
CScrollView::SetScrollSizes(MM_TEXT,CSize(800,600));
五.图形错位问题(在滚动窗口底部画线,窗口重绘后线向上错位)
1.原因:在OnPaint函数调用时调用了OnPrepareDC,该函数将视口原点上移(由(0,0)移到(0,-150));
(注意:OnPrepareDC是根据滚动条的位置调整视口原点,若滚动条在顶部,则不改变视口原点)
2.解决办法:在图形保存前OnLButtonUp函数调用时),调用OnPrepareDC,保存视口原点上移后的坐标,这样重绘时的坐标就和保存的坐标一致了.
OnPrepareDC(&dc);//调整视口原点
dc.DPToLP(&m_ptOrigin);
dc.DPToLP(&point);//转换
CGraphic *pGraphic=new CGraphic(m_nDrawType,m_ptOrigin,point);//保存
m_ptrArray.Add(pGraphic);
六.图形的保存与重绘(CMetaFile:就像一个画布,但保存的不是图形本身,而是绘制图形的命令)
1.在View类中添加成员变量
CMetaFile m_dcMetaFile;
2.在View类的构造函数中调用
m_dcMetaFile.Create();//创建一个内存元文件
3.将绘图dc都改成m_dcMetaFile,这样图形就可以自动保存到元文件对象中
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
m_dcMetaFile.SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
m_dcMetaFile.SetPixel(point,RGB(0,0,0));
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;
}
4.在OnDraw函数中关才元文件对象,然后调用PlayMetaFile显示图形
HMETAFILE hMetaFile;
hMetaFile=m_dcMetaFile.Close();
pDC->PlayMetaFile(hMetaFile);//播放pDC中的图形绘制命令,不画重绘前的图形
m_dcMetaFile.Create();
m_dcMetaFile.PlayMetaFile(hMetaFile);//播放m_dcMetaFile的图形绘制命令,画重绘前的图形
DeleteMetaFile(hMetaFile);
七.将元文件对象(CMetaFile)保存为文件
1.在菜单项OnFileSave中添加"保存"元文件代码
CGraphicView::OnFileSave()
{
HMETAFILE hMetaFile;
hMetaFile=m_dcMetaFile.Close();
CopyMetaFile(hMetaFile,"meta.wmf");//wmf:windows meta file
m_dcMetaFile.Create();
DeleteMetaFile(hMetaFile);
}
2.在菜单项OnFileOpen中添加"打开"元文件代码
CGraphicView::OnFileOpen()
{
HMETAFILE hMetaFile;
hMetaFile=GetMetaFile("meta.wmf");
m_dcMetaFile.PlayMetaFile(hMetaFile);
DeleteMetaFile(hMetaFile);
Invalidate();
}
八.利用兼容DC
1.在view类添加成员变量 CDC m_dcCompatible;
2.在OnLButtonUp中保存
CClientDC dc(this);
......
if(!m_dcCompatible.m_hDC)
{
m_dcCompatible.CreateCompatibleDC(&dc);
CRect rect;
GetClientRect(&rect);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
m_dcCompatible.SelectObject(&bitmap);
m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);
//注意兼容BITMAP在选入兼容DC后,还需调用BitBlt将源dc中的颜色表和像素数据块COPY到
//兼容DC中,不能像普通BITMAP那样选入后即可使用
m_dcCompatible.SelectObject(pBrush);//选入透明画刷
}
3.将画图dc改为m_dcCompatible
switch(m_nDrawType)
{
case 1:
m_dcCompatible.SetPixel(point,RGB(0,0,0));
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;
}
4.图形的重绘在OnDraw函数中
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);