590 likes | 768 Views
Creating Single Document Interface Applications. 建立單一文件介面的應用程式. Doc/View 架構. 在視窗應用程式中 , 資料的顯示與儲存係使用 Doc/View 的架構 Doc 物件用於管理視窗程式的資料儲存 View 物件則負責將 Doc 儲存的資料正確地顯示在視窗中 一個完整的視窗應用程式必需具備以下類別 App 類別 ( 應用程式類別 ) Frame 類別 ( 視窗框架類別 ) Document 類別 ( 文件類別 ) View 類別 ( 流覽類別 ).
E N D
Creating Single Document Interface Applications 建立單一文件介面的應用程式
Doc/View架構 • 在視窗應用程式中, 資料的顯示與儲存係使用Doc/View的架構 • Doc物件用於管理視窗程式的資料儲存 • View物件則負責將Doc儲存的資料正確地顯示在視窗中 • 一個完整的視窗應用程式必需具備以下類別 • App類別(應用程式類別) • Frame類別(視窗框架類別) • Document類別(文件類別) • View類別(流覽類別)
Creating An SDI Application • 利用AppWizard產生基本應用程式架構 • 應用程式類型 • 文件樣版字串:應用程式所要產生文件的副檔名(specifying the document file extension) • 副檔名:dhc • 產生的類別:指定View類別的基底類別 • 選取CView
Creating a line class • MFC(Microsoft Foundation Class)中並沒有line object class,僅有Point Object class(CPoint) • 在「類別檢視」中利用精靈加入類別 • 類別型態請選「泛用C++類別」, • 在精靈對話方塊中: • 類別名稱:Cline • 基底類別:Cobject • 繼承模式:Public
Creating a line class • 在類別中加入兩個CPoint物件變數,用於儲存線的兩點,存取模式為private • CPoint m_ptFrom; • CPoint m_ptTo; • 建立帶有兩個輸入參數的建構函式 • CLine(CPoint ptFrom, CPoint ptTo); • 用於設定m_ptFrom及m_ptTo這兩個成員資料的初始值
Add Draw Function • 加入一個Function 到Cline類別中,存取模式為public • void Cline::Draw(CDC* pDC) • 加入以下程式碼到Function中,實際執行在文件視窗畫線的功能 • pDC->MoveTo(m_ptFrom); • pDC->LineTo(m_ptTo);
在文件類別中加入相關的成員變數 • 宣告儲存CLine Object的陣列 • 利用精靈加在Document類別中 • 型別為CObArray • 可動態配置Array的空間以儲存使用者所畫的線段 • 可用來儲存繼承自CObject的物件(參考下頁的Array classes) • 名稱為m_oaLines • 存取模式為private
The Array Classes • CArray:A template class for creating your own array class • CByteArray:An array of Byte data types • CDWordArray:An array of DWORD data types. • CObArray:An array of classes derived from the Cobject base class • CPtrArray:An array of pointers(to any object or data type) • CStringArray:An array of Cstring objects • CUIntArray:An array of UNIT data types(unsigned integers) • CWordArray:An array of WORD data types
在文件類別中加入相關的成員函式 • 函式功能 • Getting the from and to points • Creating a new line object • Adding it to the object array • 函式定義內容 • 名稱:AddLine • 傳回值型態:Cline * • 傳入參數:CPoint ptFrom, CPoint ptTo
AddLine 函式內容 CLine *pLine=NULL; try { pLine = new CLine(ptFrom, ptTo); //Create a CLine object m_oaLines.Add(pLine); //Add the new line to the object array SetModifiedFlag(); //Mark the document as dirty } catch(CMemoryException* perr) { AfxMessageBox("Out of Memory", MB_ICONSTOP|MB_OK); if (pLine) { delete pLine; //delete it pLine = NULL; } perr->Delete(); //Delete the exception object } return pLine;
用法: Place a try section around the code that might have problem The try section should always be followed by one or more catch sections If a problem occurs during the code in the try section, the program immediately jumps to the catch sections 捕捉程式執行時的錯誤並加以處理 try { … } catch { … }
將Line Class的定義內容加到doc類別中 • 編輯SDISquigDoc.h(SDISquig為專案名稱) • 加入#include "Line.h “ • 原因:SDISquigDoc.cpp 有建立Line 物件 • 至此可先編譯程式
在Doc類別中加入「Getting the Line Count」功能 • 在Doc類別中加入函式 • 名稱為GetLineCount • 存取模式為public • 傳回值型態為int,沒有輸入參數 • 在函式中加入以下程式碼: • return (int)m_oaLines.GetCount() ;
在Doc類別中加入「Retrieving a Specific Line」功能 • 在Doc類別中加入函式 • 名稱為GetLine • 存取模式為public • 傳回值型態為Cline* • 一個輸入參數 • int iIndex • 在函式中加入以下程式碼: • return (CLine*)m_oaLines[iIndex];
Showing the Users • We have already built the capability into the document class to hold the drawing. • Now we need to add the functionality to the view object to read the user’s drawing input and to draw the image.
Add a member variable to the View class 以記錄前一次按下Mouse的位置 • Add a member variable to the View class • Type: CPoint • Name: m_ptPrevPos • Access: private
Adding the Mouse Events • 叫出View的快顯功能表並選取屬性指令,為以下事件建立事件程序 • WM_LBUTTONDOWN • WM_LBUTTONUP • WM_MOUSEMOVE
在CSDISquigView::LButtonDown()中加入以下程式碼 在CSDISquigView::LButtonUp中加入以下程式碼 WM_LBUTTONDOWN及WM_LBUTTONUP事件程序 if (GetCapture()==this) ReleaseCapture(); SetCapture(); m_ptPrevPos=point;
WM_MOUSEMOVE事件程序 • 在CSDISquigView::OnMouseMove中加入以下程式碼: if ((nFlags & MK_LBUTTON)==MK_LBUTTON) { if (GetCapture()==this) { CClientDC dc(this); CLine *pLine=GetDocument()->AddLine(m_ptPrevPos, point); pLine->Draw(&dc); m_ptPrevPos=point; } }
在View class的OnDraw函式加入以下程式碼 • The function OnDraw is called whenever the image presented to users needs to be redrawn • 加入以下程式碼到OnDraw中 int iCount = pDoc->GetLineCount(); if (iCount) { int iPos; CLine *pLine = NULL; for (iPos=0; iPos < iCount ; iPos++) { pLine = pDoc->GetLine(iPos); pLine->Draw(pDC); } }
Deleting the Current Drawing • SDI應用程式的DOC類別的基底類別為CDocument,此類別中有一個DeleteContens成員函式,在需要清除目前視窗內容時(如使用者開新檔案)將自動呼叫該函式。 • 在SDI的Doc類別中,覆寫上述函式 • 對Doc類別按右鍵並選取屬性 • 在屬性視窗中按覆寫鈕 • 選取DeleteContents • 將下一張投影片的程式碼加到DeleteContents函式中
Deleting the Current Drawing //Get the number of lines in the object array int iCount = (int)m_oaLines.GetCount(); int iPos; try { if (iCount) { //Loop through the array , deleting each object for (iPos=0; iPos < iCount ; iPos++) delete (CLine*)m_oaLines.GetAt(iPos); //Reset the array m_oaLines.RemoveAll(); } } catch (CMemoryException* perr) { //Display a message for the user, giving him or her the bad news perr->ReportError(); //Delete the exception object perr->Delete(); }
Saving and Restoring • There are two parts of serialization • When application data is stored on the system drive in the form of a file, it’s called serialization. • When the application state is restored from the file , it’s called deserialization. • Serialization in Visual C++ is accomplished through the Archive class
The serialization function • When an application is reading or writing a file , the document object’s Serialize function is called .
Saving and Restoring the Drawing • Find the serialization function in the doc class, 加入以下程式碼: //Pass the serialization on to the object array; m_oaLines.Serialize(ar);
Saving and Restoring the Drawing • Add a new function to the Line class(存取模式為public), 先加到.cpp • 加函式原型定義到.h中 void Serialize(CArchive &ar); void CLine::Serialize(CArchive &ar) { CObject::Serialize(ar); if (ar.IsStoring()) //writing ar << m_ptFrom << m_ptTo; else ar >> m_ptFrom >> m_ptTo; //reading }
Saving and Restoring the Drawing • VC++ must be told that a class should be serializable.To do this: • Open the Cline header file • Add DECLARE_SERIAL(CLine) just after the first line of the class definition. • (Line.h) class CLine : • public CObject • Open the source code file • Add IMPLEMENT_SERIAL (CLine, CObject, 1) just before the class constructor • (Line.cpp) #include "line.h" • 保留預設的建構函式(沒有輸入參數)
ID_COLOR_BLACK ID_COLOR_BLUE ID_COLOR_GREEN ID_COLOR_CYAN ID_COLOR_RED ID_COLOR_MAGENTA ID_COLOR_YELLOW ID_COLOR_WHITE Caption:&Black Modifying the Menu
Adding Color the the Cline Class • Add another member variable to the Cline class to hold the color of each line private: COLORREF m_crColor; • Modify the class constructor(.cpp及.h) CLine::CLine(CPoint ptFrom, CPoint ptTo, COLORREF crColor) { //設定兩個成員資料的初值 m_ptFrom = ptFrom; m_ptTo=ptTo; m_crColor=crColor; }
Adding color the Cline Class • Modify the Draw function to use the specified color void CLine::Draw(CDC* pDC) { //Create a pen CPen lpen(PS_SOLID, 1, m_crColor); //Set the new pen as the drawing object CPen* pOldPen = pDC->SelectObject(&lpen); //Draw the line pDC->MoveTo(m_ptFrom); pDC->LineTo(m_ptTo); //Reset the previous pen pDC->SelectObject(pOldPen); }
Adding color the Cline Class • Modify the Serialize function to save and restore the color information void CLine::Serialize(CArchive &ar) { CObject::Serialize(ar); if (ar.IsStoring()) //writing ar << m_ptFrom << m_ptTo << m_crColor; else ar >> m_ptFrom >> m_ptTo>>m_crColor; //reading }
Adding color to the Document • Add a member variable to hold the current color,存取模式為private. UINT m_nColor; • Add a color table to convert color IDs into RGB values,存取模式為public static const COLORREF m_crColors[8];
Adding color to the Document • Add the Color Table specification to the source code ,加在END_MESSAGE_MAP()之後 const COLORREF CSDISquigDoc::m_crColors[8]={ RGB(0, 0, 0), //Black RGB(0, 0, 255), //Blue RGB(0, 255, 0), //Green RGB(0, 255, 255), //Cyan RGB(255, 0, 0), //Red RGB(255, 0, 255), //Magenta RGB(255, 255, 0), //Yellow RGB(255, 255, 255), //White };
Adding color to the Document • 在OnNewDocument()中加入以下指令, 以設定顏色初始值 m_nColor=0; • Modify the AddLine function pLine = new CLine(ptFrom, ptTo, m_crColors[m_nColor] );
Adding color to the Document • Adding a function to return the current color,存取模式為public UINT CSDISquigDoc::GetColor(void) { //Return the current color return ID_COLOR_BLACK+m_nColor; }
為Color 的相關指令加事件處理程式 void CSDISquigDoc::OnColorBlack() { // TODO: 在此加入您的命令處理常式程式碼 //Set the current color to black m_nColor = ID_COLOR_BLACK - ID_COLOR_BLACK; } void CSDISquigDoc::OnUpdateColorBlack(CCmdUI *pCmdUI) { // TODO: 在此加入您的命令更新 UI 處理常式程式碼 //Determine if the Black menu entry should be checked pCmdUI->Enable(); pCmdUI->SetCheck(GetColor()==ID_COLOR_BLACK?1:0); }
為Color 的相關指令加事件處理程式 void CSDISquigDoc::OnColorBlue() { // TODO: 在此加入您的命令處理常式程式碼 m_nColor = ID_COLOR_BLUE - ID_COLOR_BLACK; } void CSDISquigDoc::OnUpdateColorBlue(CCmdUI *pCmdUI) { // TODO: 在此加入您的命令更新 UI 處理常式程式碼 pCmdUI->Enable(); pCmdUI->SetCheck(GetColor()==ID_COLOR_BLUE?1:0); }
加入顏色工具列 • 程序如slide39~slide41 • 將每一個工具按鈕的ID設成和Color底下的功能指令ID一樣 • 每一個工具按鈕的色彩如slide33, 調整方式為選取快顯功能表裡的「調整色彩」指令。 • 每一個工具按鈕的prompt 屬性值 • textOfStatusBar\ntextOfButton
修改或建立應用程式的工具列 • 在CMainFrame 類別中加入對應的宣告及程式碼: • 在MainFrm.h中宣告工具列物件變數 • CToolBar m_wndColorBar;
10-3 修改或建立應用程式的工具列 • 在MainFrm.C的OnCreate函式中,加入對應程式碼: • 呼叫CToolBar ::CreateEx函式建立工具列 • 呼叫CToolBar ::LoadToolBar函式載入工具列資源 • 呼叫CToolBar ::EnableDocking函式設定工具列可停泊在視窗的位置 • 呼叫CFrameWnd:: EnableDocking函式設定視窗框架可供停泊工具列的位置 • 呼叫CFrameWnd::DockControlBar將工具列停泊在視窗框架中。
10-3 修改或建立應用程式的工具列 • 一些設定工具列形式的選項 • CBRS_ALIGN_TOP:將工具列停留在視窗框架的上端 • CBRS_ALIGN_BOTTOM:將工具列停留在視窗框架的下端 • CBRS_ALIGN_LEFT:將工具列停留在視窗框架的左端 • CBRS_ALIGN_RIGHT:將工具列停留在視窗框架的右端 • CBRS_ALIGN_ANY:工具列可停留在視窗框架的任何一端 • CBRS_BORDER_TOP:在工具列的頂端建立外框 • CBRS_BORDER_BOTTOM:在工具列的下端建立外框 • CBRS_BORDER_LEFT:在工具列的左端建立外框 • CBRS_BORDER_RIGHT:在工具列的右端建立外框 • CBRS_FLYBY:當滑鼠游標停留在工具按鈕上方時,將在狀態列顯示該按鈕的說明。
Adding width to the line class • Add another member variable to the Cline class to hold the width of each line private: UINT m_lnWidth; • Modify the class constructor(.cpp及.h) CLine::CLine(CPoint ptFrom, CPoint ptTo,COLORREF crColor, UINT lnWidth) { //設定兩個成員資料的初值 m_ptFrom = ptFrom; m_ptTo=ptTo; m_crColor=crColor; m_lnWidth=lnWidth; }
Adding width to the line class • Modify the Draw function to use the specified width void CLine::Draw(CDC* pDC) { //Create a pen CPen lpen(PS_SOLID,m_lnWidth, m_crColor); //Set the new pen as the drawing object CPen* pOldPen = pDC->SelectObject(&lpen); //Draw the line pDC->MoveTo(m_ptFrom); pDC->LineTo(m_ptTo); //Reset the previous pen pDC->SelectObject(pOldPen); }
Adding width to the line class • Modify the Serialize function to save and restore the width information CObject::Serialize(ar); if (ar.IsStoring()) //writing ar << m_ptFrom << m_ptTo << m_crColor << m_lnWidth; else //reading ar >> m_ptFrom >> m_ptTo >> m_crColor >> m_lnWidth;
Adding width to the Document • Add a member variable to hold the current width,存取模式為private. UINT m_nWidth; • Add a width table to convert width IDs into width values,存取模式為public static const UINT m_lnWidths[5];
Adding width to the Document • Add the WidthTable specification to the source code ,加在END_MESSAGE_MAP()之後 Const UINT CSDISquigDoc::m_lnWidths[5]={ 1, //VeryThin 8, //Thin 16, //Medium 24, //Thick 32, //Very Thick };
Adding Width to the Document • 在OnNewDocument()中加入以下指令, 以設定線條粗細初始值 m_nWidth=0; • Modify the AddLine function pLine = new CLine(ptFrom, ptTo, m_crColors[m_nColor], m_lnWidths[m_nWidth]);
Adding width to the Document • Adding a function to return the current width,存取模式為public UINT CSDISquigDoc::GetWidth(void) { //Return the current width return ID_WIDTH_VERYTHIN+m_nWidth; }
Modifying the Menu • ID_WIDTH_VERYTHIN • ID_WIDTH_THIN • ID_WIDTH_MEDIUM • ID_WIDTH_THICK • ID_WIDTH_VERYTHICK
為Width 的相關指令加事件處理程式 void CSDISquigDoc::OnWidthVerythin() { // TODO: 在此加入您的命令處理常式程式碼 //Set the current width to very thin m_nWidth = ID_WIDTH_VERYTHIN - ID_WIDTH_VERYTHIN; } void CSDISquigDoc::OnUpdateWidthVerythin(CCmdUI *pCmdUI) { // TODO: 在此加入您的命令更新 UI 處理常式程式碼 //Determine if the Very Thin menu entry should be checked pCmdUI->Enable(); pCmdUI->SetCheck(GetWidth()==ID_WIDTH_VERYTHIN?1:0); }