青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

MyMSDN

MyMSDN記錄開發新知道

用文檔序列化來保存打開文件[理論聯系實際]

文檔與序列化

一、文檔的基本特征

文檔類文件是從CDocument繼承而來的。

The CDocument class provides the basic functionality for user-defined document classes. A document represents the unit of data that the user typically opens with the File Open command and saves with the File Save command.

翻譯:文檔類提供用戶自定義文檔類的基本功能。一個文檔的打開命令和保存命令是數據單元特征。

CDocument supports standard operations such as creating a document, loading it, and saving it. The framework manipulates documents using the interface defined by CDocument.

翻譯:文檔類支持標準操作有:創建文檔,載入文檔,和保存。框架界面使用由文檔類定義的界面。

An application can support more than one type of document; for example, an application might support both spreadsheets and text documents. Each type of document has an associated document template; the document template specifies what resources (for example, menu, icon, or accelerator table) are used for that type of document. Each document contains a pointer to its associated CDocTemplate object.

翻譯:一個應用程序可以支持多于一種類型的文檔;例如,一個應用程序可能同時支持電子表格和普通文本文檔。每一種類型的文檔有一種關聯文檔模板;文檔模板指定了(例如,菜單,圖標,或者加速表格)使用這些類型的文檔。每個文檔包含一個指針指向關聯的模板對象。

Users interact with a document through the CView object(s) associated with it. A view renders an image of the document in a frame window and interprets user input as operations on the document. A document can have multiple views associated with it. When the user opens a window on a document, the framework creates a view and attaches it to the document. The document template specifies what type of view and frame window are used to display each type of document.

翻譯:用戶將一個文檔和一個視類對象想關聯起來。一個視類扮演一個嵌入在文檔框架內的圖像,在文檔內解釋用戶的輸入操作。一個文檔可以有多個視類與其關聯。當用戶在一個文檔上打開一個窗體,框架創造一個視圖,把它放在文檔上。文檔模板指定適合于用戶文檔類型的相同類的視圖和框架窗口用來顯示用戶打開的文件。

Documents are part of the framework's standard command routing and consequently receive commands from standard user-interface components (such as the File Save menu item). A document receives commands forwarded by the active view. If the document doesn't handle a given command, it forwards the command to the document template that manages it.

翻譯:文檔是一個框架標準命令路由,因此從標準用戶界面組件(如文件保存菜單項)接受命令。一個文檔由其活動視圖迅速接受命令。如果該文檔沒有沒有響應給出的命令,那么該命令將交由文檔模板來管理。

When a document's data is modified, each of its views must reflect those modifications. CDocument provides the UpdateAllViews member function for you to notify the views of such changes, so the views can repaint themselves as necessary. The framework also prompts the user to save a modified file before closing it.

翻譯:當一個文檔數據發生改變,每一個它的視圖將隨即發生改變。文檔類提供更新所有視圖成員函數來通報每一個視圖的改變,因此視圖可以在必要的時候被重繪。框架也在關閉前迅速保存改動文件。

To implement documents in a typical application, you must do the following:

l???????? Derive a class from CDocument for each type of document.

l???????? Add member variables to store each document's data.

l???????? Implement member functions for reading and modifying the document's data. The document's views are the most important users of these member functions.

l???????? Override the CObject::Serialize member function in your document class to write and read the document's data to and from disk.

翻譯:在一個典型類型的應用程序中實現一個文檔,你必須按以下步驟:

l???????? 為每一種類型的文檔從 CDocument 派生一個類

l???????? 增加成員函數來存儲每一個文檔的數據

l???????? 為讀寫文檔數據實現成員函數。文檔視圖類是這個成員函數最重要的使用者。

l???????? 在你的文檔類重載 CObject::Serialize 成員函數,來將文檔數據從磁盤讀寫。

序列化:

本文解釋 Microsoft 基礎類庫 (MFC) 中提供的序列化機制,該機制使對象可以在程序運行之間保持。

序列化是指將對象寫入永久性存儲媒體(如磁盤文件)或從其中讀取對象的進程。 MFC CObject 類中的序列化提供內置支持。因此,所有從 CObject 派生的類都可利用 CObject 的序列化協議。

序列化的基本思想是對象應能將其當前狀態(通常由該對象的成員變量指示)寫入永久性存儲中。以后,通過從存儲中讀取對象狀態或反序列化對象狀態,可以重新創建該對象。序列化處理序列化對象時使用的對象指針和對象循環引用的所有詳細資料。關鍵之處在于對象本身負責讀寫其自身狀態。因此,對于可序列化的類,必須實現基本的序列化操作。正如 序列化 文章組中所顯示的那樣,很容易將該功能添加到類中。

MFC CArchive 類的對象用作將被序列化的對象和存儲媒體之間的中介物。該對象始終與 CFile 對象相關聯,它從 CFile 對象獲得序列化所需的信息,包括文件名和請求的操作是讀取還是寫入。執行序列化操作的對象可在不考慮存儲媒體本質的情況下使用 CArchive 對象。

