正文

MFC中的GDI绘图(5)2008-12-22 12:56:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/xman/40019.html

分享到:

坐标映射实例 (1)建立单文档MFC项目Draw:New—>Projects—>MFC AppWizard(EXE)—>Single Document。 (2)找到CMainFrame::PreCreateWindow函数,在其中设置默认窗口大小为400 pixel*300 pixel。 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) {     if( !CFrameWnd::PreCreateWindow(cs) )         return FALSE;     // TODO: Modify the Window class or styles here by modifying     // the CREATESTRUCT cs     cs.cx=400;     cs.cy=300;     return TRUE; } (3)添加OnPaint事件 资源管理器—>ClassView—>右击CDrawView 选择Add Windows Message Handler —>WM_PAINT—> Add Handler 1.     void CDrawView::OnPaint() 2.     { 3.          CPaintDC dc(this); // device context for painting   4.          // TODO: Add your message handler code here 5.          CRect cr;//矩形结构 6.          GetClientRect(&cr);//获得客户区窗口  7.          int cx=cr.right;//右 8.            int cy=cr.bottom;//底 9.          dc.SetMapMode(MM_ISOTROPIC);//X=Y   10.       dc.SetWindowExt(1000,1000);//设置逻辑窗口,默认窗口原点为(0,0) 11.       dc.SetViewportExt(cx,-cy);//定义输出视口,X右Y上为正 12.       dc.SetViewportOrg(cx/2,cy/2);//定义视口原点为客户区中心 13.       dc.Ellipse(-200,200,200,-200);//绘制椭圆与客户区外切的椭圆 14.       //绘制水平垂直的四条半径 15.       dc.MoveTo(0,0);     dc.LineTo(200,0); 16.       dc.MoveTo(0,0);     dc.LineTo(-200,0); 17.       dc.MoveTo(0,0);     dc.LineTo(0,200); 18.       dc.MoveTo(0,0);     dc.LineTo(0,-200); 19.       //执行F5进行Debug,在底端Output窗口中可以观察ClientRect 20.      TRACE( "ClientRect.x = %d, ClientRect.y = %d\n", cx, cy ); 21.  } 运行结果如图1左。当改变窗口大小时,图中圆形状始终不变。 <1>将上面代码的第9行改为:dc.SetMapMode(MM_ANISOTROPIC);//X!=Y运行结果如图1右。                        图1 我们发现,尽管上面代码的第13行dc.Ellipse(-200,200,200,-200);中定义的椭圆外接矩形逻辑上为正方形,但是显示的并不是圆,而是椭圆。 当我们改变窗口大小时,图中椭圆变形,甚至可能变为圆形。具体为: 保持窗口宽度不变时,减小高度,椭圆变得更扁;保持窗口高度不变时,减小宽度,椭圆变得更圆,当拉伸到客户区为正方形时,我们发现椭圆变成了圆! <2>将上面代码的第9行改回dc.SetMapMode(MM_ISOTROPIC);//X=Y,第15行改为dc.LineTo(500,0); 第18行改为dc.LineTo(0,-500); 运行结果如图2左。 保持窗口高度不变,减小窗口宽度,使窗口宽度<窗口高度,运行结果如图2右。           图2 <3>在将<2>中代码的第9行改回dc.SetMapMode(MM_ANISOTROPIC);//X!=Y, 运行结果如图3:                             图3 当我们改变窗口大小时,dc.LineTo(500,0); dc.LineTo(0,-500);都是由原点(客户区中心)到客户区右端中心、底端中心的直线。 <4>将原代码中第10行dc.SetWindowExt(1000,1000);//设置逻辑窗口后添加dc.SetWindowOrg(100,100);设置逻辑窗口的原点为(100,100)。观察运行结果可知,图1中的图形整体向左向下分别移动了100个逻辑单位: (-200,200,200,-200)——>(-200-100,200-100,200-100,-200-100) 若需要保持图1中的图形,则需要将涉及到的每个点加上(100,100),即: 13.       dc.Ellipse(-200+100,200+100,200+100,-200+100); 14.       //绘制水平垂直的四条半径 15.       dc.MoveTo(0+100,0+100);     dc.LineTo(200+100,0+100); 16.       dc.MoveTo(0+100,0+100);     dc.LineTo(-200+100,0+100); 17.       dc.MoveTo(0+100,0+100);     dc.LineTo(0+100,200+100); 18.       dc.MoveTo(0+100,0+100);     dc.LineTo(0+100,-200+100) (4)总结逻辑窗口坐标到设备视口坐标的映射方法: <1>逻辑窗口原点映射为视口原点 <2>逻辑窗口宽度和高度映射为视口宽度和高度 <3>当映射方式为MM_ISOTROPIC时,WindowExt.Width=WindowExt.Height,有效绘图区域为以视口宽高中的最小边为边长的正方形区域。比例因子为: scaleX=scaleY=min{ViewportExt.Width, ViewportExt.Height }/WindowExt.Width 当映射方式为MM_ANISOTROPIC时,有效绘图区域为整个视口(这里为客户区)。比例因子为: scaleX=ViewportExt.Width/WindowExt.Width scaleY=ViewportExt.Height /WindowExt.Height。见图4. <4>设备(视口)坐标 = (逻辑坐标–逻辑窗口原点坐标)×比例因子+视口原点坐标              图4 以下分析中客户区大小为ClientRect=(388,200),逻辑窗口原点为WindowOrg=(100,100),基于(3)<4>中修改后的代码。 在上图4左中,nMapMode=MM_ISOTROPIC,椭圆外接矩形左上角逻辑坐标(-100,300)映射为客户区的以Pixel为单位的坐标为: left_top_X= (-100-100)×(200/1000)+388/2=154 pixel left_top_Y= (300-100)×(200/1000)+200/2=140 pixel 依此次方法可计算出右下角逻辑坐标(300,-100)映射为客户区的以Pixel为单位的坐标为: right_bottom_X=234  pixel;right_bottom_Y=60 pixel 我们若在第9行dc.SetMapMode(MM_ISOTROPIC);//X=Y前添加CreatePen(PS_SOLID,2,RGB(255,0,0));dc.Ellipse(154,140,234,60);则可以发现,这个以2个像素宽的红色画笔绘制的(椭)圆刚好和设置映射模式后绘制的(椭)圆重合。但是我们改变窗口大小时,发现设置映射模式后绘制的(椭)圆按比例拉伸,但红色圆始终在原地且大小保持不变,这也说明了默认映射方式MM_TEXT是以X轴正方向朝右,Y轴正方向朝下的坐标系和1 pixel为单位进行绘制的。 同理,我们可以分析上图4右中,nMapMode=MM_ANISOTROPIC的情况下,CRect(116,140,272,60);为等效椭圆外接矩形。

阅读(4689) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册