1.项目起源以及采用文档/视图框架体系缘由

我们整天都在说:文档保存项目的数据并处理项目上的数据;视图通过关联获得文档的数据并进行可视化;主窗口框架接收外部事件消息并进行消息分配。这句口头禅感觉接触过MFC的新手都能背得一字不差,然而,这到底讲了一件啥事?我想用程序的语言进行变相的概括一下:数据变量定义在文档类并进行保护公用成员函数也被定义在文档类,公用函数是文档类与视图类沟通的唯一桥梁
这个项目挺有意思,一方面关联导师的项目。另一方法姐姐家的小孩3岁了,这是一个很好的方法练习小孩的辨色力以及反应能力。
软件的视图如下所示:
具体功能是:自动变色,调节时间变色,色差分析等。其实,利用对话框也能进行设计,不过数据交流太不方便,最终还是定下来采用文档/视图结构。

2.一步一步接触项目的核心

文档文件中,做数据存储功能实现
1.给文档添加成员变量m_clrGrid和m_clrCurrentColor,并在OnNewDocument()中实现初始化。
<span style="font-size:18px;">protected:  //文档类中进行数据成员保护,视图中索引靠接口函数COLORREF m_clrCurrentColor;COLORREF m_clrGrid[4][4];</span>
<span style="font-size:18px;">BOOL CChildGridDoc::OnNewDocument()
{if (!CDocument::OnNewDocument())return FALSE;//初始化代码for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)m_clrGrid[i][j] = RGB(255, 255, 255);//4*4格子初始化为白色m_clrCurrentColor = RGB(255, 0, 0);//初始化当前保持色为红色return TRUE;
}</span>

注意:在这里我之所以采用在OnNewDocument中而不是在构造函数中进行初始化,就是考虑到了界面可以在新文档创建时可以被重新设置。如果在文档构造函数中进行初始化,那我们的程序仅仅进行一次初始化(只有在程序启动的时候调用),再新建文档时会残余上一次结果,造成干扰。


2.给文档类添加成员函数GetCurrentColor(),GetSquare()以及SetSquare。使他们作为文档类的公用函数成员,以方便视图类通过他们访问文档数据。
<span style="font-size:18px;">//获取当前控制设备的颜色
COLORREF CChildGridDoc::GetCurrentColor()
{return m_clrCurrentColor;
}
//按位置进行颜色索引
COLORREF CChildGridDoc::GetSquare(int x, int y)
{ASSERT(x>=0&&x<=3 && y>=0&&y<=3);return m_clrGrid[x][y];
}
//在视图中进行设置
void CChildGridDoc::SetSquare(int x, int y, COLORREF color)
{ASSERT(x >= 0 && x <= 3 && y >= 0 && y <= 3);m_clrGrid[x][y] = color;SetModifiedFlag(TRUE);UpdateAllViews(NULL);
}</span>

这里需要注意的是,在赋给方格颜色之后,SetSquare将调用文档的SetModifiedFlag把文档标记为已修改,并调用UpdateAllView重绘视图来显示更新后的网络。