CArchive 對象使用重載輸出運算符 (<<) 和輸入運算符 (>>) 來執行讀寫操作。有關更多信息,請參見 序列化:序列化對象 文章中的 通過存檔存儲和加載 CObjects

注意 ??? 請不要將 CArchive 類與通用 iostream 類混淆, iostream 類只用于格式化的文本。而 CArchive 類則用于二進制格式的序列化對象。

如果愿意,可以不使用 MFC 序列化而為永久性數據存儲創建自己的機制。您將需要在用戶的命令處重寫啟動序列化的類成員函數。請參見 ID_FILE_OPEN ID_FILE_SAVE ID_FILE_SAVE_AS 標準命令的 技術說明 22 中的討論。

下列文章介紹了序列化所需的兩個主要任務:

l???????? 序列化:創建可序列化的類

l???????? 序列化:序列化對象

序列化:序列化與數據庫輸入 /輸出的對比 一文描述了序列化在數據庫應用程序中何時是適當的輸入 / 輸出技術。

通過存檔存儲和加載 CObjects

通過存檔存儲及加載 CObject 需要額外注意。在某些情況下,應調用對象的 Serialize 函數,其中, CArchive 對象是 Serialize 調用的參數,與使用 CArchive “<<” “>>” 運算符不同。要牢記的重要事實是: CArchive “>>” 運算符基于由存檔先前寫到文件的 CRuntimeClass 信息構造內存中的 CObject

因此,是使用 CArchive “<<” “>>” 運算符還是調用 Serialize ,取決于是否需要加載存檔基于先前存儲的 CRuntimeClass 信息動態地重新構造對象。在下列情況下使用 Serialize 函數:

l???????? 反序列化對象時,預先知道對象的確切的類。

l???????? 反序列化對象時,已為其分配了內存。

警告 ??? 如果使用 Serialize 函數加載對象,也必須使用 Serialize 函數存儲對象。不要使用 CArchive “<<” 運算符先存儲,然后使用 Serialize 函數進行加載;或使用 Serialize 函數存儲,然后使用 CArchive “>>” 運算符進行加載。

以下示例闡釋了這些情況:

class CMyObject : public CObject

{

// ...Member functions

?? public:

?? CMyObject() { }

?? virtual void Serialize( CArchive& ar ) { }

?

// Implementation

?? protected:

?? DECLARE_SERIAL( CMyObject )

};

?

?

class COtherObject : public CObject

{

?? // ...Member functions

?? public:

?? COtherObject() { }

?? virtual void Serialize( CArchive& ar ) { }

?

// Implementation

protected:

?? DECLARE_SERIAL( COtherObject )

};

?

?

class CCompoundObject : public CObject

{

?? // ...Member functions

?? public:

?? CCompoundObject();

?? virtual void Serialize( CArchive& ar );

?

// Implementation

protected:

?? CMyObject m_myob;??? // Embedded object

?? COtherObject* m_pOther;??? // Object allocated in constructor

?? CObject* m_pObDyn;??? // Dynamically allocated object

?? //..Other member data and implementation

?

?? DECLARE_SERIAL( CCompoundObject )

};

?

IMPLEMENT_SERIAL(CMyObject,CObject,1)

IMPLEMENT_SERIAL(COtherObject,CObject,1)

IMPLEMENT_SERIAL(CCompoundObject,CObject,1)

?

?

CCompoundObject::CCompoundObject()

{

?? m_pOther = new COtherObject; // Exact type known and object already

??????????? //allocated.

?? m_pObDyn = NULL;??? // Will be allocated in another member function

??????????? // if needed, could be a derived class object.

}

?

void CCompoundObject::Serialize( CArchive& ar )

{

?? CObject::Serialize( ar );??? // Always call base class Serialize.

?? m_myob.Serialize( ar );??? // Call Serialize on embedded member.

?? m_pOther->Serialize( ar );??? // Call Serialize on objects of known exact type.

?

?? // Serialize dynamic members and other raw data

?? if ( ar.IsStoring() )

?? {

????? ar << m_pObDyn;

????? // Store other members

?? }

?? else

?? {

????? ar >> m_pObDyn; // Polymorphic reconstruction of persistent

??????????? // object

??????????? //load other members

?? }

}

總之,如果可序列化的類將嵌入的 CObject 定義為成員,則不應使用該對象的 CArchive “<<” “>>” 運算符,而應調用 Serialize 函數。同時,如果可序列化的類將指向 CObject (或從 CObject 派生的對象)的指針定義為成員,但在自己的構造函數中將其構造為其他對象,則也應調用 Serialize

序列化:創建可序列化的類

ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/vccore/html/_core_serialization.3a_.making_a_serializable_class.htm

