国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
VC序列化問題(Serialize)
2012-02-21 11:18 1103人閱讀 評論(0) 收藏 舉報

目錄(?)[+]

 

文檔與序列化

一、文檔的基本特征

文檔類文件是從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.

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

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

翻譯:文檔類支持標準操作有:創(chuàng)建文檔,載入文檔,和保存??蚣芙缑媸褂糜晌臋n類定義的界面。

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 associatedCDocTemplate object.

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

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.

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

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.

翻譯:當一個文檔數(shù)據(jù)發(fā)生改變,每一個它的視圖將隨即發(fā)生改變。文檔類提供更新所有視圖成員函數(shù)來通報每一個視圖的改變,因此視圖可以在必要的時候被重繪??蚣芤苍陉P閉前迅速保存改動文件。

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.

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

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

l         增加成員函數(shù)來存儲每一個文檔的數(shù)據(jù)

l         為讀寫文檔數(shù)據(jù)實現(xiàn)成員函數(shù)。文檔視圖類是這個成員函數(shù)最重要的使用者。

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

序列化:

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

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

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

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

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

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

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

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

l         序列化:創(chuàng)建可序列化的類

l         序列化:序列化對象

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

通過存檔存儲和加載 CObjects

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

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

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

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

警告     如果使用 Serialize 函數(shù)加載對象,也必須使用 Serialize 函數(shù)存儲對象。不要使用 CArchive 的 “<<” 運算符先存儲,然后使用 Serialize 函數(shù)進行加載;或使用 Serialize 函數(shù)存儲,然后使用 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 函數(shù)。同時,如果可序列化的類將指向 CObject (或從 CObject 派生的對象)的指針定義為成員,但在自己的構造函數(shù)中將其構造為其他對象,則也應調用 Serialize 。

序列化:創(chuàng)建可序列化的類

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

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

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

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

從 CObject 派生類

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

 

重寫 Serialize 成員函數(shù)

 

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

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

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 成員函數(shù)

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

輸出運算符及輸入運算符與存檔類交互作用以讀寫數(shù)據(jù)。下面的示例顯示了如何實現(xiàn)以上聲明的 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::Read及 CArchive::Write成員函數(shù)來讀寫大量未鍵入的數(shù)據(jù)。

使用 DECLARE_SERIAL 宏

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

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

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

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

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

在實現(xiàn)文件中使用 IMPLEMENT_SERIAL 宏

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

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

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

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

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

  IMPLEMENT_SERIAL( CPerson, CObject, 1 )  

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

序列化 :序列化對象

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

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

什么是Archive對象?

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

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

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

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

創(chuàng)建 CArchive 對象有兩種方法:

l         通過框架隱式創(chuàng)建 CArchive 對象

l         顯式創(chuàng)建 CArchive 對象

通過框架隱式創(chuàng)建 CArchive 對象

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

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

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

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

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

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

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

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

顯式創(chuàng)建 CArchive 對象

除了通過框架將文檔序列化之外,在其他場合也可能需要 CArchive 對象。例如,可能要序列化到達或來自剪貼板的數(shù)據(jù),由 CSharedFile 對象表示?;蛘撸赡芤褂糜脩艚缑鎭肀4媾c框架提供的文件不同的文件。在這種情況下,可以顯式創(chuàng)建 CArchive 對象。使用下列過程,用與框架采用的相同方式來執(zhí)行此操作。

顯式創(chuàng)建 CArchive 對象

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

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

CFile theFile;

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

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

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

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

關閉 CArchive 對象

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

archive.Close();

theFile.Close();

 

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

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

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

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

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

WORD wEmployeeID;

...

ar << wEmployeeID;

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

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

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

WORD wEmployeeID;

...

ar >> wEmployeeID;

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

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

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 函數(shù)所創(chuàng)建的代碼模板完全相同。由于存儲代碼和加載代碼總是并行,該代碼模板有助于寫的代碼更容易復查,如下例中所示:

void CPerson:Serialize(CArchive& ar)

{

    if (ar.IsStoring())

    {

        ar << m_strName;

        ar << m_wAge;

    }

    else

    {

        ar >> m_strName;

        ar >> m_wAge;

    }

}

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

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 對象的引用,該引用為第一操作數(shù)。這使您可以鏈接運算符,如下所示:

BYTE bSomeByte;

WORD wSomeWord;

DWORD wSomeDoubleWord;

...

ar << bSomeByte << wSomeWord << wSomeDoubleWord;

 

 

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

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

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

按步驟:

l         創(chuàng)建可序列化的類 ->Graph.cpp+Graph.h

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

l         保存文件(通過 Doc 的 Serialize 來保存數(shù)據(jù))

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

在 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 );   // 創(chuàng)建一個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;   // 為了在讀取文件的時候能夠知道元素個數(shù),因此在保存的時候把個數(shù)也存進去

         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);

         }

     }

}

但是讀取數(shù)據(jù)的時候還需要重繪圖像:轉回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的好處:通過緩存來保存,當緩存區(qū)滿了才進行一次讀/寫,因此提高了應用程序的效率

 

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

因此修改 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);  // 將這個數(shù)據(jù)傳遞給

}

其中CObArray類對象讀取數(shù)據(jù)的方法:(以下是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;

存圖形數(shù)據(jù)的代碼修改為:

     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的情況

}

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

在文檔類中重載函數(shù) 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();

}

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

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
第三章 CObject類
序列化
MFC文檔序列化實現(xiàn)保存和加載
MFC序列化
MFC的Serialize機制及其使用
CList類
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服