深入理解文档/视图框架体系_九宫格项目开发感悟
生活随笔
收集整理的這篇文章主要介紹了
深入理解文档/视图框架体系_九宫格项目开发感悟
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.項目起源以及采用文檔/視圖框架體系緣由
我們整天都在說:文檔保存項目的數據并處理項目上的數據;視圖通過關聯獲得文檔的數據并進行可視化;主窗口框架接收外部事件消息并進行消息分配。這句口頭禪感覺接觸過MFC的新手都能背得一字不差,然而,這到底講了一件啥事?我想用程序的語言進行變相的概括一下:數據變量定義在文檔類并進行保護,公用成員函數也被定義在文檔類,公用函數是文檔類與視圖類溝通的唯一橋梁。這個項目挺有意思,一方面關聯導師的項目。另一方法姐姐家的小孩3歲了,這是一個很好的方法練習小孩的辨色力以及反應能力。 軟件的視圖如下所示:
具體功能是:自動變色,調節時間變色,色差分析等。其實,利用對話框也能進行設計,不過數據交流太不方便,最終還是定下來采用文檔/視圖結構。
2.一步一步接觸項目的核心
<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.文檔中的數據是保護類型,類間訪問只能通過接口函數,此外對數據的處理也是在文檔中進行。總結
以上是生活随笔為你收集整理的深入理解文档/视图框架体系_九宫格项目开发感悟的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 根据url提取网站域名的方法小结
- 下一篇: 我所理解的离散傅里叶变换_DFT