第6章數(shù)據(jù)和文檔.ppt_第1頁
第6章數(shù)據(jù)和文檔.ppt_第2頁
第6章數(shù)據(jù)和文檔.ppt_第3頁
第6章數(shù)據(jù)和文檔.ppt_第4頁
第6章數(shù)據(jù)和文檔.ppt_第5頁
已閱讀5頁,還剩41頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、第6章數(shù)據(jù)和文檔,6.1CString類,6.2使用簡單數(shù)組集合類,6.3使用CFile類,6.4文檔序列化,6.5綜合應(yīng)用,6.1CString類,6.1.1 BSTR、const char*、LPCTSTR和CString 什么是BSTR、LPSTR以及LPWSTR呢? BSTR(Basic STRing,Basic字符串)是一個OLE CHAR*類型的Unicode字符串。它被描述成一個與自動化相兼容的類型。由于操作系統(tǒng)提供相應(yīng)的API函數(shù)(如SysAllocString)來管理它以及一些默認(rèn)的調(diào)度代碼,因此BSTR實際上就是一個COM字符串,但它卻在自動化技術(shù)以外的多種場合下也得到了較

2、為廣泛的使用。 LPSTR和LPWSTR是Win32和Visual C+所使用的一種字符串?dāng)?shù)據(jù)類型。LPSTR被定義成是一個指向以NULL(0)結(jié)尾的8位ANSI字符數(shù)組指針,而LPWSTR是一個指向以NULL結(jié)尾的16位雙字節(jié)字符數(shù)組指針。在Visual C+中,還有類似的字符串類型,如LPTSTR、LPCTSTR等,它們的含義如圖6.1所示。,圖6.1 字符串類型表示的含義,6.1CString類,例如,LPCTSTR是指“l(fā)ong pointer to a constant generic string”,表示“一個指向一般字符串常量的長指針類型”,與C/C+的const char*相映

3、射,而LPTSTR映射為 char*。 一般地,Visual C+中還有下列類型定義: #ifdef UNICODE typedef LPWSTR LPTSTR; typedef LPCWSTR LPCTSTR; #else typedefLPSTR LPTSTR; typedef LPCSTR LPCTSTR; #endif,6.1CString類,CString類支持字符串類型,并可通過CString類構(gòu)造函數(shù)和一些運算符進行構(gòu)造。CString類構(gòu)造函數(shù)原型如下: CString( ); CString( const CString / 從C語言樣式的字符串來創(chuàng)建city,6.1CStr

4、ing類,當(dāng)然,也可使用CString類的Format成員函數(shù)將任意數(shù)據(jù)類型轉(zhuǎn)換成CString字符串。Format成員函數(shù)使用C語言的printf的格式樣式進行創(chuàng)建,例如: CString str; str.Format( Floating point: %.2fn, 12345.12345); str.Format( Left-justified integer: %.6dn, 35); 若將一個CString字符串向上述字符串類型進行轉(zhuǎn)換,則可使用CString類提供了的const char*、LPCTSTR運算符以及AllocSysString和SetSysString成員函數(shù)等。例如

5、: / 將CString向LPTSTR轉(zhuǎn)換的方法一 CString theString( This is a test ); LPTSTR lpsz = new TCHARtheString.GetLength()+1; / TCHAR在Unicode平臺中等同于WCHAR(16位Unicode字符),在ANSI中等價于char。 _tcscpy( lpsz, theString); / 將CString向LPTSTR轉(zhuǎn)換的方法二 CString theString( This is a test ); LPTSTR lpsz = (LPTSTR)(LPCTSTR)theString; / 將

6、CString向BSTR轉(zhuǎn)換 CString str(This is a test); BSTR bstrText = str.AllocSysString(); SysFreeString(bstrText); / 用完釋放,6.1CString類,6.1.2 字符串的字符訪問 在CString類中,可以用SetAt和GetAt來設(shè)置或獲取指定字符串中的字符,也可以使用運算符“ ”來直接操作。它們的函數(shù)原型描述如下: void SetAt( int nIndex, TCHAR ch ); 其中,參數(shù)nIndex用來指CString對象中的某個字符的索引(從零開始),它的值必須大于或等于0,且