GetCurrentColor、GetSquare、SetSquare作为文档与视图之间的桥梁,由于文档的数据成员为保护类型,所以视图不能直接访问他们,只能通过这些桥梁(类间接口函数)实现对文档数据的访问。
2.文档存储和读取操作。
<span style="font-size:18px;">void CChildGridDoc::Serialize(CArchive& ar)
{if (ar.IsStoring()){//数据存储for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)ar << m_clrGrid[i][j];ar << m_clrCurrentColor;}else{//数据读取for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)ar >> m_clrGrid[i][j];ar >> m_clrCurrentColor;}
}</span>

当我们将ChildGrid文档保存在磁盘或从磁盘中读取时,MFC就会调用文档的Serialize函数。在文档被保存时,CChildGrid::Serialize通过将m_clrGrid和m_clrCurrentColor串行化输出给文档来做响应,再打开文档时从档案中串行化输入。例如,显示Open和Save As对话框,打开文件以供读写等。这也能解释,为什么在文档/视图应用程序中对保存和装载文档的处理,工作量比在传统的应用程序中少许多。
3.颜色界面添加与消息映射图构建
通过在菜单上做颜色选择,更新程序段代码使用CCmdUI::SetRadio来设置当前颜色,这可是一个消息响应的过程,我们需要将命令处理程序将该颜色值赋给m_clrCurrentColor。假如,这是假设,我能操控MFC的ON_COMMAND_RANGE和ON_UPDATE_COMMAND_UI_RANGE宏为六个下拉颜色菜单提供一个公用的命令处理程序和更新处理程序,那就太简单了;我们完全没有必要编写6个独立的命令处理程序以及6个更新程序了!!但是很不幸,类向导并没有任何提供输出RANGE宏的方法,所以也只能手动添加。
CChildGridDoc.h 声明颜色命令的消息处理函数:
<span style="font-size:18px;">protected://手动添加颜色命令的消息处理程序afx_msg void OnColorRed();afx_msg void OnColorYellow();afx_msg void OnColorGreen();afx_msg void OnColorCyan();afx_msg void OnColorBlue();afx_msg void OnColorWhite();afx_msg void OnUpdateColorRed(CCmdUI* pCmdUI);afx_msg void OnUpdateColorYellow(CCmdUI* pCmdUI);afx_msg void OnUpdateColorGreen(CCmdUI* pCmdUI);afx_msg void OnUpdateColorCyan(CCmdUI* pCmdUI);afx_msg void OnUpdateColorBlue(CCmdUI* pCmdUI);afx_msg void OnUpdateColorWhite(CCmdUI* pCmdUI);</span>
在CChildGrid.cpp中定义“命令/消息”响应关联:
<span style="font-size:18px;">BEGIN_MESSAGE_MAP(CChildGridDoc, CDocument)ON_COMMAND(ID_COLOR_RED, OnColorRed)ON_COMMAND(ID_COLOR_YELLOW, OnColorYellow)ON_COMMAND(ID_COLOR_GREEN, OnColorGreen)ON_COMMAND(ID_COLOR_CYAN, OnColorCyan)ON_COMMAND(ID_COLOR_BLUE, OnColorBlue)ON_COMMAND(ID_COLOR_WHITE, OnColorWhite)ON_UPDATE_COMMAND_UI(ID_COLOR_RED, OnUpdateColorRed)ON_UPDATE_COMMAND_UI(ID_COLOR_YELLOW, OnUpdateColorYellow)ON_UPDATE_COMMAND_UI(ID_COLOR_GREEN, OnUpdateColorGreen)ON_UPDATE_COMMAND_UI(ID_COLOR_CYAN, OnUpdateColorCyan)ON_UPDATE_COMMAND_UI(ID_COLOR_BLUE, OnUpdateColorBlue)ON_UPDATE_COMMAND_UI(ID_COLOR_WHITE, OnUpdateColorWhite)END_MESSAGE_MAP()</span>
设置响应颜色命令的消息响应程序以及和更新程序:
<span style="font-size:18px;">//设置颜色命令的消息响应程序和更新处理程序
void CChildGridDoc::OnColorRed() {m_clrCurrentColor = RGB(255, 0, 0);
}
void CChildGridDoc::OnColorYellow() {m_clrCurrentColor = RGB(255, 255, 0);
}
void CChildGridDoc::OnColorGreen() {m_clrCurrentColor = RGB(0, 255, 0);
}
void CChildGridDoc::OnColorCyan() {m_clrCurrentColor = RGB(0, 255, 255);
}
void CChildGridDoc::OnColorBlue() {m_clrCurrentColor = RGB(0, 0, 255);
}
void CChildGridDoc::OnColorWhite() {m_clrCurrentColor = RGB(255, 255, 255);
}
void CChildGridDoc::OnUpdateColorRed(CCmdUI* pCmdUI) {pCmdUI->SetRadio(m_clrCurrentColor == RGB(255, 0, 0));
}
void CChildGridDoc::OnUpdateColorYellow(CCmdUI* pCmdUI) {pCmdUI->SetRadio(m_clrCurrentColor == RGB(255, 255, 0));
}
void CChildGridDoc::OnUpdateColorGreen(CCmdUI* pCmdUI) {pCmdUI->SetRadio(m_clrCurrentColor == RGB(0, 255, 0));
}
void CChildGridDoc::OnUpdateColorCyan(CCmdUI* pCmdUI) {pCmdUI->SetRadio(m_clrCurrentColor == RGB(0, 255, 255));
}
void CChildGridDoc::OnUpdateColorBlue(CCmdUI* pCmdUI) {pCmdUI->SetRadio(m_clrCurrentColor == RGB(0, 0, 255));
}
void CChildGridDoc::OnUpdateColorWhite(CCmdUI* pCmdUI) {pCmdUI->SetRadio(m_clrCurrentColor == RGB(255, 255, 255));
}</span>


视图文件中,进行绘画视图设计:
1.实现视图的OnDraw()函数

<span style="font-size:18px;">void CChildGridView::OnDraw(CDC* pDC)
{CChildGridDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;
//绘图代码//设备环境映射方式,定义将逻辑单位转换为设备单位,并定义了的X、Y轴方向。pDC->SetMapMode( MM_LOENGLISH );for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {COLORREF color = pDoc->GetSquare(i, j);CBrush brush(color);int x1 = (j * 100) + 50;int y1 = (i * -100) - 50;int x2 = x1 + 100;int y2 = y1 - 100;CRect rect(x1, y1, x2, y2);pDC->FillRect(rect, &brush);}}//画网格线for (int x = 50; x <= 450; x += 100) {pDC->MoveTo(x, -50);pDC->LineTo(x, -450);}for (int y = -50; y >= -450; y -= 100) {pDC->MoveTo(50, y);pDC->LineTo(450, y);}
}</span>

如图所示:

2.添加鼠标单击左键消息响应代码

此时,我们已经具备了基本的功能,但是我们并不能进行操作;那是因为我们没有定义触发重新绘图的消息。下面以单击鼠标左键消息为例,进行设计:
<span style="font-size:18px;">void CChildGridView::OnLButtonDown(UINT nFlags, CPoint point)
{CView::OnLButtonDown(nFlags, point);CClientDC dc(this);//定义当前窗口客户区的设备描述表dc.SetMapMode(MM_LOENGLISH);//设定客户区的坐标系CPoint pos = point;//设备坐标系下,鼠标单击的位置坐标//鼠标单击坐标由设备坐标系变换到逻辑坐标系中,依赖于设备的图形模式dc.DPtoLP(&pos);if (pos.x >= 50 && pos.x <= 450 && pos.y <= -50 && pos.y >= -450) {int i = (-pos.y - 50) / 100;int j = (pos.x - 50) / 100;CChildGridDoc* pDoc = GetDocument();COLORREF clrCurrentColor = pDoc->GetCurrentColor();pDoc->SetSquare(i, j, clrCurrentColor);}
}</span>

这里只需要关心一件事,就是坐标系统一的问题。函数获得的坐标是在设备坐标系下,我们应该把他统一在逻辑坐标系中。所以对于鼠标响应消息以及画图部分,还是建议将所有工作都放在逻辑坐标系的模式下进行。

定时以及轮盘赌算法采用的是开源类包,这里不再赘述。

3.项目开发中的感悟与体会

1.公用接口函数是文档和视图沟通的唯一桥梁,强烈反对友元处理。
2.文档中的数据是保护类型,类间访问只能通过接口函数,此外对数据的处理也是在文档中进行。

深入理解文档/视图框架体系_九宫格项目开发感悟相关推荐

  1. wxWidgets:文档/视图框架

    wxWidgets:文档/视图框架 wxWidgets:文档/视图框架 wxDocument 概览 wxView 概览 wxDocTemplate 概述 wxDocManager 概述 文档/视图框架 ...

  2. MFC文档/视图结构体系及SDI回顾(2)

    1.牢骚发在最前面 三件事情杂糅到了一起弄得我彻夜未眠. 香港大学的Offer不小心丢在了垃圾邮箱里,却阴差阳错的来了清华.平台是一方面,当时谈好的港府奖学金也就此泡汤,这笔钱是我急需的. 惊闻噩耗, ...

  3. MFC 文档 视图 框架窗口间的关系 和消息传送规律

    在MFC中引入了文档-视结构的概念,文档相当于数据容器,视相当于查看数据的窗口或是和数据发生交互的窗口.因此一个完整的应用一般由四个类组成:CWinApp应用类,CFrameWnd窗口框架类,CDoc ...

  4. 深入浅出MFC文档/视图架构之文档

    1.文档类CDocument 在"文档/视图"架构的MFC程序中,文档是一个CDocument派生对象,它负责存储应用程序的数据,并把这些信息提供给应用程序的其余部分.CDocum ...

  5. C++--深入分析MFC文档视图结构(项目实践)

    1 必备基础知识概述 1.1 MFC 文档视图结构程序结构总揽 当我们使用 MFC AppWizard 生成一个 MFC 程序,选用所有默认的设置(当然也是 Multiple Documents ,本 ...

  6. 深入分析MFC文档视图结构(项目实践)

    文档视图结构(Document/View Architecture)是MFC的精髓,也是Observer模式的具体实现框架之一,Document/View Architecture通过将数据和其表示分 ...

  7. 玩转MFC文档视图架构编程1——深入浅出MFC文档/视图架构之基本概念深入浅出MFC文档/视图架构之文档

    原创地址: 深入浅出MFC文档/视图架构之基本概念 http://iis.xrtvu.com/Tech/ShowArticle.asp?ArticleID=276 深入浅出MFC文档/视图架构之文档模 ...

  8. MFC让文档/视图结构程序支持滚动条

    MFC让文档/视图结构程序支持滚动条 2009-06-30 09:26要通过滚动条显示文档,还必须知道文档滚动到了什么位置:一旦用户拖动滚动条时要告诉视图改变在文档中 的位置.所有这些,由MFC的CS ...

  9. 深入浅出MFC文档/视图架构之文档模板

    在"文档/视图"架构的MFC程序中,提供了文档模板管理者类CDocManager,由它管理应用程序所包含的文档模板.我们先看看这个类的声明: / // CDocTemplate m ...

最新文章

  1. CentOS yum源
  2. python基础——Linux系统下的文件目录结构
  3. logback 配置文件编写
  4. 【v3.6.2】iNeuOS工业互联网操作系统,发布实时存储方式:实时存储、变化存储、定时存储,设备振动状态和电能状态监测驱动...
  5. D3 Handling Events
  6. [Git问题解决error: The followin]The following untracked working tree files would be overwritten by merge
  7. ActiveMQ 下载和安装
  8. 移动端自动化测试:python+appium+pytest+allure+yaml
  9. 淘宝首页中meta标签的作用整理
  10. python 等值线插值,CartoPy等值线的插值方法
  11. 台式计算机英特尔时间同步,我电脑时间没法与Inter同步,?
  12. 【VBox】解决复制VBox虚拟机后提示硬盘UUID 已经存在的问题
  13. 时寒冰说经济大棋局我们怎么办_女王的棋局:艺术才华是闯天下的最佳武器
  14. c语言编写程序p1207.c,《C语言程序设计》(卷)考核班级
  15. java 消除png 锯齿_java Graphics2d消除锯齿,使字体平滑显示
  16. 商场导航反向寻车方案及造价分析
  17. cocos2d-x教程和项目实例集合
  18. python检测键盘输入termios、等待按键超时检测
  19. echart图片库_附录:ECharts图属性介绍-统计图
  20. Neat Download Manager for Mac(多线程下载管理器)

热门文章

  1. 《C#高级编程》笔记系列第一弹-开篇
  2. HD_2553N皇后问题
  3. hdu 5616 Jam's balance(简单dp)
  4. POJ 3254 Corn Fields(状态压缩)
  5. BNUOJ 34978 汉诺塔
  6. NYOJ 711 最舒适的路线(并查集)
  7. django下载excel,使用django-excel插件
  8. 使用MyEclipse的注解提示功能以及快捷键总结
  9. System 和 Runtime 类
  10. 快速查找无序数组中的第K大数?