E
Die MFC beinhalten viel mehr als nur Klassen für die Programmierung der grafischen Benutzerschnittstelle von Windows. Sie finden darin auch viele Hilfs-Klassen für den Einsatz von Listen, Feldern, Datum und Uhrzeit oder Zuordnungstabellen. Durch den Einsatz dieser Klassen gewinnen Sie größeren Einfluß auf die Daten ihres Programms, und Sie vereinfachen viele der Operationen, die für die Bearbeitung komplexer Datenstrukturen, wie zum Beispiel Listen, erforderlich sind.
Wenn Sie beispielsweise die MFC-Klasse für Felder verwenden (CArray), können Sie deren Größe dynamisch anpassen. Das befreit Sie von der Notwendigkeit, überdimensionierte Felder anzulegen, um sicher zu stellen, daß alle von der Applikation angeforderten Daten gespeichert werden können. Auf diese Weise sparen Sie Speicher. Die anderen Kollektions-Klassen bieten eine Fülle von ähnlichen Vorteilen. n
Die Feldklassen in den MFC ermöglichen es Ihnen, eindimensionale Feldobjekte, in denen Sie jede Art von Daten speichern können, zu erstellen und zu manipulieren. Diese Feldobjekte arbeiten im Prinzip so wie normale Standardfelder, die Sie bereits in Ihren Programmen verwenden, außer daß die MFC diese Feldobjekte dynamisch vergrößern oder verkleinern können, während das Programm läuft. Das bedeutet, daß Sie sich bei der Deklaration eines Felds nicht schon über seine Dimension im klaren sein müssen. Da die MFC-Felder dynamisch anwachsen können, müssen Sie sich keine Gedanken über die Speicherplatzverschwendung machen, die oft bei konventionellen Feldern auftritt, da diese so dimensioniert sein müssen, daß sie die im Programm vorkommende maximale Anzahl an Elementen aufnehmen können, unabhängig davon, ob Sie im Einzelfall jedes Element verwenden oder nicht.
Die Feldklassen umfassen CByteArray, CDWordArray, CObArray, CPtrArray, CUIntArray, CWordArray und CStringArray. Wie Sie aus den Namen schon ersehen können, ist jede Klasse für die Speicherung eines bestimmten Datentyps gedacht. Die Klasse CUIntArray wird in den Beispielen dieses Abschnitts verwendet, und ist eine Feldklasse, die für nichtvorzeichenbehaftete Ganzzahlen vorgesehen ist. Die Klasse CPtrArray repräsentiert eine Sammlung von Zeigern auf void. Die Feldklasse CObArray nimmt von CObject abgeleitete Objekte auf. Somit unterscheiden sich alle Feldklassen hauptsächlich in der Art des Datentyps für den sie gedacht sind. Wenn Sie mit der Verwendung einer dieser Feldklasse zurechtkommen, können Sie auch alle anderen einsetzen. Tabelle E.1 listet die Mitgliedsfunktionen der Feldklassen auf und beschreibt sie kurz.
Tabelle E.1: Mitgliedsfunktionen der Feldklassen (Forts.)
Funktion |
Beschreibung |
Add |
Hängt einen Wert an das Ende des Felds an. Gleichzeitig wird, falls erforderlich, die Größe des Felds erhöht. |
ElementAt |
Liefert eine Referenz auf das über den Index abgegebene Feldelement. |
FreeExtra |
Gibt den Speicher von unbenutzten Elementen frei. |
GetAt |
Liefert das Eelement mit dem angegebenen Index. |
GetSize |
Liefert die Anzahl der Feldelemente. |
GetUpperBound |
Liefert die Obergrenze des Felds, das bedeutet den höchsten Index, an dem noch ein Feldelement gespeichert werden kann. |
InsertAt |
Fügt ein neues Element am angegebenen Index ein, wobei eventuell bereits vorhandene nachfolgende Elemente nach hinten geschoben werden. |
RemoveAll |
Löscht alle Feldelemente. |
RemoveAt |
Löscht das Feldelement mit dem angegebenen Index. |
SetAt |
Setzt ein bestimmtes Feldelement auf einen angegebenen Wert. Der Index des gewünschten Elements muß zulässig sein, da das Feld nicht erweitert wird. |
SetAtGrow |
Setzt ein bestimmtes Feldelement auf einen angegebenen Wert. Falls erforderlich wird die Größe des Felds erweitert. |
SetSize |
Legt die anfängliche Größe eines Felds und die Menge der Feldelemente, um die es falls erforderlich erweitert wird, fest. Durch das Erhöhen des Felds um mehr als ein Element sparen Sie Zeit, aber Sie verschwenden eventuell auch Speicherplatz. |
Um die Arbeitsweise von Feldklassen darzustellen, beinhaltet dieses Kapitel eine Feldapplikation. Nach einer kurzen Vorstellung der Applikation, werden Sie im darauf folgenden Abschnitt sehen, wie Sie sie selbst erstellen können. Wenn Sie das Programm starten, sehen Sie das in Abbildung E.1 gezeigte Fenster. Das Fenster zeigt den aktuellen Inhalt des Felds. Da das Feldobjekt der Applikation (in diesem Falle eine Instanz von CUIntArray) mit zehn Elementen startet, werden die Werte dieser Elemente (numeriert von 0 bis 9) auf dem Bildschirm dargestellt. Die Applikation ermöglicht es Ihnen, Elemente dieses Felds zu verändern, hinzuzufügen oder zu löschen, um danach die Ergebnisse wieder anzusehen.
Abbildung E.1: Das Beispielprogramm für Felder ermöglicht es Ihnen, mit MFC-Feldklassen zu experimentieren.
Sie können auf verschiedene Weise Elemente zu dem Feld hinzufügen. Um diese Möglichkeiten zu sehen, klicken Sie in das Fenster der Applikation. Der in Abbildung E.2 dargestellte Dialog erscheint. Geben Sie im Eingabefeld Index eine Indexnummer an und im Eingabefeld Value können Sie den gewünschten Wert eintragen. Legen Sie dann fest, ob Sie das Element festlegen, einzufügen oder hinzufügen möchten. Wenn sie die Option Set wählen, wird der Wert des Elements, das Sie unter Index angegeben haben, auf den Wert des Eingabefelds Value gesetzt. Die Operation Insert erstellt ein neues Feldelement an der durch den Index angegebenen Stelle, wodurch alle nachfolgenden Elemente verschoben werden. Die Funktion Add schließlich hängt nur ein neues Feldelement an das Ende des Felds an. In diesem Fall ignoriert das Programm den Wert des Felds Index im Dialog.
Abbildung E.2: Der Dialog Add to Array ermöglicht es Ihnen, Feldelemente hinzuzufügen.
Angenommen, Sie geben den Wert 3 im Indexfeld des Dialogs ein, tragen in das Feld Value den Wert 15 ein, belassen das Optionsfeld auf der Wahl Set und klicken dann auf die Schaltfläche OK. In Abbildung E.3 sehen Sie das Ergebnis: das Programm hat den Wert 15 in das Element 3 des Felds geschrieben, wobei der vorher dort gespeicherte Wert überschrieben wurde. Geben Sie nun im Eingabefeld Index den Wert 2, sowie im Feld Value den Wert 25 ein und wählen Sie das Optionsfeld Insert. Klicken Sie nun auf OK. Abbildung E.4 zeigt das Ergebnis: das Programm speichert ein neues Element in das Feld hinein, wobei alle anderen Elemente nach hinten verschoben werden.
Abbildung E.3: Der Wert 15 wurde in das Feldelement 3 geschrieben.
Abbildung E.4: Nun sind die neuen Feldelemente zu sehen. Insgesamt sind es nun 11 Elemente.
Ein ganz besonderer Aspekt, den Sie ausprobieren sollten und der in besonderem Maße zeigt wie dynamisch MFC-Felder sind, ist das Einfügen eines Feldelements, das sich jenseits des Endes eines Felds befindet. Angenommen das Programm befindet sich im Zustand, der in Abbildung E.4 zu sehen ist. Wenn Sie nun im Eingabefeld Index den Wert 20 eintragen und im Eingabefeld Value den Wert 45 und dann noch das Optionsfeld Set anwählen, bekommen Sie das Ergebnis, daß Sie in Abbildung E.5 sehen können. Da es noch kein Element mit der Nummer 20 gab, hat die Feldklasse alle notwendigen Elemente erzeugt, um an das Element zwanzig heranzukommen. Sie brauchen also nicht jederzeit zu wissen, wie viele Elemente im Zelt bereits vorhanden sind. Dies funktioniert nicht mit herkömmlichen Feldern.
Neben dem Hinzufügen von neuen Elementen in das Feld, können Sie auch wieder Elemente daraus entfernen, und zwar auf zwei verschiedene Weisen. Um dies zu tun, klicken sie mit der rechten Maustaste in das Fenster. Daraufhin erscheint der in Abbildung E.6 zu sehende Dialog. Wenn Sie im Eingabefeld Remove einen Index angeben und danach auf die Schaltfläche OK klicken, löscht das Programm das ausgewählte Element aus dem Feld. Dies ist die genaue Umkehrung des Kommandos Insert, weil durch Remove das Feld um das gewünschte Element verkleinert wird. Wahlweise können Sie durch anklicken des Kontrollfelds Remove All vom Programm gleichzeitig alle Elemente des Felds entfernen, so daß nur ein leeres Feld zurückbleibt.
Abbildung E.5: Die Feldklasse hat automatisch die erforderlichen Elemente hinzugefügt, um auf Element 20 zugreifen zu können.
Abbildung E.6: Der Dialog Remove from Array erlaubt es Ihnen, Feldelemente wieder zu löschen.
Nun möchten Sie vielleicht genauer sehen, wie diese Feldmanipulation funktioniert. Es ist eigentlich sehr einfach. Als erstes deklariert das Programm ein Feldobjekte als Element der Ansichtsklasse:
CUIntArray array;
Danach wird das Feldobjekt im Konstruktor der Ansichtsklasse mit 10 Elementen initialisiert:
array.SetSize(10,5);
Die Funktion SetSizenimmt 2 Parameter entgegen, wobei der erste die anfängliche Anzahl von Elementen im Feld angibt, und der zweite festgelegt um wieviel Elemente das Feld wenn erforderlich anwächst. Sie müssen die Funktion SetSize nicht aufgerufen, um Feldklassen benutzen zu können.
Nachdem Sie die Größe des Felds festgelegt haben, wartet das Programm darauf, daß der Benutzer mit der linken oder rechten Maustaste in das Fenster klickt. Wenn der Benutzer dies tut, zeigt das Programm den dazu entsprechenden Dialog und bearbeitet die im Dialog eingegeben Zahlenwerte. Listing E.1 zeigt die Funktion OnLButtonDown, die das Klicken der linken Maustaste bearbeitet.
Listing E.1: CArrayView::OnLButtonDown() |
{void CArrayView::OnLButtonDown(
UINT nFlags, CPoint point)
{
ArrayAddDlg dialog(this);
dialog.m_index = 0;
dialog.m_value = 0;
dialog.m_radio = 0;
int result = dialog.DoModal();
if (result == IDOK)
{
if (dialog.m_radio == 0)
array.SetAtGrow(dialog.m_index,
dialog.m_value);
else if (dialog.m_radio == 1)
array.InsertAt(dialog.m_index,
dialog.m_value, 1);
else
array.Add(dialog.m_value);
Invalidate();
}
CView::OnLButtonDown(nFlags, point);
}
Dieser Programmcode beginnt mit der Erstellung eines Dialogobjekts und seiner Initialisierung, wie Sie es in Kapitel 2 finden können. Wenn der Benutzer den Dialog durch Klicken auf die Schaltfläche OK verläßt, überprüft die Funktion OnLButtonDown den Wert der Mitgliedsvariable des Dialogs m_radio. Der Wert 0 bedeutet dabei, daß das erste Optionsfeld Set) gewählt wurde, 1 bedeutet das die zweite Option (Insert) gewählt wurde und 2 bedeutet das die dritte Option (Add) aktiviert war.
Wenn der Benutzer den Wert eines Feldelements setzen möchte, ruft das Programm die Funktion SetAtGrow auf und übergibt den Feldindex und den neuen Wert als Argument. Im Gegensatz zu der Funktion SetAt, welche Sie nur mit bereits vorhandenen gültigen Indexnummern verwenden können, erlaubt SetAtGrow das Vergrößern eines Felds, falls dies für den neuen Index erforderlich ist. Auf diese Weise wurden die zusätzlichen Elemente hinzugefügt, als Sie im oberen gezeigten Beispiel das Element 20 anwählten.
Wenn der Benutzer die Option Insert gewählt hat, ruft das Programm die Funktion Insert auf, und übergibt dabei den Feldindex und den neuen Wert als Argumente. Das veranlaßt die MFC dazu, ein neues Feldelement zu erzeugen, das an der durch den Index angegebenen Stelle auftaucht, wobei die anderen Feldelemente verschoben werden. Hat der Benutzer die Option Add gewählt, ruft das Programm die Funktion Add auf, welche ein neues Element am Ende des Felds anfügt. Der einzige Parameter dieser Funktion ist der neue Wert des Elements. Der Aufruf von Invalidate zwingt das Fenster dazu, sich neu zu zeichnen und damit die neuen Informationen anzuzeigen.
Nachdem Sie nun gesehen haben wie sich Feldelemente hinzufügen, verändern und löschen lassen, können Sie einen Blick auf die Funktion OnDraw der Applikation werfen, welche den Inhalt des Felds ausliest und die entsprechenden Werte für jedes Element ausgibt. Der Code für diese Funktion ist in Listing E.2 dargestellt.
Listing E.2: CArrayView::OnDraw() |
void CArrayView::OnDraw(CDC* pDC)
{
CArrayDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Font-Höhe ermitteln
TEXTMETRIC textMetric;
pDC->GetTextMetrics(&textMetric);
int fontHeight = textMetric.tmHeight;
// wieviel Elemenete passen denn rein?
int count = array.GetSize();
int displayPos = 10;
// Feldelemente anzeigen
for (int x=0; x<count; ++x)
{
UINT value = array.GetAt(x);
char s[81];
wsprintf(s,
"Element %d contains the value %u.", x, value);
pDC->TextOut(10, displayPos, s);
displayPos += fontHeight;
}
}
Zunächst ermittelt das Programm die Höhe des aktuellen Zeichensatzes, um den erforderlichen Platz für jede Textzeile im Fenster zu ermitteln. Danach informiert es sich über die Anzahl der Elemente im Feld, indem es die Feldobjektfunktion GetSize aufruft. Zuletzt verwendet das Programm diese Anzahl für eine for-Schleife in der die Funktion Getvalue des Feldobjekts benutzt wird, um den jeweils indizierten Feldeintrag auszulesen. Das Programm konvertiert diesen Wert zur Darstellung in eine Zeichenkette.
Da Sie mit der rechten Maustaste den Dialog Remove from Array aufrufen, muß es eine entsprechende Funktion geben, die diese Nachricht verarbeitet: OnRButtonDown. Diese Funktion wird in Listing E.3 gezeigt.
Listing E.3: CArrayView:OnRButtonDown() |
void CArrayView::OnRButtonDown(
UINT nFlags, CPoint point)
{
ArrayRemoveDlg dialog(this);
dialog.m_remove = 0;
dialog.m_removeAll = FALSE;
int result = dialog.DoModal();
if (result == IDOK)
{
if (dialog.m_removeAll)
array.RemoveAll();
else
array.RemoveAt(dialog.m_remove);
Invalidate();
}
CView::OnRButtonDown(nFlags, point);
}
Nach anzeigen des Dialogs wird der Wert der Mitgliedsvariablen m_removeAll überprüft. Der Wert TRUE bedeutet, daß das Kontrollfeld vom Benutzer aktiviert wurde, um alle Elemente des Felds zu löschen. In diesem Fall wird die Funktion RemoveAll des Felds aufgerufen. Anderenfalls wird die Funktion RemoveAt benutzt, wobei als Parameter die eingegebene Indexnummer des gewünschten Elements übergeben wird. Durch den Aufruf von Invalidate wird das Fenster dazu veranlaßt, sich neu zu zeichnen und dadurch die neuen Informationen anzuzeigen.
Listen sind im Prinzip den gerade vorgestellten Feldklassen sehr ähnlich. In einer verketteten Liste besitzt jedes Element (genannt Knoten) zusätzliche Zeiger, die auf das vorhergehende und nachfolgende Elemente verweisen. Listen sind also die besseren Datenstrukturen, wenn es darum geht Elemente schnell einzufügen oder zu löschen. Das Finden eines Elements der Liste kann jedoch langsamer sein, als das Auffinden eines Elements in einem Feld, weil eine Liste oft sequentiell durchlaufen werden muß, um von einem Zeiger zum nächsten zu gelangen.
Wenn Sie Listen verwenden, müssen Sie ein paar spezielle Vokabeln kennen. Sie müssen wissen, daß der Kopf einer Liste der erste Knoten in der Liste ist, und der Fuß (oder auch Schwanz) einer Liste den letzten Knoten der Liste bezeichnet. Sie sehen ein Beispiel dafür in Abbildung E.7. Jeder Knoten weiß, wie er den nächsten Knoten erreichen kann, also denjenigen, der ihm in der Liste folgt. Diese Termini werden oft innerhalb der Beschreibung der Listenklassen der MFC verwendet.
Die MFC stellen drei verschiedene Listenklassen für Ihre eigenen Listen zur Verfügung. Jede dieser Klassen hat die gleichen Mitgliedsfunktionen. Die Klassen unterscheiden sich nur in der Art des Datentyps den sie in ihrer Liste speichern können. Tabelle E.2 führt die einzelnen Funktionen auf und beschreibt sie kurz.
Abbildung E.7: Eine verkettete Liste hat einen Kopf und einen Fuß, dazwischen befinden sich die übrigen Knoten.
Tabelle E.2: Mitgliedsfunktionen der Listenklassen (Forts.)
Funktion |
Beschreibung |
AddHead |
Fügt einen Knoten am Kopf der Liste ein und macht diesen Knoten zum neuen Kopf. |
AddTail |
Fügt einen Knoten am Fuß der Liste ein und macht diesen Knoten zum neuen Fuß. |
Find |
Durchsucht die Liste sequentiell, um einen gegeben Objektzeiger zu finden. Der Rückgabewert ist vom Typ Position. |
FindIndex |
Durchläuft die Liste sequentiell und hält an dem Knoten an, der durch den angegebenen Index bestimmt wird. Liefert als Rückgabewert eine Wert vom Typ Position. |
GetAt |
Liefert den Knoten an der angegebenen Stelle. |
GetCount |
Ermittelt die Anzahl von Knoten der Liste. |
GetHead |
Liefert den Kopf der Liste. |
GetHeadPosition |
Liefert die Position des Listenkopfes. |
GetNext |
Liefert den nächsten Knoten in der Liste, wenn über diese Liste iteriert wird. |
GetPrev |
Liefert den vorhergehenden Knoten einer Liste, wenn über diese Liste iteriert wird. |
GetTail |
Liefert den Fuß einer Liste. |
GetTailPosition |
Ermittelt die Position des Listenfußes. |
InsertAfter |
Fügt einen Knoten nach der angegebenen Stelle ein. |
InsertBefore |
Fügt einen Knoten vor der angegebenen Stelle ein. |
IsEmpty |
Liefert den Wert TRUE zurück, wenn die Liste leer ist, anderenfalls wird FALSE zurückgeliefert. |
RemoveAll |
Löscht alle Knoten der Liste. |
RemoveAt |
Löscht einen einzelnen Knoten aus der Liste. |
RemoveHead |
Löscht den Kopf der Liste. |
RemoveTail |
Löscht den Fuß der Liste. |
SetAt |
Setzt den Wert eines Knotens an der angegebenen Position. |
Nachdem Sie nun einen Überblick über die Listenklassen und ihre Mitgliedsfunktionen bekommen haben, werden Sie in einer Listenapplikation sehen wie diese eingesetzt werden können. Wenn Sie das Programm starten, sehen Sie das in Abbildung E.8 abgebildete Fenster. Das Fenster zeigt die Werte eines einzigen Knotens mit dem die Liste beginnt. Jeder Knoten in der Liste kann zwei verschiedene Werte haben, von denen beide jeweils vom Typ Integer sind.
Abbildung E.8: Die Listenapplikation beginnt mit einem Element in der Liste.
Sie können die Listenapplikation benutzen, um Knoten zur Liste hinzuzufügen und zu löschen. Um einen Knoten hinzuzufügen klicken Sie mit der linken Maustaste in das Applikationsfenster. Daraufhin erscheint der in Abbildung E.9 zu sehende Dialog. Geben Sie zwei beliebige Werte für den neuen Knoten ein und klicken dann auf die Schaltfläche OK. Das Programm fügt den neuen Knoten am Fuß der Liste an, und stellt die neue Liste im Fenster dar. Wenn Sie zum Beispiel die Werte 55 und 65 im Dialog eingeben, sehen Sie ein Fenster wie in Abbildung E.10.
Abbildung E.9: Durch einen linken Mausklick erhalten Sie den Dialog zum Hinzufügen eines Knotens.
Abbildung E.10: Jeder Knoten der Liste kann zwei verschiedene Werte enthalten.
Sie können auch Knoten aus der Liste entfernen. Klicken Sie dazu mit der rechten Maustaste in das Fenster, woraufhin der Dialog aus Abbildung E.11 erscheint. In diesem Dialog können Sie auswählen, ob Sie den Kopf oder den Fuß der Liste löschen möchten. Wenn Sie den Dialog durch anklicken von OK verlassen, löscht das Programm den festgelegten Knoten und zeigt das neue Ergebnis im Fenster an.
Abbildung E.11: Klicken Sie mit der rechten Maustaste in das Fenster, um einen Knoten zu löschen.
Die Deklaration einer Liste ist genauso einfach, wie die Deklaration eines anderen Datentyps. Geben Sie nur den Namen der Klasse an, die Sie benötigen, gefolgt von dem Namen dieses Objekts. In der Listenapplikation finden Sie zum Beispiel diese Deklaration:
CPtrList list;
Hier deklariert das Programm ein Objekt der Klasse CPtrList. Diese Klasse beinhaltet eine verkettete Liste von Zeigern, das bedeutet, daß die Liste jeden beliebigen Typ von Informationen referenzieren kann.
Obwohl Sie zur Initialisierung einer leeren Liste nicht viel tun müssen, ist es doch erforderlich, festzulegen, welche Arten von Information durch die Zeiger in der Liste repräsentiert werden sollen. Das bedeutet, daß Sie genau festlegen müssen, wie ein Knoten der Liste aussehen soll. Die Listenapplikation deklariert einen Knoten wie in Listing E.4 zu sehen ist.
Listing E.4: Die Struktur CNode |
struct CNode
{
int value1;
int value2;
};
Hier wird ein Knoten als Struktur definiert, die zwei Integer-Werte beinhaltet. Sie können natürlich jede beliebige Art von Datenstrukturen für ihre eigenen Knoten benutzen. Um einen Knoten an eine Liste anzufügen, benutzen Sie den Operator new, um eine solche Knotenstruktur im Speicher anzulegen, und übergeben dann den zurückgelieferten Zeiger an die Zeigerliste. Die Listenapplikation beginnt mit einer Liste die einen einzelnen Knoten enthält, der im Konstruktor der Ansichts-Klasse erstellt wird (Listing E.5).
Listing E.5: isting E.5 Der Konstruktor von CMyListView |
CMyListView::CMyListView()
{
CNode* pNode = new CNode;
pNode->value1 = 11;
pNode->value2 = 22;
list.AddTail(pNode);
}
Zunächst wird im Hauptspeicher eine neue Struktur vom Typ CNode angelegt, dann werden die beiden Mitgliedsvariablen initialisiert. Danach wird dieser Knoten durch den Aufruf der Listenfunktion AddTail an die Liste angefügt. Da die Liste leer war entspricht das Anhängen eines Knotens am Fuß der Liste dem Hinzufügen eines Knotens am Kopf der Liste. Darum könnte hier auch die Funktion AddHead benutzt werden. In beiden Fällen hat die Liste nur einen Knoten, der sowohl der Kopf, als auch der Fuß der Liste ist.
Obwohl Sie einen Knoten an einer beliebigen Stelle der Liste einfügen können, ist es doch der einfachste Weg einen Knoten am Kopf oder am Fuß der Liste anzuhängen, wodurch der neue Knoten der neue Kopf oder Fuß der Liste wird. In der Listenapplikation können Sie mit der linken Maustaste den Dialog Add Node aufrufen, weshalb Sie einen Blick auf die Funktion OnLButtonDown werfen sollten (Listing E 6).
Listing E.6: CMyListView::OnLButtonDown() |
void CMyListView::OnLButtonDown(
UINT nFlags, CPoint point)
{
// erzeuge und initialisiere das Dialogfeld
AddNodeDlg dialog;
dialog.m_value1 = 0;
dialog.m_value2 = 0;
// Display the dialog box.
int result = dialog.DoModal();
// If the user clicked the OK button...
if (result == IDOK)
{
// erzeuge und initialisiere den neuen Knoten
CNode* pNode = new CNode;
pNode->value1 = dialog.m_value1;
pNode->value2 = dialog.m_value2;
// füge den Knoten an die Liste an
list.AddTail(pNode);
Invalidate();
}
CView::OnLButtonDown(nFlags, point);
}
Nach dem Anzeigen des Dialogs überprüft das Programm, ob der Benutzer den Dialog durch Anklicken der Schaltfläche OK beendet hat. Ist dies der Fall, möchte der Benutzer einen neuen Knoten zur Liste hinzufügen. Darum erzeugt das Programm einen neuen Knoten, auf die gleiche Weise wie schon beim ersten Knoten im Konstruktor der Ansichts-Klasse. Dann wird dieser Knoten auf die gleiche Weise hinzugefügt, nämlich durch einen Aufruf der Funktion AddTail. Wenn Sie die Listenapplikation modifizieren möchten, könnten Sie hier eventuell die Wahlmöglichkeit einbauen, entweder am Kopf oder am Fuß der Liste anzufügen, anstatt automatisch am Fuß der Liste die Erweiterung vorzunehmen.
Das Löschen eines Knotens aus einer Liste kann einfach oder komplizierter sein, abhängig davon, wo in der Liste der zu löschende Knoten liegt. Genau wie beim Hinzufügen eines Knotens erfordert das Arbeiten mit Knoten die nicht Kopf oder Fuß der Liste sind zunächst die Ermittlung der Position des gewünschten Knotens innerhalb der Liste. Im nächsten Abschnitt werden Sie etwas über Positionierung von Knoten sehen, und Sie erfahren, wie man über eine Liste iteriert. Um die Beispielapplikation einfach zu halten, ermöglicht Sie Ihnen nur das Löschen von Elementen am Kopf oder Fuß der Liste, wie Sie in Listing E.7 sehen können.
Listing E.7: CMyListView::OnRButtonDown() |
void CMyListView::OnRButtonDown(
UINT nFlags, CPoint point)
{
RemoveNodeDlg dialog;
dialog.m_radio = 0;
int result = dialog.DoModal();
if (result == IDOK)
{
CNode* pNode;
// die Liste darf nicht leer sein
if (list.IsEmpty())
MessageBox("keine Knoten zu löschen");
else
{
// entferne den Knoten ...
if (dialog.m_radio == 0)
pNode = (CNode*)list.RemoveHead();
else
pNode = (CNode*)list.RemoveTail();
// ... und lösche ihn
delete pNode;
Invalidate();
}
}
CView::OnRButtonDown(nFlags, point);
}
Nach der Anzeige des Dialogs überprüft das Programm, ob der Benutzer den Dialog mit der Schaltfläche OK beendet hat. Ist dies der Fall, muß überprüft werden, ob der Benutzer einen Knoten vom Kopf oder vom Fuß der Liste entfernen möchte. Wenn das Optionsfeld Remove Head aktiviert war, dann ist der Wert der Mitgliedsvariablen m_radio des Dialoges 0. In diesem Fall wird die Funktion RemoveHead der Listenklassen aufgerufen. Andernfalls ruft das Programm die Funktion RemoveTail auf. Beide Funktionen liefern einem Zeiger, der auf das entfernte Objekt zeigt. Beachten Sie, daß das Programm vor dem Aufruf einer dieser Funktionen mit Hilfe von IsEmpty überprüft, ob die Liste überhaupt noch Knoten enthält. Sie können keinem Knoten aus einer leeren Liste entfernen.
Manchmal ist es erforderlich eine ganze Liste Element für Element abzuarbeiten (zu iterieren). Das kann zum Beispiel erforderlich sein, um die Werte aller Elemente einer Liste vom Kopf bis zum Fuß nacheinander aufzulisten, so wie es auch in der Listenapplikation geschieht (Listing E.8).
Listing E.8: CMyListView::OnDraw() |
void CMyListView::OnDraw(CDC* pDC)
{
CListDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
TEXTMETRIC textMetric;
pDC->GetTextMetrics(&textMetric);
int fontHeight = textMetric.tmHeight;
// Initialize values used in the loop.
POSITION pos = list.GetHeadPosition();
int displayPosition = 10;
int index = 0;
// Iteriere über die Liste,
// und zeige alle Elemente an
while (pos != NULL)
{
CNode* pNode = (CNode*)list.GetNext(pos);
char s[81];
wsprintf(s,
"Node %d contains %d and %d.",
index, pNode->value1, pNode->value2);
pDC->TextOut(10, displayPosition, s);
displayPosition += fontHeight;
++index;
}
}
In diesem Listing ermittelt das Programm die Position des Listenkopfes mit Hilfe der Funktion GetHeadPosition. Der Rückgabewert ist eine Positionsangabe, die viele Mitgliedsfunktionen der Listenklassen benutzen, um einen bestimmten Knoten schnell aufzufinden. Für eine Iteration durch die Liste benötigen Sie diese Startposition.
In der while-Schleife ruft das Programm die Mitgliedsfunktion GetNext des Listenobjekts auf. Dazu wird als einziger Parameter die Position des zu verwendenden Knotens benötigt. Die Funktion liefert dann einen Zeiger auf diesen Knoten und setzt die Position auf das nächste Element der Liste. Wenn die Position der Wert NULL annimmt, hat das Programm das Ende der Liste erreicht. In Listing E.8 ist dieser NULL-Wert die Abbruchbedingung der while-Schleife.
Es gibt noch eine andere Gelegenheit, zu der Sie die elementweise Abarbeitung einer Liste benötigen: wenn das Programm im Begriff ist, sich selbst zu beenden, und alle Objekte einer Liste gelöscht werden müssen. In der Listenapplikation geschieht das im Destruktor der Ansichts-Klasse (Listing E.9).
Listing E.9: Der CMyListView-Destruktor |
CMyListView::~CMyListView()
{
// durchlaufe die Liste,
// und lösche jeden Knoten
while (!list.IsEmpty())
{
CNode* pNode = (CNode*)list.RemoveHead();
delete pNode;
}
}
Der Destruktor iteriert in der Schleife so lange über die Liste, bis IsEmpty TRUE zurückgibt. Innerhalb der Schleife entfernt das Programm jeweils den Kopf der Liste, wodurch jeweils der nächste Knoten zum Kopf der Liste wird. Danach wird der entfernte Knoten aus dem Speicher entfernt. Wenn die Liste leer ist, wurden auch alle Knoten, die das Programm angelegt hatte, aus dem Speicher entfernt.
Sie können die MFC-Kollektionsklassen dazu verwenden, Nachschlagetabellen zu erstellen. Wenn Sie zum Beispiel eine Ziffer durch das entsprechende Zahlwort ersetzen wollen, dann ist die Zuordnungsklasse genau die richtige Anwendung dafür. Dank der zahlreichen MFC-Zuordnungsklassen können Sie verschiedene Datentypen für die Schlüssel und Werte benutzen.
Zu den MFC-Zuordnungsklassen gehören CMapPtrRoPtr, CMapPtrToWord, CMapStringToOb, CMapStringToPtr, CMapStringToString, CMapWordToOb und CMapWordToPtr. Der erste Datentyp im Namen ist der Schlüsseldatentyp und der zweite der Wertdatentyp. So benutzt CMapStringToOb Zeichenketten als Schlüssel und Objekte als Werte, wohingegen CMapStringToString, als zweites Beispiel der obigen Liste, Zeichenketten sowohl als Schlüssel und als Wert benutzt. Alle Zuordnungslistenklassen ähneln einander und so verfügen sie auch über gleiche Mitgliedsvariablen, die in Tabelle E.3 aufgelistet sind.
Tabelle E.3: Funktionen der Zuordnungsklassen (Forts.)
Funktion |
Beschreibung |
GetCount |
Ermittelt die Anzahl der Elemente |
GetNextAssoc |
Ermittelt das folgende Elemente bei der Aufzählung der Zuordnung. |
GetStartPosition |
Ermittelt die Position des ersten Elements. |
IsEmpty |
Gibt TRUE zurück, wenn die Liste leer ist und FALSE, wenn dies nicht der Fall ist. |
Lookup |
Sucht den mit dem Schlüssel verbundenen Wert. |
RemoveAll |
Entfernt alle Listenelemente. |
RemoveKey |
Entfernt ein Elemente aus der Liste. |
SetAt |
Fügt ein Listenelement hinzu oder ersetzt ein Element mit einem passenden Schlüssel. |
In diesem Abschnitt gibt das Beispielprogramm den Inhalt einer Zuordnungsliste aus und ermöglicht es Ihnen, Werte aus der Liste zu erhalten, indem Sie den entsprechenden Schlüssel eingeben. Wenn Sie das Programm ausführen lassen, dann sehen Sie das Fenster aus Abbildung E.12.
Abbildung E.12: Diese Zuordnungsanwendung zeigt Ihnen den Inhalt eines Zuordnungsobjekts.
In diesem Fenster wird der Inhalt der Zuordnungsobjekte der Applikation angezeigt. Hier werden Ziffern als Schlüssel für den Zugriff auf Zahlenwörter gegeben. Wenn Sie einen Wert aus der Zuordnungsliste erhalten wollen, dann klicken Sie in das Fenster. Es öffnet sich dann der Dialog, den Sie in Abbildung E.13 sehen. Geben Sie die Ziffer ein, die Sie als Schlüssel verwenden wollen und klicken Sie dann OK. Das Programm sucht den entsprechenden Wert in der Zuordnungsliste und zeigt ihn dann in einem anderen Meldungsdialog an. Wenn Sie als Schlüssel zum Beispiel 8 eingeben, dann erhalten Sie die Ausgabe, die in Abbildung E.14 zu sehen ist. Falls der eingegebene Schlüssel nicht existiert, dann teilt Ihnen das Programm dies mit einer entsprechenden Nachricht mit.
Abbildung E.13: Der hier zu sehende Dialog ermöglicht es Ihnen, den einem Schlüssel zugeordneten Wert zu suchen.
Abbildung E.14: Dieses Nachrichtenfeld zeigt Ihnen das Ergebnis der Suche an.
Die Beispielanwendung beginnt mit einer Zuordnungsliste mit zehn Elemenen. Das Listenelement ist als Datenelement der Ansichtsklasse wie folgt definiert:
CMapStringToString map;
Dies ist ein Objekt der CMapStringToString-Klasse, was bedeutet, daß die Zuordnungsliste Zeichenfolgen als Schlüssel und Werte benutzt.
Die Erstellung des Zuordnungsobjekts füllt es noch lange nicht mit einem Wert. Diese Aufgabe bleibt Ihnen überlassen. In der Beispielanwendung geschieht dies im Ansichts-Klassen-Konstruktor (Listing E.10).
Listing E.10: CMapView-Konstruktor |
CMapView::CMapView()
{
map.SetAt("1", "One");
map.SetAt("2", "Two");
map.SetAt("3", "Three");
map.SetAt("4", "Four");
map.SetAt("5", "Five");
map.SetAt("6", "Six");
map.SetAt("7", "Seven");
map.SetAt("8", "Eight");
map.SetAt("9", "Nine");
map.SetAt("10", "Ten");
}
Die Funktion SetAt übernimmt als Parameter den Schlüssel und den mit dem Schlüssel verbundenen Wert der Zuordnungsliste. Wenn der Schlüssel bereits existiert, dann ersetzt die Funktion den mit dem Schlüssel verbundenen Wert durch den neu als zweites Argument angegebenen Wert.
Wenn Sie in das Fenster der Zuordnungsliste klicken, dann erscheint der Dialog Get Map Value. So ist es auch nicht verwunderlich, wenn die Mitgliedsfunktion der Ansichts-Klasse, OnLButtonDown hier ins Spiel kommt (Listing E.11).
Listing E.11: CMapView::OnLButtonDown() |
void CMapView::OnLButtonDown(
UINT nFlags, CPoint point)
{
GetMapDlg dialog(this);
dialog.m_key = "";
int result = dialog.DoModal();
if (result == IDOK)
{
CString value
BOOL found = map.Lookup(dialog.m_key,
value);
if (found)
MessageBox(value);
else
MessageBox("No matching value.");
}
CView::OnLButtonDown(nFlags, point);
}
In OnLButtonDown zeigt das Programm den Dialog in normaler Form an und überprüft, ob der Anwender die Dialogbox bereits durch einen Klick auf OK verlassen hat. Wenn der Anwender dies getan hat, dann ruft das Programm die Mitgliedsfunktion Lookup des Zuordnungslistenobjekts auf. Der im Dialog eingegebene Schlüssel wird der Funktion als erstes Argument übergeben. Das zweite Argument ist eine Referenz auf eine Zeichenfolge, in die die Funktion den Wert, den Sie aus der Zurordnungsliste erhält, speichern kann. Falls der Schlüssel nicht gefunden werden kann, gibt die Funktion Lookup FALSE zurück, falls dies nicht zutrifft, wird TRUE zurückgegeben. Das Programm benutzt diesen Rückgabewert, um festzustellen, ob es den Zeichenfolgenwert, den es aus der Zuordnungsliste erhalten hat oder eine Fehlermeldung anzeigen soll.
Um die Schlüssel und Werte in der Zuordnungsliste anzeigen zu können, muß das Programm diese iterieren, indem es von einem Eintrag zum nächsten springt und die Informationen für jedes Element der Zuordnungsliste ermittelt und anzeigt. Genau wie bei den Feld- und Listenbeispielen erreicht die Beispielanwendung dies mit ihrer OnDraw-Funktion, die Sie in Listing E.12 sehen.
Listing E.12: CMapView::OnDraw() |
void CMapView::OnDraw(CDC* pDC)
{
CMapDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
TEXTMETRIC textMetric;
pDC->GetTextMetrics(&textMetric);
int fontHeight = textMetric.tmHeight;
int displayPosition = 10;
POSITION pos = map.GetStartPosition();
CString key;
CString value;
while (pos != NULL)
{
map.GetNextAssoc(pos, key, value);
CString str = "Key '" + key +
"' is associated with the value '" +
value + "'";
pDC->TextOut(10, displayPosition, str);
displayPosition += fontHeight;
}
}
Vieles in OnDraw entspricht den anderen Versionen, die Sie in diesem Kapitel bereits kennengelernt haben. Die Aufzählung über die Zuordnungsliste beginnt mit einem Aufruf von GetStartPosition. Sie liefert die Position des ersten Listenelements in der Zuordnungsliste zurück (das ist nicht unbedingt auch das erste Element, das in die Liste eingefügt wurde). Innhalb einer while-Schleife ruft das Programm die Mitgliedsfunktion GetNextAssoc des Zuordnungslistenobjekts auf, der als einziges Argument der durch GetStartPosition ermittelte Wert übergeben wird. GetNextAssoc ermittelt den Schlüssel und den Wert an der gegebenen Stelle und aktualisiert dann die Position auf das nächste Element der Liste. Wenn diese Position den Wert NULL annimmt, hat das Programm das Ende der Liste erreicht.
Die MFC beinhalten Klassentemplates, die es Ihnen erlauben, Ihre eigenen speziellen Kollektionsklassen zu erstellen (mehr Informationen zu Templates finden Sie in Kapitel 26). Das Thema Templates kann sehr komplex sein, aber die Benutzung von Klassentemplates für Kollektionen ist sehr einfach. Nehmen Sie zum Beispiel an, sie möchten eine Feldklasse erstellen, die Daten vom in Listing E.13 gezeigten Typ speichern können soll.
Listing E.13: Eine Beispielstruktur |
struct MyValues
{
int value1;
int value2;
int value3;
};
Der erste Schritt bei der Benutzung der Schablone ist die Erstellung der Klasse, die so aussieht:
CArray<MyValues, MyValues&> myValueArray;
Hier ist CArray die Schablone, die Sie für Ihre eigene Klasse benutzen. Die beiden Parameter der Schablone geben die Typen an, die zum einen im Feld gespeichert werden sollen, und zum anderen für den Zugriff auf die Elemente verwendet werden sollen. In diesem Fall soll das Feld Daten vom Typ MyValues speichern können.
Um Ihr Feld nun zu erstellen, können Sie optional eine Anfangsgröße festlegen:
myValueArray.SetSize(10, 5);
Danach können Sie beginnen, Elemente zum Feld hinzuzufügen, wie Sie es hier sehen:
MyValues myValues;
myValueArray.Add(myValues);
Nachdem Sie das Feld aus einer Schablone erstellt haben, können Sie es so verwenden, wie jedes andere MFC-Feld auch. Sie haben das ja schon in einem früheren Abschnitt dieses Kapitels gesehen. Andere Klassentemplates für Kollektionen, die Sie benutzen können, sind CList und CMap. Das bedeutet, Sie können die gesamten Vorteile der in den MFC implementierten Kollektionsklassen übernehmen, um sie auf Ihre eigenen Bedürfnisse, was die zu speichernden Objekte angeht, zuzuschneiden, egal ob es um Felder, verkettete Listen oder Zuordnungslisten geht.
Es gibt nur wenige Programme, die nicht in der einen oder anderen Weise mit Zeichenketten arbeiten müssen. Die MFC-Klasse CString nimmt sich dieser Aufgabe an, indem sie Mitgliedsfunktionen zur Verfügung stellt, die sich sehr einfach handhaben lassen. In Tabelle E.4 finden Sie die am häufigsten verwendeten Mitgliedsfunktionen der Klasse CString.
Tabelle E.4: Häufig benutzte Mitgliedsfunktionen der Klasse CString
Funktion |
Beschreibung |
Compare |
Groß-/kleinschreibungsabhängiger Vergleich von zwei Zeichenketten. |
CompareNoCase |
Vergleich von zwei Zeichenketten ohne Berücksichtigung der Groß-/Kleinschreibung. |
Empty |
Löscht eine Zeichenkette. |
Find |
Sucht eine Teilzeichenkette. |
Format |
Formatiert Werte in CString-Zeichenketten wie die Funktion sprintf in C. |
GetAt |
Ermittelt ein Zeichen an einer bestimmten Stelle der Zeichenkette. |
GetBuffer |
Liefert einen Zeiger auf den Inhalt der Zeichenkette. |
GetLength |
Ermittelt die Länge der Zeichenkette. |
IsEmpty |
Liefert der Wert TRUE, wenn die Zeichenkette leer ist. |
Left |
Ermittelt den linken Teil einer Zeichenkette. |
MakeLower |
Wandelt eine Zeichenkette in Kleinbuchstaben. |
MakeReverse |
Dreht den Inhalt einer Zeichenkette um. |
MakeUpper |
Wandelt eine Zeichenkette in Großbuchstaben. |
Mid |
Ermittelt Zeichen an einer beliebigen Stelle einer Zeichenkette. |
Right |
Ermittelt den rechten Teil einer Zeichenkette. |
SetAt |
Setzt ein Zeichen an einer bestimmten Stelle der Zeichenkette. |
TrimLeft |
Entfernt führende Leerzeichen in einer Zeichenkette. |
TrimRight |
Entfernt Leerzeichen am Ende einer Zeichenkette. |
Neben den hier in der Tabelle aufgelisteten Funktionen, besitzt die Klasse CString auch noch einen vollständigen Satz an Operatoren für die Bearbeitung von Zeichenketten. Mit Hilfe dieser Operatoren können Sie Zeichenketten zusammenfügen (+), Werte zuweisen (=), die Zeichenkette wie ein C-Zeichenkette behandeln (mit dem Operator LPCTSTR) und vieles mehr.
Das Erstellen eines Zeichenkettenobjekts ist schnell und einfach auf diese Weise möglich:
CString str = "This is a test string";
Natürlich gibt es noch viele andere Wege ein Zeichenkettenobjekt anzulegen. Das hier gezeigte Beispiel ist nur einer davon. Sie können ebenso ein leeres Zeichenkettenobjekt erzeugen und später Zeichen hineinfüllen, Sie können Zeichenkettenobjekte aus einem bereits bestehenden Zeichenkettenobjekt erzeugen und Sie können sogar eine Zeichenkette aus einem sich wiederholenden Einzelzeichen aufbauen.
Nachdem Sie das Zeichenkettenobjekt erzeugt haben, können Sie alle Mitgliedsfunktionen einsetzen und die Zeichenkette so auf eine vielfältige Art und Weise manipulieren. Sie können zum Beispiel alle Zeichen einer Zeichenkette in Großbuchstaben umwandeln, und das geht so:
str.MakeUpper();
Um eine Zeichenkette zu verlängern, benutzen Sie den Operator + oder += :
CString sentence = "hello " + str;
sentence += " there."
Um zwei Zeichenketten zu vergleichen machen Sie einen ähnlichen Funktionsaufruf, wie in diesem Beispiel:
str.Compare("Test String");
Sie können auch zwei Zeichenkettenobjekte miteinander vergleichen;
CString testStr = "Test String";
str.Compare(testStr);
Noch schöner sieht es so aus:
if (testStr == str)
Bei der Durchsicht der Online-Dokumentation werden Sie feststellen, daß die meisten der anderen Mitgliedsfunktionen von CString ähnlich einfach zu handhaben sind.
Wenn Sie jemals versucht haben die vom Computer gelieferten Zeitangaben zu verarbeiten, dann werden Sie sicherlich froh sein, daß es die beiden MFC-Klassen CTime und CTimeSpan gibt. Sie repräsentieren die absolute Zeit und eine Zeitspanne. Der folgende Abschnitt zeigt Ihnen, wie Sie den Einstieg in diese Klassen finden. Werfen Sie aber zunächst einen Blick auf die Tabelle E.5. Sie listet die Mitgliedsfunktionen der Klasse CTime auf. Die Mitgliedsvariablen von CTimeSpan finden Sie in Tabelle E.6.
Tabelle E.5: Die Mitgliedsfunktionen der Klasse CTime
Funktion |
Beschreibung |
Format |
Konstruiert eine Zeichenkette, die die Zeit des Objekts widerspiegelt. |
FormatGmt |
Konstruiert eine Zeichenkette, die die Zeit des Objekts widerspiegelt, und zwar als GMT- (oder UTC-) Zeit. GMT steht für Greenwich Mean Time. |
GetCurrentTime |
Erzeugt ein Objekt von Typ CTime mit der aktuellen Uhrzeit. |
GetDay |
Ermittelt den Tag der Zeitangabe als Integer-Zahl. |
GetDayOfWeek |
Ermittelt den Wochentag als Nummer, basierend auf der regionalen Einstellung. |
GetGmtTm |
Ermittelt die Sekunde, Minute, Stunde, den Tag, Monat, das Jahr, den Wochentag und den Tag des Jahres als tm-Struktur. |
GetHour |
Ermittelt die Stunde als Integer-Zahl. |
GetLocalTm |
Ermittelt die lokale Zeit und liefert Sekunde, Minute, Stunde, Tag, Monat, Jahr, Wochentag und den Tag des Jahres als tm-Struktur zurück. |
GetMinute |
Ermittelt die Minuten als Integer-Zahl. |
GetMonth |
Ermittelt den Monat als Integer-Zahl. |
GetSecond |
Ermittelt die Sekunden als Integer-Zahl. |
GetTime |
Ermittelt Uhrzeit als time_t-Wert. |
GetYear |
Ermittelt das Jahr als Integer-Zahl. |
Tabelle E.6: Die Mitgliedsfunktionen der Klasse CTimeSpan
Funktion |
Beschreibung |
Format |
Konstruiert eine Zeichenkette, die die Zeitangabe des Zeitspannenobjekts widerspiegelt. |
GetDays |
Ermittelt die Tage. |
GetHours |
Ermittelt die Stunden des aktuellen Tags. |
GetMinutes |
Ermittelt die Minuten der aktuellen Stunde. |
GetSeconds |
Ermittelt die Sekunden der aktuellen Minute. |
GetTotalHours |
Ermittelt die gesamten Stunden. |
GetTotalMinutes |
Ermittelt die gesamten Minuten. |
GetTotalSeconds |
Ermittelt die gesamten Sekunden. |
Das Erstellen eines CTime-Objekts für die aktuelle Uhrzeit ist sehr einfach und erfordert nur der Aufruf der Routine GetCurrentTime:
CTime time = CTime::GetCurrentTime();
Da GetCurrentTime eine statische Mitgliedsfunktion von CTime ist, können Sie sie aufrufen, ohne tatsächlich ein CTime-Objekt anlegen zu müssen. Sie müssen aber den Klassennamen als Teil des Aufrufes angeben, wie es im vorigen Beispiel gezeigt wird. Die Funktion liefert als Ergebnis ein CTime-Objekt. Dieses Objekt repräsentiert die aktuelle Uhrzeit. Um den Inhalt anzuzeigen können Sie die Funktion Format wie folgt benutzen:
CString str = time.Format("DATE: %A, %B %d, %Y");
Der einzige Parameter der Funktion Format ist die Formatierungszeichenkette, die der Funktion mitteilt, wie die Zeichenkette zusammengebaut werden soll. Die Zeichenkette des oben gezeigten Beispiels sieht in der Ausgabe so aus:
DATE: Saturday, April 20, 1996
Die Formatierungszeichenkette für die Funktion Format ist nicht unähnlich zu der Formatierungszeichenkette, wie sie zum Beispiel mit der alten DOS Routine printf oder der Windows-Konvertierungsfunktion wsprintf verwendet wird. Das Prinzip besteht darin, daß Sie festen Ausgabetext zusammen mit Steuerzeichen in dieser Zeichenkette anordnen. Ausgabetext ist in diesem Beispiel »DATE:«, sowie die Kommata. Sie werden genauso ausgegeben, wie sie in der Zeichenkette festgelegt werden. Die Steuerzeichen jedoch werden durch die entsprechenden Werte des Zeitobjekts ersetzt. Das Steuerzeichen %A im vorherigen Beispiel wird durch den Namen des Wochentags ersetzt und %B erhält den Namen des Monats. Obwohl das Konzept der Formatierungszeichenkette dem von printf entspricht, hat Format einen eigenen Satz an Steuerzeichen. Sie sehen sie in Tabelle E.7.
Tabelle E.7: Format-Codes für die Funktion Format (Forts.)
Code |
Beschreibung |
%a |
Name des Wochentags (abgekürzt, als z.B. Mon für Montag) |
%A |
Name des Wochentags (nicht abgekürzt) |
%b |
Name des Monats (abgekürzt, als z.B. Feb für Februar) |
%B |
Name des Monats (nicht abgekürzt) |
%c |
Lokalisierte Datums- und Zeitangabe (im deutschsprachigen Raum zum Beispiel 07.07.96 14:22:12) |
%d |
Tag des Monats als Zahl (01 û 31) |
%H |
Stunde im 24-Stunden-Format (00 û 23) |
%I |
Stunde im 12-Stunden-Format (01 û 12) |
%j |
Tag des Jahres als Zahl (001 û 366) |
%m |
Monat als Zahl (01 û 12) |
%M |
Minute als Zahl (00 û 59) |
%p |
lokalisierter A.M./P.M. Anzeiger beim 12-Stunden-Format der Uhrzeit |
%S |
Sekunden als Zahl (00 û 59) |
%U |
Woche des Jahres als Zahl (00 û 51, unter der Annahme, daß Sonntag der erste Tag der Woche ist) |
%w |
Wochentags als Zahl (0 û 6, wobei Sonntag den Wert 0 erhält) |
%W |
Woche des Jahres als Zahl (00 û 51, wobei Montag als erster Tag der Woche angenommen wird) |
%x |
Lokalisierte Datumsrepräsentation |
%X |
Lokalisierte Zeitrepräsentation |
%y |
Jahreszahl ohne Jahrhundert als Zahl (00 û 99) |
%Y |
Jahreszahl mit Jahrhundert als Zahl (wie zum Beispiel 1997) |
%z |
Name der Zeitzone (abgekürzt) |
%Z |
Name der Zeitzone (nicht abgekürzt) |
%% |
Prozentzeichen |
Die Verwendung anderer Mitgliedsfunktionen von CTime, wie zum Beispiel GetMinute, GetYear und GetMonth sind offensichtlich. Es ist aber vielleicht noch interessant, sich ein Beispiel für die Verwendung von GetLocalTM anzusehen:
struct tm* timeStruct;
timeStruct = time.GetLocalTm();
Die erste Zeile erzeugt einen Zeiger auf eine tm-Struktur (welche wie in Listing E.14 definiert ist). Die zweite Zeile setzt den Zeiger auf die tm-Struktur, die von der Funktion GetLocalTm erzeugt wurde.
Listing E.14: Die Struktur tm |
struct tm {
int tm_sec; /* seconds after the minute û [0,59] */
int tm_min; /* minutes after the hour û [0,59] */
int tm_hour; /* hours since midnight û [0,23] */
int tm_mday; /* day of the month û [1,31] */
int tm_mon; /* months since January û [0,11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday û [0,6] */
int tm_yday; /* days since January 1 û [0,365] */
int tm_isdst; /* daylight savings time flag */
};
Eine Zeitspanne ist nicht mehr, als die Differenz zwischen zwei Zeitpunkten. Sie können CTime-Objekte in Verbindung mit CTimeSpan verwenden, um auf einfache Weise die abgelaufene Zeit zwischen zwei absoluten Zeitpunkten zu ermitteln. Als erstes müssen Sie dazu ein Zeitobjekt mit der aktuellen Zeit anlegen. Wenn die zu messende Zeit abgelaufen ist, legen Sie ein zweites Zeitobjekt an, mit der dann aktuellen Zeit. Ziehen Sie die alte Zeit von der neuen Zeit ab, um ein Objekt vom Typ CTimeSpan zu erhalten. Dieses Objekt repräsentiert dann die verstrichene Zeit. Das Beispiel in Listing E.15 zeigt, wie das vonstatten geht.
Listing E.15: Berechnen einer Zeitspanne |
CTime startTime = CTime::GetCurrentTime();© 1997 Que
//.
//. warten, warten ...
//.
CTime endTime = CTime::GetCurrentTime();
CTimeSpan timeSpan = endTime û startTime;