Vorheriges Kapitel: Drucken  Nächstes Kapitel: Dokument und Ansicht       Inhaltsverzeichnis Inhaltsverzeichnis       Die Downloadseite Download       Kontakt Kontakt

 

Serialisierung

 

 

Die MFC Klasse CFile
Die MFC Klasse CArchive
Der Mechanismus von Serialisierung

 

 

Der Prozeß , in dem man ein Objekt automatisch auf ein Speichermedium wie etwa eine Festplatte schreibt, oder davon liest, wird als Serialisierung genannt. Der Mechanismus von Serialisierung beruht sich auf eine Technik, die Streaming genannt wird. Falls Sie textorientierte Programme mit C++ geschrieben haben, haben Sie bestimmt von den Eingabe- und Ausgabeoperatoren (>>,<<) Gebrauch gemacht. In solchen Streams haben Sie mit formatierter Ein- und Ausgabe zu tun gehabt. Die Daten, die durch den Mechanismus der Serialisierung gespeichert oder gelesen werden, haben jedoch binäre Form. Um den Mechanismus der Serialisierung verstehen zu können, muß man sich unbedingt mit der MFC Klasse CArchive vertraut machen. Außerdem sollte man über die M FC Klasse CFile Bescheid wissen.

 

CFile ist die Basisklasse für alle anderen MFC File-Klassen. Die Dienste dieser Klasse konzentrieren sich unmittelbar auf den Vorgang der ungepufferten binären Ein- und Ausgabe von Dateien auf ein Speichermedium. CFile arbeitet sehr eng mit der MFC Klasse CArchive zusammen, um den Mechanismus der Serialisierung zu verwirklichen.

 

 

Ein CArchive Objekt ist wie ein binärer Stream zu verstehen. Ein Objekt der Klasse CArchive ist immer mit einem CFile-Objekt ,etwa einer Datei, assoziiert und ermöglicht gepuffertes Lesen und Schreiben von und auf ein Speichermedium. Da ein CArchive-Objekt immer mit einer Datei verbunden ist, muß man vor dem Aufruf eines CArchive-Objekts ein Objekt der Klasse CFile aufgerufen haben.

 

 

Wenn Sie irgendwelche Daten serialisieren, schreibt Visual C++ diese Daten nicht direkt in das CFile-Objekt auf den Datenträger. Es handelt sich dabei immer um einen zweistufigen Vorgang. In Stufe eins werden die Daten in einem Objekt der Klasse CArchive gelagert und in Stufe zwei werden dann diese Daten vom Archive in das CFile-Objekt geschrieben oder daraus geladen. Das CArchive-Objekt benutzt die überladenen Operatoren(<<, >>) zum Speichern und Laden der Daten. Das erinnert sehr an die formatierte Ein-und Ausgabe (cin>> und cout<<) in textorientierten C++ Anwendungen. Diese Analogie ist auch bestimmt hilfreich. Wenn Sie Ihre Anwendung mit Hilfe von AppWizard erstellen, erledigt AppWizard die obige zweistufige Aufgabe für Sie. Sie können bequem mit Hilfe der MFC Funktion Serialize( ) die Daten im Dokument speichern. Aus dieser Möglichkeit machen wir erst im nächsten Kapitel, Dokument&View, Gebrauch. Falls Sie sich mit Serialisierung wirklich vertraut machen möchten, dann müssen Sie sich das Kapitel Dokument&View genauer anschauen. Um die Serialisierung besser zu verstehen, werden wir zuerst mal ausnahmsweise auf die Mithilfe von AppWizard im Bezug auf die Serialisierung verzichten. In dem Beispielprogramm grafik werden Sie zehn Werte zwischen 0 und 250 eingeben, diese auf dem Bildschirm grafisch darstellen, auf dem Datenträger speichern und nach Bedarf wieder laden oder löschen.