7、應(yīng)小于由GetLength的返回的值。ch用來指定要插入的字符。這樣,就可將一個CString對象看作是一個字符數(shù)組,SetAt成員函數(shù)用來改寫指定索引的字符。 TCHAR GetAt( int nIndex ) const; 該函數(shù)用來返回由nIndex指定索引位置(從零開始)的TCHAR字符。例如: CString str( abcdef ); ASSERT( str.GetAt(2) = c ); / 斷言返回的字符與c相等。在MFC中,斷言機制常用于調(diào)試,當(dāng)斷言失敗后,程序在此中斷, / 然后彈出對話框,詢問是否進入調(diào)試或選擇其他操作 TCHAR operator ( int nInd

8、ex ) const; 這是一個運算符重載函數(shù),即將一個CString對象看作是一個字符數(shù)組,使用下標(biāo)運行符“”,通過指定下標(biāo)值nIndex來獲取相應(yīng)的字符。例如: CString str( abc ); ASSERT( str1 = b );,6.1CString類,6.1.3 清空及字符串長度 清空CString對象可用Empty函數(shù),判斷CString對象是否為空用函數(shù)IsEmpty,獲取CString對象的字符串長度用函數(shù)GetLength,它們的原型如下: void Empty( ); 該函數(shù)強迫CString對象為空(字符串長度為0)并釋放相應(yīng)的內(nèi)存。 BOOL IsEmpty(

9、) const; 該函數(shù)用來判斷CString對象是否為空(字符串長度為0),“是”為TRUE,“否”為FALSE。 int GetLength( ) const; 該函數(shù)用來獲取CString對象的字符串長度(字符個數(shù)),這個長度不包括字符串結(jié)尾的結(jié)束符。例如: CString s( abcdef ); ASSERT( s.GetLength() = 6 ); 6.1.4 提取和大小寫轉(zhuǎn)換 CString類提供許多用來從一個字符串中提取部分字符串的操作函數(shù),也提供了大小寫轉(zhuǎn)換函數(shù)。下面分別說明。 CString Left( int nCount ) const; 該函數(shù)用來從CString對

10、象中提取最前面的nCount個字符作為要提取的子字符串(簡稱子串)。如果nCount超過了字符串的長度,則整個字符串都被抽取。 CString Mid( int nFirst ) const; CString Mid( int nFirst, int nCount ) const;,6.1CString類,該函數(shù)函數(shù)用從CString對象中提取一個從nFirst(從零開始的索引)指定的位置開始的nCount個字符的子串。若nCount不指定,則提取的子串是從nFirst開始直到字符串結(jié)束。 CString Right( int nCount ) const; 該函數(shù)用來從CString對象中提

11、取最后面的nCount個字符作為要提取的子字符串。如果nCount超過了字符串的長度,則整個字符串都被抽取。 void MakeLower( ); 該函數(shù)用來將CString對象的所有字符轉(zhuǎn)換成小寫字符。 void MakeUpper( ); 該函數(shù)用來將CString對象的所有字符轉(zhuǎn)換成大寫字符。 void TrimLeft( ); void CString:TrimLeft( TCHAR chTarget ); void CString:TrimLeft( LPCTSTR lpszTargets ); 該函數(shù)用來將CString對象最左邊的空格、空格和tab字符或chTarget指定的字符

12、或lpszTargets指定的子串刪除。 void TrimRight( ); void CString:TrimRight( TCHAR chTarget ); void CString:TrimRight( LPCTSTR lpszTargets );,6.1CString類,該函數(shù)用來將CString對象最后邊的空格、空格和tab字符或chTarget指定的字符或lpszTargets指定的子串刪除。 例如: CString strBefore; CString strAfter; strBefore = Hockey is Best! ; strAfter = strBefore; s

13、trAfter.TrimRight(! ); / strAfter中的字符串“Hockey is Best!”變成了“Hockey is Best” strBefore =Hockey is Best?!?!?!?! ; strAfter = strBefore; strAfter.TrimRight(?!?); / strAfter中的字符串“Hockey is Best?!?!?!?!”變成了“Hockey is Best”,6.2使用簡單數(shù)組集合類,1. 簡單數(shù)組集合類的構(gòu)造及元素的添加 對簡單數(shù)組集合類構(gòu)造的方法都是一樣的,均是使用各自的構(gòu)造函數(shù),它們的原型如下: CByteArray

14、 CByteArray( ); CDWordArray CDWordArray( ); CObArray CObArray( ); CPtrArray CPtrArray( ); CStringArray CStringArray( ); CUIntArray CUIntArray( ); CWordArray CWordArray( ); 下面的代碼說明了簡單數(shù)組集合類的兩種構(gòu)造方法: CObArray array; / 使用默認(rèn)的內(nèi)存塊大小 CObArray* pArray = new CObArray; / 使用堆內(nèi)存中的默認(rèn)的內(nèi)存塊大小 為了有效使用內(nèi)存,在使用簡單數(shù)組集合類之前最好調(diào)