使類可序列化需要五個主要步驟。下面列出了這些步驟并在以后章節內進行了解釋:

  1. CObject 派生類 (或從 CObject 派生的某個類中派生)。
  2. 重寫 Serialize 成員函數
  3. 使用 DECLARE_SERIAL (在類聲明中)。
  4. 定義不帶參數的構造函數
  5. 為類 在實現文件中使用 IMPLEMENT_SERIAL

如果直接調用 Serialize而不是通過 CArchive“>>”“<<”運算符調用,則序列化不需要最后三個步驟。

CObject 派生類

CObject 類中定義了基本的序列化協議和功能。正如在 CPerson 類的下列聲明中所示,通過從 CObject 中(或從 CObject 的派生類中)派生類,可獲得對 CObject 的序列化協議及功能的訪問權限。

?

重寫 Serialize 成員函數

?

CObject 類中定義的 Serialize 成員函數實際上負責對捕獲對象的當前狀態所必需的數據進行序列化。 Serialize 函數具有 CArchive 參數,該函數使用其來讀寫對象數據。 CArchive 對象具有成員函數 IsStoring ,該成員函數指示 Serialize 正在存儲(即正在寫入數據)還是正在加載(即正在讀取數據)。用 IsStoring 的結果作為參考,使用輸出運算符 (<<) 將對象數據插入到 CArchive 對象中或使用輸入運算符 (>>) 提取數據。

假定一個類是從 CObject 派生的并具有兩個新成員變量,分別為 CString WORD 類型。下列類聲明段顯示了新成員變量和重寫的 Serialize 成員函數的聲明:

class CPerson : public CObject

{

public:

??? DECLARE_SERIAL( CPerson )

??? // empty constructor is necessary

??? CPerson(){};

?

??? CString m_name;

??? WORD?? m_number;

?

??? void Serialize( CArchive& archive );

???

??? // rest of class declaration

};

?

重寫 Serialize 成員函數

  1. 調用 Serialize 的基類版本以確保序列化對象的繼承部分。
  2. 插入或提取您的類所特定的成員變量。

輸出運算符及輸入運算符與存檔類交互作用以讀寫數據。下面的示例顯示了如何實現以上聲明的 CPerson類的 Serialize

				
						
void ?CPerson::Serialize(?CArchive & ?archive?)
{
????
// ?call?base?class?function?first
????
// ?base?class?is?CObject?in?this?case
????CObject::Serialize(?archive?);

????
// ?now?do?the?stuff?for?our?specific?class
???? if (?archive.IsStoring()?)
????????archive?
<< ?m_name? << ?m_number;
????
else
????????archive?
>> ?m_name? >> ?m_number;
}

也可使用 CArchive::ReadCArchive::Write成員函數來讀寫大量未鍵入的數據。

使用 DECLARE_SERIAL

在支持序列化的類的聲明中需要 DECLARE_SERIAL宏,如下所示:

				
class ?CPerson?:? public ?CObject
{
????DECLARE_SERIAL(?CPerson?)
????
// ?rest?of?declaration?follows
}
;
定義不帶參數的構造函數

反序列化對象(從磁盤上加載)后,MFC 重新創建這些對象時,需要一個默認的構造函數。反序列化進程將用重新創建對象所需的值填充所有成員變量。

可將該構造函數聲明為公共的、受保護的或私有的。如果使該構造函數成為受保護的或私有的,請確保它將僅由序列化函數使用。該構造函數必須使對象處于這樣一種狀態:必要時,可允許將其安全刪除。

注意 ??? 如果忘記在使用 DECLARE_SERIAL IMPLEMENT_SERIAL 宏的類中定義不帶參數的構造函數,將在使用 IMPLEMENT_SERIAL 宏的行上得到 沒有可用的默認構造函數 編譯器警告。

在實現文件中使用 IMPLEMENT_SERIAL

IMPLEMENT_SERIAL 宏用于定義從 CObject中派生可序列化類時所需的各種函數。在類的實現文件 (.CPP) 中使用這個宏。該宏的前兩個參數是類名和直接基類的名稱。

該宏的第三個參數是架構編號。架構編號實質上是類對象的版本號。架構編號使用大于或等于零的整數。(請不要將該架構編號與數據庫術語混淆。)

MFC 序列化代碼在將對象讀取到內存時檢查該架構編號。如果磁盤上對象的架構編號與內存中類的架構編號不匹配,庫將引發 CArchiveException,防止程序讀取對象的不正確版本。

如果要使 Serialize成員函數能夠讀取多個版本(即,讀取用應用程序的不同版本寫入的文件),可將 VERSIONABLE_SCHEMA值作為 IMPLEMENT_SERIAL宏的參數。有關用法信息和示例,請參見 CArchive類的 GetObjectSchema成員函數。

以下示例顯示了如何將 IMPLEMENT_SERIAL用于從 CObject派生的 CPerson類。

				
						IMPLEMENT_SERIAL( CPerson, CObject, 1 )
				
		

正如序列化:序列化對象文章中所討論的,一旦具有可序列化的類,就可以序列化類的對象。

序列化 :序列化對象