Abbildung
Erzeugen Sie ein SDI Projekt namens grafik und leiten Sie die Ansicht im Schritt sechs des AppWizards von CFormView ab. Für den Entwurf der Dialogseite IDD_GRAFIK_FORM benötigen Sie zehn Editboxen für die zehn Werte, vier Schaltflächen zum Zeichnen, Speichern, Löschen und Laden der Werte. Außerdem brauchen Sie ein Rechteck, worin die Werte grafisch dargestellt werden. Plazieren Sie dafür ein Gruppenfeld(Groupbox) auf die Dialogseite und deaktivieren Sie die Option sichtbar in den Eigenschaften des Gruppenfeldes. Erledigen Sie die Routinearbeit für die Steuerelemente, wie etwa Deklaration der Member-Variablen für die Editboxen und die Erzeugung der Nachrichten-Funktionen für die vier Schaltflächen. Die Nachrichten-Funktionen im Beispielprogramm heißen OnZeig(), OnLoesch(), OnSav() und OnLade(). Erzeugen Sie außerdem mit Hilfe von ClassWizard für die Nachricht WM_PAINT die dazugehörige Nachrichten-Funktion OnPaint(). Deklarieren Sie in der Headerdatei der Ansicht die drei öffentlichen Variablen folgendermaßen:

 
int punkt[10];
CRect rect;
BOOL zeichne;

Setzen Sie im Konstruktor der View-Datei den Wert von zeichne auf FALSE.

Die Funktion OnZeig() liest die Werte, die Sie eingegeben haben, ein und überträgt sie in dem Array punkt[ ]. Anschließend wird der Zeichenvorgang eingeleitet:

void CGrafikView::OnZeig() 
{
UpdateData(TRUE);   
punkt[0]=m_y1;
punkt[1]=m_y2;
punkt[2]=m_y3;
punkt[3]=m_y4;
punkt[4]=m_y5 ;
punkt[5]=m_y6;
punkt[6]=m_y7;
punkt[7]=m_y8;
punkt[8]=m_y9;
punkt[9]=m_y10;

     for(int i=0;i<10;i++)
                         {
        if( punkt[i] > 250 || punkt[i] <0 ) {
           AfxMessageBox(" Bitte korrigieren Sie Ihre Eingaben."
                         " Die Werte dürfen nur zwischen 0 und 250          liegen. ");
return;
	              }
	
	}
zeichne=TRUE;
InvalidateRect(&rect);
UpdateWindow();
}

Die Variablen m_Y0......m_Y9 sind natürlich mit den zehn Editboxen verbunden. Nachdem geprüft wurde, daß die Werte tatsächlich zwischen 0 und 250 liegen, wird der Wert von zeichne auf TRUE gesetzt und mit InvalidateRect() der Zeichenvorgang ausgelöst. Der Quellcode zum Zeichnen befindet sich in OnPaint() und sieht wie folgt aus:

void CGrafikView::OnPaint() 
{
CPaintDC dc(this);// device context for painting
GetDlgItem (IDC_ZEICHEN)->GetWindowRect(&rect); 
ScreenToClient(&rect);	
dc.Rectangle(rect);
dc.SetViewportOrg( rect.left, rect.top );
int hoch=rect.Height();
int breit=rect.Width();
int schritt = breit/10;
CPen pen,*oldpen;
pen.CreatePen(PS_SOLID,2,RGB(200,0,0));
oldpen= dc.SelectObject(&pen);

   if(zeichne){
dc.MoveTo(0,hoch);
dc.LineTo(schritt,hoch-punkt[0]);

         for(int i=1;i<10;i++)
                       {
         dc.MoveTo(i*schritt,hoch-punkt[i-1]);
         dc.LineTo((i+1)*schritt,hoch-punkt[i]);
                       }
               }
}

Die ID des Gruppenfeldes auf der Dialogseite heißt IDC_ZEICHEN.

Mit GetDlgItem (IDC_ZEICHEN)->GetWindowRect(&rect); wird die Größe des Gruppenfeldes in dem CRect-Objekt rect gespeichert. Da die Position des Gruppenfeldes auf der Dialogseite in Bildschirmkoordinaten geschrieben ist, müssen wir diese in Clientkoordinaten umwandeln. Die Funktion ScreenToClient(...) erledigt das für uns. Wir haben ja vor, die Werte innerhalb des Rechtecks zu zeichnen. Daher verlagern wir den Koordinatenursprung in die obere linke Ecke des Rechtecks. Die Funktion SetViewportOrg(...) erfüllt diese Aufgabe. Wenn Sie das Kapitel Grafik gelesen haben, werden Sie mit dem Rest des Quellcodes keine Probleme haben. Nun ist es an der Zeit, uns die beiden Funktionen zum Speichern und Laden der Werte anzuschauen: Die Nachrichten-Funktion zum Speichern der Daten heißt im Beispielprogramm OnSav(). Der Quellcode darin sieht wie folgt aus:

void CGrafikView::OnSav() 
{
     if(!zeichne){
         AfxMessageBox("Zuerst müssen Sie die Werte zeichnen.");
         return;
	         }
CFile Datei;
Datei.Open("kartei.txt",CFile::modeCreate|CFile::modeWrite);
CArchive ar(&Datei,CArchive::store);

        for(int i=0;i<10;i++)
             {
        ar<<punkt[i];
             }
ar.Close();
Datei.Close();	
 
}

Wie aus dem obigen Quellcode ersichtlich ist, wurde zuerst ein Objekt von CFile namens Datei deklariert. Mit der Funktion Open(...), die der Klasse CFile angehört, wird eine Datei namens kartei.txt angesprochen. CFile::modeCreate erzeugt diese Datei, falls sie noch nicht existiert und CFile::modeWrite setzt den Mode zum Schreiben.

Mit der Anweisung CArchive ar(&Datei,CArchive::store); wird ein Objekt vom Typ CArchive namens ar erzeugt. Im Konstruktor wird ar mit dem CFile Objekt Datei verbunden und durch CArchive::store wird dem Archive signalisiert, daß Daten gespeichert werden müssen. Genauso, wie cout<<.... in einem textorientierten C++ Programm, Daten auf den Bildschirm schreibt, so schreibt auch ar mit Hilfe der überladenen Operatoren(<<) die Daten in das CFile-Objekt auf den Datenträger. Mit den letzten beiden Anweisungen ar.Close und Datei.Colse schließen Sie die beiden Objekte. Analog dazu funktioniert das Laden von Daten. Die Funktion zum Laden der Daten heißt im Beispielprogramm OnLade(). Ihr Quellcode sieht wie folgt aus:

void CGrafikView::OnLade() 
{
CFile Datei;
Datei.Open("kartei.txt", CFile::modeRead);
CArchive ar(&Datei, CArchive::load);
      for(int i=0;i<10;i++)
             {
      ar>>punkt[i];
             }

m_y1=punkt[0];
m_y2= punkt[1];
m_y3=punkt[2];
m_y4=punkt[3];
m_y5=punkt[4];
m_y6=punkt[5];
m_y7=punkt[6];
m_y8=punkt[7];
m_y9=punkt[8];
m_y10=punkt[9];

zeichne=TRUE;
UpdateData(FALSE);
InvalidateRect(&rect);
UpdateWindow();
}

Wie schon bekannt, kann man die Daten nicht direkt laden und muß sie zuerst in einem CArchive-Objekt lagern. Zuerst wird ein CFile-Objekt namens Datei erzeugt. Mit Open(...) wird die Datei kartei.txt angesprochen und mit mode::read wird der Mode zum Lesen gesetzt. Mit CArchive ar(&Datei, CArchive::load); wird ein CArchive-Objekt ar erzeugt. Achten Sie im Konstruktor auf CArchive::load, was besagt, daß Daten aus dem Datenträger geladen werden müssen. Mit ar>>... laden Sie die gespeicherten Daten.

Als letztes bekommen Sie den Quellcode zum löschen der Werte zu sehen, was nicht sehr aufregend ist:

void CGrafikView::OnLoesch() 
{
     for(int i=0;i<10;i++)
              {
     punkt[i]=0;
              }

m_y1=punkt[0];
m_y2=punkt[1];
m_y3=punkt[2];
m_y4=punkt[3];
m_y5=punkt[4];
m_y6=punkt[5];
m_y7=punkt[6];
m_y8=punkt[7];
m_y9=punkt[8];
m_y10=punkt[9];
UpdateData(FALSE);
InvalidateRect(&rect);
UpdateWindow();
SetFocus()->GetDlgItem(IDC_EDIT_Y1);
}

 

      Vorheriges Kapitel: Drucken  Nächstes Kapitel: Dokument und Ansicht       Inhaltsverzeichnis Inhaltsverzeichnis       Die Downloadseite Download       Kontakt Kontakt