15、用成員函數(shù)SetSize 設(shè)置此數(shù)組的大小,與其對應(yīng)的函數(shù)是GetSize,用來返回數(shù)組的大小。它們的原型如下: void SetSize( int nNewSize, int nGrowBy = -1 ); int GetSize( ) const;,6.2使用簡單數(shù)組集合類,其中,參數(shù)nNewSize用來指定新的元素的數(shù)目(必須大小或等于0)。nGrowBy表示當(dāng)數(shù)組需要擴展時允許可添加的最少元素數(shù)目,默認(rèn)時為自動擴展。 向簡單數(shù)組集合類添加一個元素,可使用成員函數(shù)Add和Append,它們的原型如下: int Add( CObject* newElement ); int Append(

16、 const CObArray 其中,Add函數(shù)是向數(shù)組的末尾添加一個新元素,且數(shù)組自動增1。如果調(diào)用的函數(shù)SetSize的參數(shù)nGrowBy 的值大于1,那么擴展內(nèi)存將被分配。此函數(shù)返回被添加的元素序號,元素序號就是數(shù)組下標(biāo)。參數(shù)newElement表示要添加的相應(yīng)類型的數(shù)據(jù)元素。而Append函數(shù)是向數(shù)組的末尾添加由src指定的另一個數(shù)組的內(nèi)容。函數(shù)返回加入的第一個元素的序號。,6.2使用簡單數(shù)組集合類,2. 訪問簡單數(shù)組集合類的元素 在MFC中,一個簡單數(shù)組集合類元素的訪問既可以使用GetAt函數(shù),也可使用“”操作符,例如: / CObArray:operator 示例 CObArray

17、 array; CAge* pa;/ CAge是一個用戶類 array.Add( new CAge( 21 ) ); / 添加一個元素 array.Add( new CAge( 40 ) ); / 再添加一個元素 pa = (CAge*)array0; / 獲取元素0 array0 = new CAge( 30 ); / 替換元素0; / CObArray:GetAt示例 CObArray array; array.Add( new CAge( 21 ) ); / 元素 0 array.Add( new CAge( 40 ) ); / 元素 1,6.2使用簡單數(shù)組集合類,3. 刪除簡單數(shù)組集合

18、類的元素 刪除簡單數(shù)組集合類中的元素一般需要進行以下幾個步驟: (1)使用函數(shù)GetSize和整數(shù)下標(biāo)值訪問簡單數(shù)組集合類中的元素。 (2)若對象元素是在堆內(nèi)存中創(chuàng)建的,則使用delete操作符刪除每一個對象元素。 (3)調(diào)用函數(shù)RemoveAll刪除簡單數(shù)組集合類中的所有元素。 例如,下面代碼是一個CObArray的刪除示例: CObArray array; CAge* pa1; CAge* pa2; array.Add( pa1 = new CAge( 21 ) ); array.Add( pa2 = new CAge( 40 ) ); ASSERT( array.GetSize() =

19、2 ); for (int i=0;iarray.GetSize();i+) delete array.GetAt(i); array.RemoveAll(); 需要說明的是:函數(shù)RemoveAll是刪除數(shù)組中的所有元素,而函數(shù)RemoveAt( int nIndex, int nCount = 1)則表示要刪除數(shù)組中從序號為nIndex元素開始的,數(shù)目為nCount的元素。,6.3使用CFile類,6.3.1 文件的打開和關(guān)閉 在MFC中,使用CFile打開一個文件通常使用下列兩個步驟: 構(gòu)造一個不帶任何參數(shù)的CFile對象; (1)調(diào)用成員函數(shù)Open并指定文件路徑以及文件標(biāo)志。 (2)C

20、File類的Open函數(shù)原型如下: BOOL Open( LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL ); 其中,lpszFileName用來指定一個要打開的文件路徑,該路徑可以是相對的、絕對的或是一個網(wǎng)絡(luò)文件名(UNC)。nOpenFlags用來指定文件打開的標(biāo)志,它的值見表6.1。pError用來表示操作失敗產(chǎn)生的CFileException指針,CFileException是一個與文件操作有關(guān)的異常處理類。函數(shù)Open操作成功時返回TRUE,否則為FALSE。,6.3使用CFile類,表6.1

21、CFile類的文件訪問方式,6.3使用CFile類,例如,下面的代碼將顯示如何用讀寫方式創(chuàng)建一個新文件: char* pszFileName = c:testmyfile.dat; CFile myFile; CFileException fileException; if ( !myFile.Open( pszFileName, CFile:modeCreate | CFile:modeReadWrite ), 代碼中,若文件創(chuàng)建打開有任何問題,Open函數(shù)將在它的最后一個參數(shù)中返回CFileException(文件異常類)對象,TRACE宏將顯示出文件名和表示失敗原因的代碼。使用AfxTh

22、rowFileException函數(shù)將獲得更詳細(xì)的有關(guān)錯誤的報告。 與文件“打開”相反的操作是“關(guān)閉”,可以使用Close函數(shù)來關(guān)閉一個文件對象,若該對象是在堆內(nèi)存中創(chuàng)建的,還需調(diào)用delete來刪除它(不是刪除物理文件)。,6.3使用CFile類,6.3.2 文件的讀寫和定位 CFile類支持文件的讀、寫和定位操作。它們相關(guān)函數(shù)的原型如下: UINT Read( void* lpBuf, UINT nCount ); 此函數(shù)將文件中指定大小的數(shù)據(jù)讀入指定的緩沖區(qū),并返回向緩沖區(qū)傳輸?shù)淖止?jié)數(shù)。需要說明的是,這個返回值可能小于nCount,這是因為可能到達了文件的結(jié)尾。 void Write(

23、const void* lpBuf, UINT nCount ); 此函數(shù)將緩沖區(qū)的數(shù)據(jù)寫到文件中。參數(shù)lpBuf用來指定要寫到文件中的數(shù)據(jù)緩沖區(qū)的指針,nCount表示從數(shù)據(jù)緩沖區(qū)傳送的字節(jié)數(shù)。對于文本文件,每行的換行符也被計算在內(nèi)。 LONG Seek( LONG lOff, UINT nFrom ); 此函數(shù)用來定位文件指針的位置,若要定位的位置是有效的,則此函數(shù)將返回從文件開始的偏移量。否則,返回值是不定的且激活一個CFileException對象。參數(shù)lOff用來指定文件指針移動的字節(jié)數(shù),nFrom表示指針移動方式,它可以是CFile:begin(從文件的開始位置)、CFile:cu