序列化:創建可序列化的類 一文說明如何使類可序列化。一旦具有可序列化的類,就可以通過 CArchive對象將該類的對象序列化到文件和從文件序列化該類的對象。本文將解釋:

可使框架創建可序列化文檔的存檔或自己顯式創建 CArchive對象。通過使用 CArchive“<<”“>>”運算符或在某些情況下通過調用 CObject派生類的 Serialize 函數,可在文件和可序列化對象間傳輸數據。

什么是Archive對象?

CArchive 對象提供了一個類型安全緩沖機制,用于將可序列化對象寫入 CFile對象或從中讀取可序列化對象。通常,CFile對象表示磁盤文件;但是,它也可以是表示剪貼板的內存文件(CSharedFile對象)。

給定的 CArchive對象要么存儲數據(即寫入數據或將數據序列化),要么加載數據(即讀取數據或將數據反序列化),但決不能同時進行。CArchive對象的壽命只限于將對象寫入文件或從文件讀取對象的一次傳遞。因此,需要兩個連續創建的 CArchive對象將數據序列化到文件,然后從文件反序列化數據。

當存檔將對象存儲到文件時,存檔將 CRuntimeClass名稱附加到這些對象。然后,當另一個存檔將對象從文件加載到內存時,將基于這些對象的 CRuntimeClass動態地重新構造 CObject派生的對象。通過存儲存檔將給定對象寫入文件時,該對象可能被引用多次。然而,加載存檔將僅對該對象重新構造一次。有關存檔如何將 CRuntimeClass信息附加到對象以及重新構造對象(考慮可能的多次引用)的詳細信息,請參見技術說明 2

將數據序列化到存檔時,存檔積累數據,直到其緩沖區被填滿為止。然后,存檔將其緩沖區寫入 CArchive對象指向的 CFile對象。同樣,當您從存檔中讀取數據時,存檔會將數據從文件讀取到它的緩沖區,然后從緩沖區讀取到反序列化的對象。這種緩沖減少了物理讀取硬盤的次數,從而提高了應用程序的性能。

創建 CArchive 對象有兩種方法:

l???????? 通過框架隱式創建 CArchive 對象

l???????? 顯式創建 CArchive 對象

通過框架隱式創建 CArchive 對象

最普通且最容易的方法是使框架代表“文件”菜單上的“保存”、“另存為”和“打開”命令為文檔創建 CArchive 對象。

以下是應用程序的用戶從“文件”菜單上發出“另存為”命令時,框架所執行的操作:

顯示“另存為”對話框并從用戶獲取文件名。

打開用戶命名的文件作為 CFile 對象。

創建指向該 CFile 對象的 CArchive 對象。在創建 CArchive 對象時,框架將模式設置為“存儲”(即寫入或序列化),而不是“加載”(即讀取或反序列化)。

調用在 CDocument 派生類中定義的 Serialize 函數,將 CArchive 對象的引用傳遞給該函數。

然后,文檔的 Serialize 函數將數據寫入 CArchive 對象(剛作了解釋)。從 Serialize 函數返回時,框架先銷毀 CArchive 對象,再銷毀 CFile 對象。

因此,如果讓框架為文檔創建 CArchive 對象,您所要做的一切是實現寫入存檔和從存檔中讀取的文檔的 Serialize 函數。您還必須為文檔的 Serialize 函數直接或間接依次序列化的任何 CObject 派生對象實現 Serialize

顯式創建 CArchive 對象

除了通過框架將文檔序列化之外,在其他場合也可能需要 CArchive 對象。例如,可能要序列化到達或來自剪貼板的數據,由 CSharedFile 對象表示。或者,可能要使用用戶界面來保存與框架提供的文件不同的文件。在這種情況下,可以顯式創建 CArchive 對象。使用下列過程,用與框架采用的相同方式來執行此操作。

顯式創建 CArchive 對象

構造 CFile 對象或從 CFile 導出的對象。

按照下面示例所示,將 CFile 對象傳遞到 CArchive 的構造函數:

CFile theFile;

theFile.Open(..., CFile::modeWrite);

CArchive archive(&theFile, CArchive::store);

CArchive 構造函數的第二個參數是指定存檔將用于向文件中存儲數據還是用于從文件中加載數據的枚舉值。對象的 Serialize 函數通過調用存檔對象的 IsStoring 函數來檢查該狀態。

當完成向 CArchive 對象存儲數據或從該對象中加載數據時,關閉該對象。雖然 CArchive 對象(和 CFile 對象)會自動關閉存檔(和文件),好的做法是顯式執行,因為這使從錯誤恢復更為容易。有關錯誤處理的更多信息,請參見異常:捕捉和刪除異常一文。

關閉 CArchive 對象

以下示例闡釋了如何關閉 CArchive 對象:

archive.Close();

theFile.Close();

?

使用 CArchive 對象的“ << ”和“ >> ”操作符

CArchive 提供“ << ”和“ >> ”運算符,用于向文件中寫入簡單的數據類型和 CObjects 以及從文件中讀取它們。

