Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2086854
  • 博文数量: 909
  • 博客积分: 4000
  • 博客等级: 上校
  • 技术积分: 12260
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-06 20:50
文章分类

全部博文(909)

文章存档

2008年(909)

我的朋友

分类:

2008-05-06 22:36:55

一起学习
采用 MFC 编制 MVC 模式之球体演示程序

作者:haykey

下载源代码


  在传统面向过程的程序设计中,往往采用 Input-Processing-Output 模式,这“归功”于 DOS 操作系统的单任务。当 Windows 图形界面 OS 出现后,MVC(Model-View-Controller)模型更适合 Windows 图形界面程序的设计,它将数据处理和数据显示分离开,使维护,扩展系统更加灵活 。其中,View:负责 显示数据,它从Model处获得数据然后显示。当然,一个Model会有用户可从不同角度来观察的多个View。Model:存储数据以及对数据进行各种运算和处理 。Controller:负责接受用户输入,并且把用户输入转换成对 Model 的操作。因此Controller 可能会修改 Model 的数据,当数据修改后,更新 View。其结构示意图如下:




  一直采用MFC编程的朋友可能不太熟悉它,这是因为MFC的文档视图结构就是基于MVC的高层结构,这蒙蔽了我们的双眼。虽然MS替我们做了,我们还是有必要接触它,以在SDK or 其他地方有的放矢。我做了一个球体演示的例子,其界面如下:



  左侧两个表面积和体积Edit让使用者从文本的角度精确地观察,我们称其为TextView。右侧为从CStatic派生的CGraphicView,使得人们可直观地观察Sphere.对话窗口CMVCSphereDlg是控制器,来获取用户的键盘输入(输入半径后回车)和在Static上的鼠标点击与拖动(可动态调整球体半径并实时反馈球体变化)而CSphere类是模型,存储了球体半径和计算表面积,计算体积等处理半径数据的操作.
  现在让我们详细看看代码,来感受下Model,View,Controller之间如何关联,如何协同工作的。


class CSphere  

{

public:

     ... ....

    //更新Graphic-VIEW

    BOOL UpdateGraphicView(HWND hWnd,const CRect &rect,BOOL bErase);

    //更新Text-VIEW

    void UpdateTextView();

    //外界Controller的接口:设置球体半径

    void SetRadius(float r);

private:

    //球体半径

    float m_fRadius;

    //计算球体表面积

    float CalculateArea(float radius);

    //计算球体体积

    float CSphere::CalculateVolumn(float radius);

};
   这里面 UpdateTextView,UpdateTextView 就是当用户输入新半径或拖动鼠标 Controller 捕获后通知 Model,Model 通知两个View更新显示 。具体代码如下:

BOOL CSphere::UpdateGraphicView(HWND hWnd,const CRect &rect,BOOL bErase)

{

    //data format examination

    if(!::IsWindow(hWnd)||::IsRectEmpty(&rect))

    {

      AfxMessageBox("View is not created by now or rect is empty");

      return false;

    }

	

    //get the window pointer from window handle

    CWnd *pView = CWnd::FromHandle(hWnd);

    if(pView == NULL)

        return false;

    //set graphic view''s radius in order to painting

    ((CGraphicView*)pView)->SetRadius(m_fRadius);

    bPaintSphere = true;//set paint tag true

	

    //repaint

    if(!::InvalidateRect(hWnd,&rect,bErase)&&

	   !::UpdateWindow(hWnd))

    {

      AfxMessageBox("UpdateView failed");

      return true;

    }

    

    pView = NULL;

    return false;

}



void CSphere::UpdateTextView()

{

   CMVCSphereDlg *parent = (CMVCSphereDlg *)AfxGetMainWnd();

   CWnd *wnd1 = parent->GetDlgItem(IDC_SURFACE);

   CWnd *wnd2 = parent->GetDlgItem(IDC_VOLUMN);

   

   CString str;

   str.Format("%.2f平方米",CalculateArea(m_fRadius));

   wnd1->SetWindowText(str);

   str.Empty();

   str.Format("%.2f立方米",CalculateVolumn(m_fRadius));

   wnd2->SetWindowText(str);



}

CGraphicView中绘图关键代码如下:

void CGraphicView::OnPaint() 

{

    ... .....

    if(!bPaintSphere) 

	dc.DrawText("球体演示",rect,DT_VCENTER|DT_CENTER|DT_SINGLELINE);

    else

	{

	   int r=(int)m_radius;//半径取整

	   CPoint MiddlePoint = rect.CenterPoint();//以矩形框的中心为球心

	   int x=MiddlePoint.x;

	   int y=MiddlePoint.y;

	   oldpen = (CPen*)dc.SelectObject(&solid_pen);

	   oldbru = (CBrush*)dc.SelectObject(&brush);

	   dc.Ellipse(x-r,y-r,x r,y r);              //先画一个圆形

       

	   dc.SelectObject(&dash_pen);

	   dc.Arc(x-r/2,y-r,x r/2,y r,x,y-r,x,y r);  //再画4个半圆弧

	   dc.Arc(x-r/2,y-r,x r/2,y r,x,y r,x,y-r);

	   dc.Arc(x-r,y-r/2,x r,y r/2,x-r,y,x r,y);

	   dc.Arc(x-r,y-r/2,x r,y r/2,x r,y,x-r,y);

	   

	   ... ...

	}

	

}

关于控制器CMVCSphereDlg响应用户输入半径回车核心代码如下:

BOOL CMVCSphereDlg::PreTranslateMessage(MSG* pMsg) 

{

        UpdateData();

	//violation examination

	if(m_r<0.||m_r>100)

	{

	  AfxMessageBox("半径输入范围(0---100)");

	  return false;

	}

	

	if(pMsg->message == WM_KEYDOWN)

	   if(pMsg->wParam == VK_RETURN)//回车

	   {

	      CRect rect;

	      m_GraphicView.GetClientRect(rect);

		

	      m_Sphere.SetRadius(m_r);//把用户输入转换成对Model的操作

	      m_Sphere.UpdateTextView();//更新View

	      m_Sphere.UpdateGraphicView(m_GraphicView.GetSafeHwnd(),rect,true);//更新View

	      return true;

	   }

	... ...

}

响应鼠标拖动核心代码如下:

void CMVCSphereDlg::OnMouseMove(UINT nFlags, CPoint point) 

{

    CRect rect;

    m_GraphicView.GetClientRect(rect);

    CPoint middlepoint = rect.CenterPoint(); 



    //if click on the graphic view

    if(rect.PtInRect(point)&&bIsDragging)

    {

       double dbDistance2 = (point.x-middlepoint.x)*(point.x-middlepoint.x) (point.y-middlepoint.y)*(point.y-middlepoint.y);

       double dbDistance = sqrt(dbDistance2);	         

       if(dbDistance>100.)

          dbDistance = 100.;

	   

       m_r = (float)dbDistance;

       //update radius edit

       UpdateData(false);

       m_Sphere.SetRadius(m_r);

       m_Sphere.UpdateTextView();

       m_Sphere.UpdateGraphicView(m_GraphicView.GetSafeHwnd(),rect,true);

     }

     ... ...

}

该程序功能简单,只是示例性说明采用 MFC 如何实现MVC模型,就当抛砖引玉了。具体实现参考源代码例子。

下载本文示例代码


采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序采用 MFC 编制 MVC 模式之球体演示程序
阅读(455) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~