24、rrent(從文件的當(dāng)前位置)或CFile:end(從文件的最后位置,但lOff必須為負(fù)值才能在文件中定位,否則將超出文件)等。需要說明的是,文件剛打開時,默認(rèn)的文件指針位置為0,即文件的開始位置。 另外,函數(shù)void SeekToBegin( )和DWORD SeekToEnd( )分別將文件指針移動到文件開始和結(jié)尾位置,對于后者還將返回文件的大小。,6.3使用CFile類,6.3.3 獲取文件的有關(guān)信息 CFile 還支持獲取文件狀態(tài),包括文件是否存在、創(chuàng)建與修改的日期和時間、邏輯大小和路徑等。 BOOL GetStatus( CFileStatus 若指定文件的狀態(tài)信息成功獲得,該函數(shù)返

25、回TRUE,否則返回FALSE。其中,參數(shù)lpszFileName用來指定一個文件路徑,這個路徑可以是相對的或是絕對的,但不能是 網(wǎng)絡(luò)文件名。rStatus用來存放文件狀態(tài)信息,它是一個CFileStatus結(jié)構(gòu)類型,該結(jié)構(gòu)具 有下列成員: CTime m_ctime 文件創(chuàng)建日期和時間 CTime m_mtime 文件最后一次修改日期和時間 CTime m_atime 文件最后一次訪問日期和時間 LONGm_size 文件大小的字節(jié)數(shù) BYTE m_attribute 文件屬性 char m_szFullName_MAX_PATH 文件名,6.3使用CFile類,需要說明的是,static形

26、式的GetStatus函數(shù)將獲得指定文件名的文件狀態(tài),并將文件名復(fù)制至m_szFullName中。該函數(shù)僅獲取文件狀態(tài),并沒有真正打開文件,這對于測試一個文件的存在性是非常有用的。例如下面的代碼: CFile theFile; char* szFileName = c:testmyfile.dat; BOOL bOpenOK; CFileStatus status; if( CFile:GetStatus( szFileName, status ) ) / 該文件已存在,直接打開 bOpenOK = theFile.Open( szFileName, CFile:modeWrite ); el

27、se / 該文件不存在,需要使用modeWrite方式創(chuàng)建它 bOpenOK = theFile.Open( szFileName, CFile:modeCreate | CFile:modeWrite ); ,6.3使用CFile類,6.3.4 CFile示例 如圖6.2所示,單擊瀏覽按鈕,將彈出文件“打開”對話框,從中選擇一個文件時,編輯框上方顯示出該文件的路徑名、創(chuàng)建時間和文件大小,并在編輯框中顯示出該文件的內(nèi)容。,圖6.2 CFile示例運行結(jié)果,6.3使用CFile類,例Ex_File 使用CFile (1)創(chuàng)建一個默認(rèn)的對話框應(yīng)用程序Ex_File。 (2)將對話框的標(biāo)題設(shè)為“使用

28、CFile”。刪除“TODO: 在這里設(shè)置對話控制?!膘o態(tài)文本控件和 取消按鈕,將確定按鈕標(biāo)題改為“退出”。 (3)打開對話框網(wǎng)格,參看圖6.2的控件布局,添加靜態(tài)文件控件IDC_STATIC_TITLE(選中“垂直居中”和“凹陷”選項)、一個編輯框IDC_EDIT1(選中“多行”、“水平滾動”、“垂直滾動”和“自動垂直滾動”選項)和一個“打開”按鈕IDC_BUTTON_OPEN。 (4)打開MFC ClassWizard的Member Variables頁面,為IDC_STATIC_TITLE控件添加Value類型變量m_strTitle,為IDC_EDIT1控件添加Value類型變量m_s

29、trContent。 (5)再次打開MFC ClassWizard,切換到Messsage Maps頁面,為CEx_FileDlg類添加按鈕IDC_BUTTON_OPEN 的BN_CLICKED消息映射,保留默認(rèn)的映射函數(shù)名,并添加下列代碼: (6)編譯運行并測試。,6.4文檔序列化,6.4.1 文檔模板和字串資源 1. 文檔模板 文檔應(yīng)用程序框架是在程序運行時就開始構(gòu)造的,在單文檔應(yīng)用程序(設(shè)為Ex_SDI)的應(yīng)用程序類InitInstance函數(shù)中,可以看到這樣的代碼: BOOL CEx_SDIApp:InitInstance() CSingleDocTemplate* pDocTempl

30、ate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME,/ 資源ID RUNTIME_CLASS(CEx_SDIDoc),/ 文檔類 RUNTIME_CLASS(CMainFrame), / 主框架窗口類 RUNTIME_CLASS(CEx_SDIView);/ 視圖類 AddDocTemplate(pDocTemplate); return TRUE; ,6.4文檔序列化,類似的,多文檔模板類CMultiDocTemplate的構(gòu)造函數(shù)也有相同的定義。如下面的代碼(設(shè)為Ex_MDI): BOOL CEx_MDIApp:InitIns

31、tance() CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_EX_MDITYPE,/ 資源ID RUNTIME_CLASS(CEx_MDIDoc),/ 文檔類 RUNTIME_CLASS(CChildFrame), / MDI文檔窗口類 RUNTIME_CLASS(CEx_MDIView);/ 視圖類 AddDocTemplate(pDocTemplate); / 創(chuàng)建主框架窗口 CMainFrame* pMainFrame = new CMainFrame; if (!pMainFram

32、e-LoadFrame(IDR_MAINFRAME) return FALSE; m_pMainWnd = pMainFrame; return TRUE; ,6.4文檔序列化,2. 文檔模板字串資源 從前面的單文檔模板類可以看出,為了能將菜單、加速鍵、圖標(biāo)等資源加載到應(yīng)用程序框架中,這些資源的標(biāo)識符都設(shè)為了IDR_MAINFRAME。事實上,在MFC文檔序列化流程(后面會討論到)中,文檔標(biāo)題和通用文件“打開”和“保存”對話框的過濾器中文件類型還必需能夠在相關(guān)的資源給予指定,這個資源就是文檔模板字串資源,它是String Table(字符串)資源列表中的IDR_MAINFRAME項,其內(nèi)容如下

33、(以單文檔應(yīng)用程序Ex_SDI為例): Ex_SDInnEx_SDInnnExSDI.DocumentnEx_SDI Document 可以看出,IDR_MAINFRAME所標(biāo)識的字符串被分成了一些以“n”結(jié)尾的子串,這些子串共有7段,每段都有特定的用途,其含義如表6.2所示。,6.4文檔序列化,表6.2 文檔模板字符串的含義,6.4文檔序列化,但對于MDI來說,上述的字串分別由IDR_MAINFRAME和IDR_EX_MDITYPE(若項目名為Ex_MDI)組成;其中,IDR_MAINFRAME表示窗口標(biāo)題,而IDR_EX_MDITYPE表示后6項內(nèi)容。它們的內(nèi)容如下: IDR_MAINFR

34、AME:Ex_MDI圖6.3 Advanced Options對話框5036214 IDR_EX_MDITYPE:nEx_MDInEx_MDInnnExMDI.DocumentnEx_MDI Document 實際上,文檔模板字串資源內(nèi)容既可直接通 過上述字串資源編輯器進行修改,也可以在文檔 應(yīng)用程序創(chuàng)建向?qū)У牡谒牟街?,單擊高級按鈕, 通過“高級選項(Advanced Options)”對話框 中的“文檔字符模板(Document Template Strings) ”頁面來指定,如圖6.3所示(以單文檔應(yīng)用程序 Ex_SDI為例)。圖中的數(shù)字表示該項的含義與 表6.3中對應(yīng)串號的含義相同。,

35、6.4文檔序列化,6.4.2 文檔序列化過程 MFC文檔序列化過程包括:創(chuàng)建空文檔、打開文檔、保存文檔和關(guān)閉文檔這幾個操作,下面來闡述它們的具體運行過程。 1. 創(chuàng)建空文檔 應(yīng)用程序類的InitInstance函數(shù)在調(diào)用了AddDocTemplate函數(shù)之后,會通過CWinApp: ProcessShellCommand間接調(diào)用CWinApp的另一個非常有用的成員函數(shù)OnFileNew,并依次完成下列工作: (1)構(gòu)造文檔對象,但并不從磁盤中讀數(shù)據(jù)。 (2)構(gòu)造主框架類CMainFrame的對象,并創(chuàng)建該主框架窗口,但不顯示。 (3)構(gòu)造視圖對象,并創(chuàng)建視圖窗口,也不顯示。 (4)通過內(nèi)部機制

36、,使文檔、主框架和視圖“對象”之間“真正”建立聯(lián)系。注意與 AddDocTemplate函數(shù)的區(qū)別,AddDocTemplate函數(shù)建立的是“類”之間的聯(lián)系。 (5)調(diào)用文檔對象的CDocument:OnNewDocument虛函數(shù),并調(diào)用CDocument: DeleteContents虛函數(shù)來清除文檔對象的內(nèi)容。,6.4文檔序列化,(6)調(diào)用視圖對象的CView:OnInitialUpdate虛函數(shù)對視圖進行初始化操作。 (7)調(diào)用框架對象的CFrameWnd:ActiveFrame虛函數(shù),以便顯示出帶有菜單、工具欄、狀態(tài)欄以及視圖窗口的主框架窗口。 在單文檔應(yīng)用程序中,文檔、主框架以及視

37、圖對象僅被創(chuàng)建一次,并且這些對象在整個運行過程中都有效。CWinApp:OnFileNew函數(shù)被InitInstance函數(shù)所調(diào)用。但當(dāng)用戶選擇“文件(File)”菜單中的“新建(New)”時,CWinApp:OnFileNew也會被調(diào)用,但與InitInstance不同的是,這種情況下不再創(chuàng)建文檔、主框架以及視圖對象,但上述過程的最后三個步驟仍然會被執(zhí)行。 2. 打開文檔 當(dāng)MFC AppWizard創(chuàng)建應(yīng)用程序時,它會自動將“文件(File)”菜單中的“打開(Open)”命令(ID號為ID_FILE_OPEN)映射到CWinApp的OnFileOpen成員函數(shù)。這一結(jié)果可以從應(yīng)用類(.cp

38、p)的消息入口處得到驗證: BEGIN_MESSAGE_MAP(CEx_SDIApp, CWinApp) ON_COMMAND(ID_FILE_NEW, CWinApp:OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp:OnFileOpen) / Standard print setup command ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp:OnFilePrintSetup) END_MESSAGE_MAP() OnFileOpen函數(shù)還會進一步完成下列工作:,6.4文檔序列化,(1)彈出通用文件“打開”對話框,供