通過存檔將對象存儲在文件中

以下示例顯示了如何通過存檔將對象存儲在文件中:

CArchive ar(&theFile, CArchive::store);

WORD wEmployeeID;

...

ar << wEmployeeID;

從先前存儲在文件中的值加載對象

以下示例顯示了如何從先前存儲在文件中的值加載對象:

CArchive ar(&theFile, CArchive::load);

WORD wEmployeeID;

...

ar >> wEmployeeID;

通常,通過 CObject 派生類的 Serialize 函數中的存檔將數據存儲到文件中或從文件中加載數據,必須已用 DECLARE_SERIALIZE 宏來聲明這些函數。將 CArchive 對象的引用傳遞到 Serialize 函數。調用 CArchive 對象的 IsLoading 函數以確定是否已調用 Serialize 函數來從文件中加載數據或將數據存儲到文件中。

可序列化的 CObject 派生類的 Serialize 函數通常具有以下形式:

void CPerson::Serialize(CArchive& ar)

{

??? CObject::Serialize(ar);

??? if (ar.IsStoring())

??? {

??????? // TODO:? add storing code here

??? }

??? else

??? {

??? // TODO:? add loading code here

??? }

}

上面的代碼模板與 AppWizard 為該文檔(從 CDocument 派生的類)的 Serialize 函數所創建的代碼模板完全相同。由于存儲代碼和加載代碼總是并行,該代碼模板有助于寫的代碼更容易復查,如下例中所示:

void CPerson:Serialize(CArchive& ar)

{

??? if (ar.IsStoring())

??? {

??????? ar << m_strName;

??????? ar << m_wAge;

??? }

??? else

??? {

??????? ar >> m_strName;

??????? ar >> m_wAge;

??? }

}

庫將 CArchive 的“ << ”和“ >> ”運算符定義為第一操作數,將下列數據類型和類類型定義為第二操作數:

CObject*

SIZE CSize

float

WORD

CString

POINT CPoint

DWORD

BYTE

RECT CRect

double

LONG

CTime CTimeSpan

int

COleCurrency

COleVariant

COleDateTime

COleDateTimeSpan

?

?

注意 ?? 通過存檔存儲及加載 CObjects 需要額外注意。有關更多信息,請參見通過存檔存儲和加載 CObjects

CArchive 的“ << ”和“ >> ”運算符總是返回 CArchive 對象的引用,該引用為第一操作數。這使您可以鏈接運算符,如下所示:

BYTE bSomeByte;

WORD wSomeWord;

DWORD wSomeDoubleWord;

...

ar << bSomeByte << wSomeWord << wSomeDoubleWord;

?

?

通過存檔存儲及加載 CObject (見前)

下面用一個示例來解釋這個問題。

目標:一個畫圖程序,通過保存打開按鈕存取圖片。方法:保存圖片繪制信息。

按步驟:

l???????? 創建可序列化的類 ->Graph.cpp+Graph.h

l???????? View 類中添加對控件的響應,實現畫圖功能,每次鼠標彈起的時候保存繪圖信息

l???????? 保存文件(通過 Doc Serialize 來保存數據)

l???????? 打開文件(通過 Doc Serialize 來讀取數據,并將其重繪)

View 類中定義 CObArray m_obArray;

下面按這個思路來完成:(在 C Graph 子類中完成重繪的畫圖功能)

Graph.cpp

#include "StdAfx.h"

#include ".\graph.h"

IMPLEMENT_SERIAL(CGraph, CObject, 1 )

CGraph::CGraph(void)

: m_ptOrigin(0)

, m_ptEnd(0)

, m_nDrawType(0)

{

}

CGraph::CGraph(CPoint m_ptOrigin,CPoint m_ptEnd,UINT m_nDrawType)

{

???? this->m_ptOrigin=m_ptOrigin;

???? this->m_ptEnd=m_ptEnd;

???? this->m_nDrawType=m_nDrawType;

}

CGraph::~CGraph(void)

{

}

void CGraph::Serialize( CArchive& ar )

{

???? // 繼承基類的CObject

??? CObject::Serialize( ar );

??? if( ar.IsStoring() )

???? {

??????? ar << m_ptOrigin << m_ptEnd << m_nDrawType ;

???? }

???? else

???? {

???????? ar >> m_ptOrigin >> m_ptEnd >> m_nDrawType ;

???? }

}

void CGraph::Draw(CDC* pDC)

{

???? CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));

???? CBrush *pOldBrush=pDC->SelectObject(pBrush);

???? switch(m_nDrawType)

???? {

???? case 1:

???????? pDC->SetPixel(m_ptEnd,RGB(0,0,0));

???????? break;

???? case 2:

???????? pDC->MoveTo(m_ptOrigin);

???????? pDC->LineTo(m_ptEnd);

???????? break;

???? case 3:

???????? pDC->Rectangle(CRect(m_ptOrigin,m_ptEnd));

???????? break;

???? case 4:

???????? pDC->Ellipse(CRect(m_ptOrigin,m_ptEnd));

???????? break;

???? }

