1.2 Unser Dialog empfängt und verarbeitet Nachrichten
Nachdem wir jetzt ein "brauchbares" Dialog-Fenster vorliegen haben, wenden wir uns dem nächsten Schritt zu, nämlich der in Windows so wichtigen Nachrichtenverarbeitung. Schauen wir uns unsere Dialoganwendung aus Abb. 1.15 diesbezüglich genauer an. Worauf reagiert unser Fenster? Bisher reagiert unsere Anwendung für uns erkennbar nur auf das Anklicken der von uns hinzugefügten Fenster-Elemente wie z.B. MINIMIZEBOX, MAXIMIZEBOX, SYSMENU.
Klickt man in die von der hübschen Client-Kante eingerahmte graue Fläche, dann passiert nichts. Was müssen wir unternehmen, damit hier eine Aktion erfolgt? Zunächst müssen wir die Nachricht "linke Maustaste gedrückt" in unser Programm einbinden.
Dieser Nachricht (Message) müssen wir
anschließend
eine Member-Funktion zuordnen, die als Reaktion auf die Nachricht
ausgelöst
wird.
Zum Schluß müssen wir diese Funktion
mit Quellcode füllen, damit auch wirklich etwas passiert.
Bisher haben wir uns mit den Ressourcen beschäftigt. Nun wechseln wir im Arbeitsbereich zu den mittels MFC erstellten Klassen unserer Anwendung. Wir verwandeln alle "+" in "-", um den kompletten Klassen-Aufbau zu sehen:
Abb. 1.16: Klassenansicht der beiden
DialogEins-Klassen
Das Projekt umfaßt zwei Klassen: CDialogEinsApp und CDialogEinsDlg.
Die Klasse CDialogEinsApp besitzt zwei
Member-Funktionen
(Methoden):
den Konstruktor CDialogEinsApp() und
die Funktion InitInstance().
Die Klasse CDialogEinsDlg besitzt fünf
Member-Funktionen
und eine Member-Variable (Attribut):
den Konstruktor CDialogEinsDlg(...),
DoDataExchange(...),
OnInitDialog(),
OnPaint(),
OnQueryDragIcon() und
m_hIcon.
Die Klassenansicht zeigt symbolhaft den Zugriffsstatus auf Member-Variablen bzw. Member-Funktionen an:
Hinweis zur objektorientierten Programmierung (OOP): Klassen sind nichts anderes als
"Baupläne"
für Objekte. Der Zugriff auf Funktionen und
Variablen
wird bei deren Deklaration erledigt: Bei private kann nur von innerhalb
der Klasse
zugegriffen werden. |
Hier müssen wir in die richtige Klasse eine
Funktion zur Reaktion auf den Mausklick einfügen.
Wie machen wir das? Genau wie bei den Ressourcen
gibt es hier den sogenannten Klassen-Assistenten.
Wie ruft man diesen auf? Im Menü findet sich
ein Zauberstab. Wenn Sie den Pfeil rechts daneben anklicken,
öffnet sich folgendes Menü (Auch über
Strg
+ W erreichbar bzw. Ansicht /Klassen-Assistent):
Abb. 1.17: Der Klassen-Assistent bietet seine Hilfe an
Wählen Sie hier bitte "Behandlungsroutine für Windows-Nachrichten hinzufügen".
Abb. 1.18: Der Klassen-Assistent
bietet
eine Fülle von Nachrichten an
Wir wählen nun links unter "Neue
Windows-Nachrichten/-Ereignisse"
WM_LBUTTONDOWN
aus.
Dann drücken wir rechts auf "Behandlungsroutine
hinz(ufügen)". Der Assistent fügt die gewünschte
Nachricht
WM_LBUTTONDOWN zu den bereits vorhandenen Nachrichten WM_PAINT und
WM_INITDIALOG
(in der Mitte) hinzu. Damit haben wir unser Programm auf diese
Nachricht
vorbereitet.
Nun ordnen wir sofort eine Funktion zu. Da wir
die
Nachricht bereits hinzugefügt haben, drücken wir auf
"Vorhandene
bearbeiten" (hierbei muß WM_LBUTTONDOWN ausgewählt sein).
Jetzt
springt der Assistent direkt in die Funktion "CDialogEinsDlg::OnLButtonDown(UINT
nFlags, CPoint point)". Der Assistent hat diese Funktion angelegt. Ein
Blick nach links auf die Klassenansicht zeigt die neue Funktion in der
Klasse CDialogEinsDlg. Jetzt müssen wir nur noch etwas bewirken,
sprich
programmieren.
1.3 Textausgabe mit TextOut()
Geben Sie bitte nach der Kommentarzeile folgendes ein:
Abb. 1.19: Punkt hinter Objekten öffnet eine Auswahlliste für Funktionen und Datenelemente
Mit "CClientDC dc(this);" definieren wir
einen
sogenannten Gerätekontext (Device Context), der die
Rolle der Schnittstelle zwischen Programm und Bildschirmausgabe
übernimmt.
Das erzeugte Objekt dc (der Name ist frei wählbar) besitzt
eine große Menge von Funktionen (natürlich automatisch durch
MFC vorgegeben), die wir sofort einsehen können, sobald wir in der
zweiten Zeile den Punkt hinter dc eintippen.
Ein Listenfeld klappt auf, das uns eine breite
Auswahl
bietet (auch hier spürt man etwas vom "Visual" des MS VC++).
Wir wollen Text ausgeben und wählen daher
per
Doppelclick die Funktion "TextOut" aus.
Sobald wir anschließend eine öffnende
runde Klammer hinter TextOut eingeben, erhalten wir die nächste
Information:
Abb. 1.20: Eingabe der Klammer hinter Funktionsnamen öffnet eine Parameterliste
Sie sehen, VisualC++ läßt uns
nicht
im Stich, sondern stellt kontextbezogene Informationen zur
Verfügung.
Wir geben in dieser Zeile folgendes ein:
dc.TextOut( point.x, point.y, "linke Maustaste" ); |
Achten Sie bei der Eingabe von Programmcode bitte
auf alle Klammern, Kommas und Semikolons. Da ist C++
besonders
empfindsam.
Wir benützen als x- und y-Ausgabe für
den Text die von der Funktion übergebenen Mauskoordinaten, die in
point
als Elemente point.x und point.y enthalten sind. Wenn Sie alles richtig
gemacht haben, dann erhalten Sie nach dem Speichern und Kompilieren
eine
Anwendung, die auf das Niederdrücken der linken Maustaste im
sogenannten
Client-Bereich des Fensters wie folgt reagiert:
Abb. 1.21: Unser "Fenster" reagiert auf die Nachricht WM_LBUTTONDOWN mit einer Textausgabe
Dieses Beispiel demonstriert Ihnen, daß es
nicht schwierig ist, eigene Nachrichten-Behandlungs-Funktionen in eine
Klasse einzubauen.
In welche Klasse haben wir eigentlich unsere
Funktion
eingebaut?
Ein Blick in den Arbeitsbereich beantwortet diese
Frage sofort:
Abb. 1.22: Die Nachricht WM_LBUTTONDOWN startet die Funktion OnLButtonDown(...)
OnLButtonDown(...) ist eine
Funktion
der Klasse CDialogEinsDlg. Wenn Sie mehr über diese Klasse wissen
wollen,
führen Sie einfach einen Doppelklick
auf den Klassennamen CDialogEinsDlg aus.
Im rechten Fenster sehen wir daraufhin
die Header-Datei "DialogEinsDlg.h". Diese Datei enthält die
Definition
der Klasse CDialogEinsDlg,
die von der MFC-Klasse CDialog abgeleitet
wurde. CDialog ist wiederum abgeleitet von CWnd, der
MFC-Basisklasse
für Fenster.
Hinweis:
Die gesamte (Vererbungs-)Hierarchie sieht
wie folgt aus:
CObject
CCmdTarget
CWnd
CDialog
CDialogEinsDlg
Die Klasse CDialogEinsDlg enthält im Bereich "Generierte Message-Map-Funktionen" die Deklaration der von uns hinzugefügten Funktion OnLButtonDown(...). Der Assistent hat dies für uns hier eingefügt. In diesem Bereich wollen wir nichts ändern, da wir neue Datenelemente oder Funktionen nicht mit dem Texteditor, sondern mit dem Klassen-Assistenten eingeben wollen. Der Assistent kennzeichnet seine Bereiche durch seine graue Handschrift, die er mit (grünen) AFX...-Kommentaren eingrenzt. Das ist für uns im Normalfall Sperrgebiet, obwohl der Assistent uns bereitwillig zu all den Stätten seines Wirkens führt. Man vertraut uns eben.
Das Fenster mit all seinen Ausstattungen ist bis zum Schließen der Anwendung stabil. Wenn man das Fenster mit der Maus z.B. teilweise über den Bildschirmrand hinaus schiebt und dann wieder zurück zieht, dann gehen keine Details oder Funktionen verloren. Auch nach dem Minimieren (Ablegen) und Wiederaufrufen besitzt das Fenster noch all seine Details (Rahmen, Titel, Buttons, Farbe). Anders ist dies mit dem von uns erzeugten Text. Dieser ist nicht stabil gespeichert, sondern vergänglich. Schieben Sie nach einigen Mausklicks (über das gesamte Fenster verteilt) das Fenster zur Hälfte über den Bildschirmrand hinaus. Nach dem Zurückziehen könnte Ihr Fenster dann wie folgt aussehen:
Abb. 1.23: Der in OnLButtonDown(...) ausgegebene Text ist vergänglich.
Unser Gerätekontext leitet seine Ausgaben
direkt
an das Fenster. Nach dem Verschwinden dieser Informationen können
diese beim Wiederaufbau des Fensters nicht mehr berücksichtigt
werden.