39、用戶選擇一個文檔。 (2)文檔指定后,調(diào)用文檔對象的CDocument: OnOpenDocument虛函數(shù)。該函數(shù)將打開文檔,并調(diào)用DeleteContents清除文檔對象的內(nèi)容,然后創(chuàng)建一個CArchive對象用于 數(shù)據(jù)的讀取,接著又自動調(diào)用Serialize函數(shù)。 (3)調(diào)用視圖對象的CView:OnInitialUpdate虛函數(shù)。 除了使用“文件(File)”“打開(Open)”菜單項外,用戶也可以選擇最近使用過的文件列表來打開相應(yīng)的文檔。在應(yīng)用程序的運行過程中,系統(tǒng)會記錄下4個默認(rèn)最近使用過的文件,并將文件名保存在Windows的注冊表中。當(dāng)每次啟動應(yīng)用程序時,應(yīng)用程序都會最近使用

40、過的文件名稱顯示在“文件(File)”菜單中。 3. 保存文檔 (1)當(dāng)MFC AppWizard創(chuàng)建應(yīng)用程序時,它會自動將“文件(File)”菜單中的“保存(Save)”命令與文檔類CDocument的OnFileSave函數(shù)在內(nèi)部關(guān)聯(lián)起來,但用戶在程序框架中看不到相應(yīng)的代碼。OnFileSave函數(shù)還會進一步完成下列工作: (2)彈出通用文件“保存”對話框,讓用戶提供一個文件名。 (3)調(diào)用文檔對象的CDocument:OnSaveDocument虛函數(shù),接著又自動調(diào)用Serialize函數(shù),將CArchive對象的內(nèi)容保存在文檔中。,6.4文檔序列化,需要說明的是: 只有在保存文檔之前還