???? pDC->SelectObject(pOldBrush);

}

Graph..h

#pragma once

#include "atltypes.h"

?

class CGraph : publicCObject

{

public :

???? DECLARE_SERIAL( CGraph )

???? CGraph(void);

???? CGraph::CGraph(CPoint m_ptOrigin,CPoint m_ptEnd,UINT m_nDrawType);

???? void Serialize( CArchive& ar );

???? ~CGraph(void);

???? CPoint m_ptOrigin;

???? CPoint m_ptEnd;

???? UINT m_nDrawType;

???? void Draw(CDC* pDC);

};

View 類中添加畫圖功能

void CGraphicSerialView::OnDot()

{

???? // TODO: 在此添加命令處理程序代碼

???? m_nDrawType=1;

}

?

void CGraphicSerialView::OnLine()

{

???? // TODO: 在此添加命令處理程序代碼

???? m_nDrawType=2;

}

?

void CGraphicSerialView::OnRectangle()

{

???? // TODO: 在此添加命令處理程序代碼

???? m_nDrawType=3;

}

?

void CGraphicSerialView::OnEllipse()

{

???? // TODO: 在此添加命令處理程序代碼

???? m_nDrawType=4;

}

?

void CGraphicSerialView::OnLButtonDown(UINT nFlags, CPoint point)

{

???? // TODO: 在此添加消息處理程序代碼和/或調用默認值

???? m_ptOrigin = point;

???? CView::OnLButtonDown(nFlags, point);

}

?

void CGraphicSerialView::OnLButtonUp(UINT nFlags, CPoint point)

{

???? // TODO: 在此添加消息處理程序代碼和/或調用默認值

???? CClientDC dc(this);

???? CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));???? // 選擇一個透明畫刷

???? dc.SelectObject(pBrush);

?

???? switch(m_nDrawType)

???? {

???? case 1:

???????? dc.SetPixel(point,RGB(0,0,0));

???????? break;

???? case 2:

???????? dc.MoveTo(m_ptOrigin);

???????? dc.LineTo(point);

???????? break;

???? case 3:

???????? dc.Rectangle(m_ptOrigin.x,m_ptOrigin.y,point.x,point.y);

???????? break;

???? case 4:

???????? dc.Ellipse(CRect(m_ptOrigin,point));

???????? break;

???? default:

???????? break;

???? }

???? // 將圖形信息保存起來

???? CGraph *pGraph=new CGraph( m_ptOrigin , point , m_nDrawType );?? // 創建一個pGraph指針指向一個存儲圖形信息的“圖形”

???? m_obArray.Add(pGraph);// 將一群這樣的pGraph組織在一起放進m_obArray

???? CView::OnLButtonUp(nFlags, point);

}

但是要保存和讀取文件需要用到 Serialize

因此轉到 Doc

void CGraphicSerialDoc::Serialize(CArchive& ar)

{

???? POSITION pos=GetFirstViewPosition();// 獲得第一個視類對象在對象列表中的位置

???? CGraphicSerialView *pView=(CGraphicSerialView*)GetNextView(pos);// 找到當前視類對象的指針,由于這是單文檔,因此只有一個視類對象

???? if (ar.IsStoring())

???? {

???????? // TODO: 在此添加存儲代碼

???????? int nCount=pView->m_obArray.GetSize();

???????? ar<<nCount;?? // 為了在讀取文件的時候能夠知道元素個數,因此在保存的時候把個數也存進去

???????? for(int i=0;i<nCount;i++)

???????? {

????????????? ar<<pView->m_obArray.GetAt(i);

???????? }

???? }

???? else

???? {

???????? // TODO: 在此添加加載代碼

???????? int nCount;

???????? ar>>nCount;

???????? CGraph *pGraph;

???????? for(int i=0;i<nCount;i++)

???????? {

????????????? ar>>pGraph;

????????????? pView->m_obArray.Add(pGraph);

???????? }

???? }

}

但是讀取數據的時候還需要重繪圖像:轉回View類,因為在View類加載的時候會自動調用OnDraw(),OnDraw()中添加如下語句。

???? int nCount;

???? nCount=m_obArray.GetSize();

???? for(int i=0;i<nCount;i++)

???? {

???????? ((CGraph*)m_obArray.GetAt(i))->Draw(pDC);

???? }

基本上完成了通過serialize保存和打開文件。

serialize的好處:通過緩存來保存,當緩存區滿了才進行一次讀/寫,因此提高了應用程序的效率

?

另外 Archive 對象是支持序列化的,因此在讀寫數據的時候即可以按以上方法在 Doc 類的 Serialize 來保存和打開數據。

因此修改 Doc 中的 Serialize

void CGraphicSerialDoc::Serialize(CArchive& ar)

{

???? POSITION pos=GetFirstViewPosition();// 獲得第一個視類對象在對象列表中的位置

???? CGraphicSerialView *pView=(CGraphicSerialView*)GetNextView(pos);// 找到當前視類對象的指針,由于這是單文檔,因此只有一個視類對象

???? if (ar.IsStoring())

???? {

???????? // TODO: 在此添加存儲代碼

???? }

???? else

???? {

???????? // TODO: 在此添加加載代碼

???? }

???? pView->m_obArray.Serialize(ar);? // 將這個數據傳遞給

}

其中CObArray類對象讀取數據的方法:(以下是MFC源代碼,無須用戶添加)

void CObArray::Serialize(CArchive& ar)

{

???? ASSERT_VALID(this);

?

???? CObject::Serialize(ar);

?

???? if (ar.IsStoring())

???? {

???????? ar.WriteCount(m_nSize);

???????? for (INT_PTR i = 0; i < m_nSize; i++)

????????????? ar << m_pData[i];

???? }

???? else

???? {

???????? DWORD_PTR nOldSize = ar.ReadCount();

???????? SetSize(nOldSize);

???????? for (INT_PTR i = 0; i < m_nSize; i++)

????????????? ar >> m_pData[i];

???? }

}

?

下面直接在 Doc 類中使用 CObArray 對象(取消之前定義在 View 類中的該類對象)

Doc 類中定義 CObArray m_obArray;

存圖形數據的代碼修改為:

???? CGraphicDoc *pDoc=GetDocument();// 通過視類提供的GetDocument()方法來獲得Doc類指針

???? pDoc->m_obArray.Add(pGraph);

修改其他位置的 m_obArray

void CGraphicSerialView::OnDraw(CDC* pDC)

{

???? ……

???? nCount=pDoc->m_obArray.GetSize();

???? for(int i=0;i<nCount;i++)

???? {

???? ???? ((CGraph*)pDoc->m_obArray.GetAt(i))->Draw(pDC);???//Doc類中定義m_obArray的情況

???? }

}

void CGraphicSerialDoc::Serialize(CArchive& ar)

{

……

???? m_obArray.Serialize(ar); ??? //Doc 類中定義m_obArray的情況

}

當我們新建和打開文檔的時候,我們之前的文檔對象并沒有被銷毀(系統利用 OnNewDocument 方法所新建的對象)之前在堆上建立了文檔對象。此時應刪除文檔對象。

在文檔類中重載函數 void CGraphicSerialDoc::DeleteContents() 來刪除文檔對象,以避免內存泄露。

void CGraphicSerialDoc::DeleteContents()

{

???? int nCount;

???? nCount=m_obArray.GetSize();

???? /*for(int i=0;i<nCount;i++)

???? {

???????? delete m_obArray.GetAt(i);

???????? //m_obArray.RemoveAt(i);

???? }

???? m_obArray.RemoveAll();*/

???? while(nCount--)

???? {

???????? delete m_obArray.GetAt(nCount);

???????? m_obArray.RemoveAt(nCount);

???? }

???? CDocument::DeleteContents();

}

下面是關于內存泄露的在此的一段論述。(此文同時發布于)

http://www.shnenglu.com/mymsdn/archive/2006/08/16/11266.html

posted on 2006-08-16 23:19 volnet 閱讀(2447) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