41、沒有存過盤(亦即沒有文件名)或讀取的文檔是“只讀”的, OnFileSave函數(shù)才會彈出通用“保存”對話框。否則,只執(zhí)行第二步。 “文件(File)”菜單中還有一個“另存為(Save As)”命令,它是與文檔類CDocument的 OnFileSaveAs函數(shù)相關(guān)聯(lián)。不管文檔有沒有保存過,OnFileSaveAs都會執(zhí)行上述兩個步驟。 上述文檔存盤的必要操作都是由系統(tǒng)自動完成的。 4. 關(guān)閉文檔 當(dāng)用戶試圖關(guān)閉文檔(或退出應(yīng)用程序)時,應(yīng)用程序會根據(jù)用戶對文檔的修改與否來進一步完成下列任務(wù): (1)若文檔內(nèi)容已被修改,則彈出一個消息對話框,詢問用戶是否需要將文檔保存。當(dāng)用戶選擇“是”,則應(yīng)用程

42、序執(zhí)行OnFileSave過程。 (2)調(diào)用CDocument:OnCloseDocument虛函數(shù),關(guān)閉所有與該文檔相關(guān)聯(lián)的文檔窗口及相應(yīng)的視圖,調(diào)用文檔類CDocument的DeleteContents清除文檔數(shù)據(jù)。,6.4文檔序列化,6.4.3 CArchive類和序列化操作 從上述的單文檔序列化過程可以看出:打開和保存文檔時,系統(tǒng)都會自動調(diào)用Serialize函數(shù)。事實上,MFC AppWizard在創(chuàng)建文檔應(yīng)用程序框架時已在文檔類中重載了Serialize函數(shù),通過在該函數(shù)中添加代碼可達到實現(xiàn)數(shù)據(jù)序列化的目的。例如,在Ex_SDI單文檔應(yīng)用程序的文檔類中有這樣的默認(rèn)代碼: void

43、CEx_SDIDoc:Serialize(CArchive/ 讀寫數(shù)據(jù)時使用 CString m_strArchive; / 讀寫數(shù)據(jù)時使用 BOOL m_bIsMyDoc;/ 用于判斷文檔 (4)在CEx_SDIArchiveDoc類構(gòu)造函數(shù)中添加下列代碼: CEx_SDIArchiveDoc:CEx_SDIArchiveDoc() m_bIsMyDoc = FALSE; (5)在CEx_SDIArchiveDoc:OnNewDocument函數(shù)中添加下列代碼: BOOL CEx_SDIArchiveDoc:OnNewDocument() if (!CDocument:OnNewDocume

44、nt() return FALSE; strcpy(m_chArchive, ,6.4文檔序列化,(6)在CEx_SDIArchiveDoc:Serialize函數(shù)中添加下列代碼: (7)編譯運行并測試。程序運行后,選擇“文件”“另存為”菜單,指定一個文檔名1.my,然后選擇“文件”“新建”菜單,再打開該文檔,結(jié)果就會彈出對話框,顯示該文檔的內(nèi)容,如圖6.4所示。,圖6.4 顯示文檔內(nèi)容,6.4文檔序列化,6.4.4 CArchive類和CFile類關(guān)聯(lián) 事實上,文檔應(yīng)用程序框架就是將一個外部磁盤文件和一個CArchive 對象關(guān)聯(lián)起來。當(dāng)然,這種關(guān)聯(lián)還可直接通過CFile來進行。例如: CF

45、ile theFile; theFile.Open(., CFile:modeWrite); CArchive archive(,6.5綜合應(yīng)用,在用文件來存取數(shù)據(jù)時,最大的難度是要保證讀取的數(shù)據(jù)的正確性。若有一個記錄結(jié)構(gòu),包括學(xué)生的姓名(字符串)、學(xué)號(字符串)以及三門課程成績,則如何保證在文件讀寫的正確性呢?一種辦法是將記錄定義成C結(jié)構(gòu)體類型,使用CFile來操作,這是避開MFC文檔序列化機制而進行的方法,雖有效但缺少對MFC機制和類的應(yīng)用,因為在C+中,C結(jié)構(gòu)體被看作是類的一種簡單形式。另一種方法,是將記錄聲明成一個類,并使該類具體可序列化特性。一個可序列化的類的對象可以在Seriali

46、ze函數(shù)使用CArchive對象通過“”來正確地向文件進行寫入和讀取操作。,圖6.5 Ex_Student運行結(jié)果,6.5綜合應(yīng)用,下面來看一個綜合應(yīng)用,如圖6.5所示。它首先通過對話框來輸入一個學(xué)生記錄,記錄包括學(xué)生的姓名、學(xué)號和三門成績,用類CStudent來描述,并使其可序列化。然后將記錄內(nèi)容保存到一個對象數(shù)組集合類對象中,最后通過文檔序列化將記錄保存到一個文件中。當(dāng)添加記錄或打開一個記錄文件,還會將數(shù)據(jù)顯示在文檔窗口(即視圖)中。 例Ex_Student 文檔序列化示例 1)添加用于學(xué)生記錄輸入的對話框 (1)創(chuàng)建一個默認(rèn)的單文檔應(yīng)用程序Ex_Student。 (2)向應(yīng)用程序中添加一

47、個對話框資源,打開屬性對話框?qū)⑵渥煮w設(shè)置為“宋體,9”,標(biāo)題改為“添加學(xué)生記錄”,取默認(rèn)的ID號IDD_DIALOG1,將OK和Cancel按鈕的標(biāo)題分別改為“確 定”和“取 消”。 (3)參看圖6.5的控件布局,用編輯器為對話框添加如下表6.4所示的一些控件。,6.5綜合應(yīng)用,表6.4 添加的控件,6.5綜合應(yīng)用,(4)雙擊對話框模板或按Ctrl+W快捷鍵,為對話框資源IDD_DIALOG1創(chuàng)建一個對話框類CInputDlg。 (5)打開ClassWizard的Member Variables標(biāo)簽,在Class name中選擇CInputDlg,選中所需的控件ID標(biāo)識符,雙擊鼠標(biāo)或單擊Add

48、 Variables按鈕。依次為表6.5控件增加成員變量。,表6.5 控件變量,6.5綜合應(yīng)用,2)添加一個CStudent類并使該類可序列化 一個可序列化的類必須是CObject的一個派生類,且在類聲明中,需要包含DECLARE_SERIAL宏調(diào)用,而在類的實現(xiàn)文件中包含IMPLEMENT_SERIAL宏調(diào)用,這個宏有3個參數(shù):前2個參數(shù)分別表示類名和基類名,第3個參數(shù)表示應(yīng)用程序的版本號。最后還需要重載Serialize函數(shù),使該類的數(shù)據(jù)成員進行相關(guān)序列化操作。 由于使用ClassWizard無法添加一個CObject派生類,因此必須手動進行。為了簡化類文件的復(fù)雜性,這里創(chuàng)建的這個CStu

49、dent類的聲明和實現(xiàn)代碼是直接添加在Ex_StudentDoc.h和Ex_StudentDoc.cpp文件中的,具體如下: 3)添加并處理菜單項 (1)在菜單資源的主菜單中增加頂層菜單項“學(xué)生記錄( if (IDOK = dlg.DoModal() / 添加記錄 CStudent *pStudent = new CStudent(dlg.m_strName, dlg.m_strID, dlg.m_fScore1, dlg.m_fScore2, dlg.m_fScore3); m_stuObArray.Add(pStudent); SetModifiedFlag();/ 設(shè)置文檔更改標(biāo)志 UpdateAllViews(NULL);/ 更新視圖 (3)在Ex_StudentDoc.cpp文件的開始處,增加包含CAddDlg的頭文件。 #include Ex_StudentDoc.h

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論