特殊功能
 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            在线欧美日韩| 国产亚洲一区二区三区| 国产精品久久久久影院亚瑟| 国产欧美日韩综合| 亚洲国产成人精品久久久国产成人一区 | 一本一本久久a久久精品综合麻豆| 亚洲一品av免费观看| 久久久精品一区| 欧美精品尤物在线| 国产一区二区三区久久 | 欧美美女喷水视频| 久久夜色精品国产亚洲aⅴ | 欧美不卡视频| 99在线热播精品免费99热| 亚洲欧美日韩中文在线制服| 噜噜噜躁狠狠躁狠狠精品视频 | 亚洲综合电影| 美女黄毛**国产精品啪啪| 99re6热在线精品视频播放速度| 久久国产精彩视频| 欧美视频国产精品| 亚洲国产精品一区在线观看不卡| 亚洲——在线| 亚洲国产va精品久久久不卡综合| 亚洲一区二区三区三| 欧美成人小视频| 国产一区二区三区四区在线观看 | 一区二区三区四区五区在线| 久久久久久久高潮| 国产精品视频免费| 99精品久久久| 久久婷婷国产综合国色天香| 一区二区三区国产精品| 欧美成人在线网站| 激情欧美一区二区三区在线观看| 亚洲女人天堂成人av在线| 欧美高清你懂得| 欧美综合国产精品久久丁香| 欧美图区在线视频| 亚洲另类视频| 欧美大片18| 久久精品国产免费观看| 国产欧美日韩一区| 亚洲午夜国产一区99re久久| 91久久国产精品91久久性色| 另类亚洲自拍| 黄色成人在线网址| 久久精品国产91精品亚洲| 亚洲天堂久久| 欧美日韩三级视频| 日韩一二三在线视频播| 欧美激情在线| 老色批av在线精品| 在线观看视频一区二区| 久久综合99re88久久爱| 欧美在线视频观看| 国产欧美一区在线| 亚洲欧美美女| 一区二区三区四区五区视频| 欧美日韩一区不卡| 一级日韩一区在线观看| 亚洲精品在线观看免费| 欧美91视频| 亚洲精品视频在线观看网站| 亚洲第一在线视频| 欧美电影在线播放| 亚洲精品国产精品国自产观看浪潮| 免费一级欧美片在线观看| 久久婷婷色综合| 亚洲第一色中文字幕| 欧美国产精品专区| 欧美成人免费播放| 一本色道久久综合亚洲精品高清| 亚洲精品国产精品久久清纯直播| 欧美精品一区二区在线观看| 中国成人黄色视屏| 在线亚洲电影| 国产婷婷色一区二区三区| 久久久精品网| 理论片一区二区在线| 亚洲人体影院| 妖精视频成人观看www| 国产精品成人在线| 久久成人综合视频| 欧美综合激情网| 91久久精品国产91久久性色| 最近中文字幕日韩精品 | 午夜视频在线观看一区二区三区| 午夜精品福利在线| 在线观看亚洲精品视频| 欧美国产一区二区在线观看| 欧美另类极品videosbest最新版本| 在线一区欧美| 亚洲欧美一区二区三区在线| 极品少妇一区二区三区精品视频| 欧美成人一品| 欧美色精品在线视频| 欧美综合国产| 免费看成人av| 亚洲综合色在线| 久久久久国产成人精品亚洲午夜| 亚洲精品久久久久久久久久久久| 一本一道久久综合狠狠老精东影业 | 欧美久久在线| 午夜一区二区三区不卡视频| 久久成人这里只有精品| 亚洲三级免费| 亚洲网友自拍| 曰本成人黄色| 在线视频中文亚洲| 黄色av成人| 亚洲精品视频在线看| 国产美女一区二区| 欧美阿v一级看视频| 国产精品超碰97尤物18| 久久中文字幕一区| 欧美网站在线观看| 免费精品视频| 国产精品久在线观看| 蜜臀久久久99精品久久久久久| 欧美日韩一区二区三区高清| 久久香蕉国产线看观看网| 欧美日韩精品免费观看视一区二区| 久久国产精品99精品国产| 欧美国产日韩a欧美在线观看| 午夜精品亚洲| 欧美高清视频一区二区三区在线观看 | 亚洲日本久久| 国内视频一区| 99国产精品99久久久久久粉嫩| 精品电影在线观看| 一本色道久久综合亚洲精品不卡| …久久精品99久久香蕉国产| 亚洲永久在线| 99精品视频免费| 久久久夜夜夜| 欧美一区二区三区久久精品茉莉花| 欧美暴力喷水在线| 久久久久久九九九九| 国产精品极品美女粉嫩高清在线 | 欧美日韩日日骚| 欧美电影免费观看| 国产区日韩欧美| 亚洲精品婷婷| 亚洲精品国产欧美| 久久精品综合网| 午夜在线电影亚洲一区| 欧美日产一区二区三区在线观看 | 欧美激情一区二区三区高清视频| 久久夜色精品国产欧美乱| 国产精品免费一区二区三区在线观看| 91久久精品国产| 亚洲国产欧美另类丝袜| 性一交一乱一区二区洋洋av| 午夜激情亚洲| 国产精品成人播放| 亚洲精品视频一区二区三区| 亚洲欧洲日本国产| 久久午夜羞羞影院免费观看| 久久久久久久尹人综合网亚洲| 国产精品专区h在线观看| 日韩视频一区二区| 亚洲精品久久久一区二区三区| 裸体一区二区三区| 美女网站久久| 伊人狠狠色j香婷婷综合| 久久riav二区三区| 久久精品国产成人| 国产小视频国产精品| 亚洲在线视频网站| 性欧美videos另类喷潮| 国产精品亚洲不卡a| 亚洲一区自拍| 欧美专区亚洲专区| 亚洲神马久久| 国产精品久久久久久av福利软件 | 亚洲少妇一区| 亚洲网站视频福利| 欧美三级欧美一级| 一区二区三区**美女毛片| 亚洲小说欧美另类婷婷| 欧美视频在线一区| 亚洲一区二区黄色| 性色一区二区三区| 国产亚洲一级高清| 久久国产精品免费一区| 另类天堂视频在线观看| 亚洲国产精品久久久| 欧美第一黄色网| 亚洲美女在线国产| 亚洲资源av| 国产香蕉97碰碰久久人人| 久久本道综合色狠狠五月| 毛片一区二区| 亚洲清纯自拍| 欧美三级中文字幕在线观看| 亚洲欧美另类综合偷拍| 久久久久久伊人| 亚洲国产日韩在线一区模特| 欧美另类女人|