In den meisten Anwendungen gibt es zahlreiche Situationen, wo die Anwendung Informationen vom Benutzer anfordert, beispielsweise wie man die Anwendung konfigurieren möchte oder ob ein Dokument vor dem Verlassen der Anwendung zu speichern ist. In den meisten derartigen Fällen öffnet die Anwendung ein neues Fenster, um die entsprechenden Fragen zu stellen. Man bezeichnet diese Fenster als Dialogfelder.
Dialogfelder enthalten in der Regel ein oder mehrere Steuerelemente und erklären mit etwas Text, welche Informationen die Anwendung vom Benutzer erwartet. In Dialogfeldern ist normalerweise kein größerer leerer Arbeitsbereich vorgesehen, wie er etwa in den Hauptfenstern von Textverarbeitungen oder Programmeditoren zu finden ist. Alle in den vergangenen Tagen erstellten Anwendungen waren als Dialogfelder konzipiert, was sich auch in den unmittelbar folgenden Lektionen nicht ändert.
Die bisher erstellten Dialogfelder waren durchweg Anwendungen mit einem einzigen Dialogfenster. Heute lernen Sie, wie man ...
Das Betriebssystem Windows stellt eine Reihe von vordefinierten Dialogfeldern bereit. Einfache Dialogfelder, die sogenannten Meldungsfelder, präsentieren dem Benutzer eine Nachricht und enthalten eine bis drei Schaltflächen, über die der Benutzer seine Reaktion an die Anwendung übermitteln kann. Komplexere Dialogfelder, wie etwa die Dialogfelder Öffnen, Speichern unter oder Drucken, werden ebenfalls durch Windows bereitgestellt. Diese System- (oder allgemeinen) Dialogfelder werden zusammen mit einer Kombination aus einer Variablendeklaration einer C++-Klasse und einer Reihe von Interaktionen mit der Klasseninstanz erzeugt und verwendet.
In den vergangenen Tagen haben Sie bereits erfahren, daß sich Meldungsfelder sehr einfach einsetzen lassen: Man ruft einfach eine Funktion auf und übergibt den Meldungstext als einziges Argument. Es erscheint ein Meldungsfeld mit einem Symbol und dem Meldungstext sowie einer Schaltfläche, die der Benutzer anklickt, wenn er die Meldung zur Kenntnis genommen hat. Aus anderen Windows-Anwendungen ist Ihnen sicherlich bekannt, daß es eine ganze Palette von Meldungsfeldern mit verschiedenartigen Kombinationen von Schaltflächen und Symbolen gibt.
Wie Sie bereits aus den letzten Tagen wissen, kann die Funktion MessageBox
ein oder
zwei Argumente übernehmen. Das erste Argument ist die für den Benutzer anzuzeigende
Meldung, während der Wert des optionalen zweiten Arguments in der Titelleiste
des Meldungsfelds erscheint. Mit einem ebenfalls optionalen dritten Argument lassen
sich die Schaltflächen, die der Benutzer wählen kann, und das in der Meldung
anzuzeigende Symbol festlegen. Zusätzlich zu diesen drei Argumenten liefert die Funktion
MessageBox
einen Ergebniswert zurück, der die vom Benutzer angeklickte Schaltfläche
kennzeichnet. Über die Kombination von drittem Argument und Rückgabewert
kann man in Visual C++-Anwendungen mit der Funktion MessageBox
ein breites
Funktionsspektrum realisieren.
Bezüglich der Kombination von Schaltflächen, die im Meldungsfeld erscheinen, sind
Ihnen enge Grenzen gesetzt. Eigene Schaltflächenkombinationen lassen sich nicht
festlegen. Sollten Sie mit den vordefinierten Schaltflächen oder den zulässigen Kombinationen
nicht auskommen, bleibt Ihnen nichts anderes übrig, als ein benutzerdefiniertes
Dialogfeld zu erstellen, das dem gewünschten Meldungsfeld entspricht. Tabelle 5.1
listet die verfügbaren Kombinationen von Schaltflächen auf, die man in der Funktion
MessageBox
spezifizieren kann.
Um das anzuzeigende Symbol festzulegen, addiert man die ID des Symbols zur ID der Schaltflächenkombination. Die verfügbaren Symbole sind in Tabelle 5.2 aufgeführt. Möchten Sie nur das Symbol oder nur die Schaltflächenkombination festlegen und für das jeweils andere Element den Standardwert übernehmen, geben Sie einfach nur die gewünschte ID an.
Wenn man eine Schaltflächenkombination angibt, liegt es nahe, auch den Rückgabewert zu verwenden, damit man ermitteln kann, auf welche Schaltfläche der Benutzer geklickt hat. Der Rückgabewert ist als Integer-Wert definiert. Die verfügbaren Werte sind in Tabelle 5.3 aufgelistet.
Damit Sie kennenlernen, wie man in einer Anwendung mit der Funktion MessageBox
vom Benutzer Informationen einholt, erstellen Sie eine einfache Beispielanwendung,
in der die Funktion MessageBox
in verschiedenen Varianten zum Einsatz kommt. Die
Anwendung verfügt über zwei separate Schaltflächen, über die sich zwei verschiedene
Versionen der Funktion MessageBox
aufrufen lassen, damit Sie die Unterschiede und
Gemeinsamkeiten der verschiedenen Optionen der Funktion studieren können. Weiter
hinten in der heutigen Lektion fügen Sie der Anwendung das Standarddialogfeld
Öffnen hinzu. Dieses Beispiel zeigt, wie der Benutzer einen Dateinamen festlegen
oder eine andere der vordefinierten Funktionen ausführen kann. Schließlich erzeugen
Sie ein benutzerdefiniertes Dialogfeld, in das der Benutzer verschiedene Arten von
Werten eingeben kann. In diesem Beispiel sehen Sie, wie man die vom Benutzer in
das Hauptdialogfeld der Anwendung eingegebenen Werte lesen kann, nachdem der
Benutzer das benutzerdefinierte Dialogfeld geschlossen hat.
Den ersten Teil der Anwendung erstellen Sie mit folgenden Schritten:
1. Legen Sie mit dem MFC-Anwendungs-Assistenten einen neuen Projektarbeitsbereich
an, und nennen Sie das Projekt Dialoge
.
2. Wählen Sie die gleichen Einstellungen wie in den Anwendungen der letzten Lektionen.
Als Titel der Anwendung legen Sie Dialoge
fest.
3. Gestalten Sie das Hauptdialogfeld der Anwendung entsprechend Abbildung 5.1, und legen Sie die Eigenschaften gemäß Tabelle 5.4 fest.
Abbildung 5.1:
Das Layout des Hauptdialogfelds der Anwendung
4. Verbinden Sie mit Hilfe des Klassen-Assistenten die Variablen mit den in Tabelle 5.5 aufgeführten Steuerelementen.
5. Weisen Sie wie an den vorherigen Tagen mit Hilfe des Klassen-Assistenten Code an die Schaltfläche Beenden zu, um die Anwendung zu schließen.
Erstellen Sie mit dem Klassen-Assistenten für die erste Schaltfläche (diejenige mit der Beschriftung Ja, Nein, Abbrechen) eine Funktion für das Klickereignis, wie Sie es von den vergangenen Tagen her kennen. Nehmen Sie in die Funktion für diese Schaltfläche den Code von Listing 5.1 auf.
Listing 5.1: Die Funktion OnYesnocancel
1: void CDialogeDlg::OnYesnocancel()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: int iResults; // Variable für Schaltflächenauswahl
10:
11: // Benutzer fragen
12: iResults = MessageBox("Ja, Nein oder Abbrechen drücken",
13: "Dialogfeld Ja, Nein, Abbrechen",
14: MB_YESNOCANCEL | MB_ICONINFORMATION);
15:
16: // Angeklickte Schaltfläche ermitteln
17: // Benutzer die angeklickte Schaltfläche melden
18: switch (iResults)
19: {
20: case IDYES: // Schaltfläche Ja?
21: m_sResults = "Ja! Ja! Ja!";
22: break;
23: case IDNO: // Schaltfläche Nein?
24: m_sResults = "Nein, nein, nein, nein, nein.";
25: break;
26: case IDCANCEL: // Schaltfläche Abbrechen?
27: m_sResults = "Sorry, abgebrochen.";
28: break;
29: }
30:
31: // Dialogfeld aktualisieren
32: UpdateData(FALSE);
33:
34: ///////////////////////
35: // EIGENER CODE, ENDE
36: ///////////////////////
37: }
Wenn Sie die Anwendung kompilieren und ausführen, können Sie verfolgen, wie sich
durch Wahl der verschiedenen Schaltflächen im Meldungsfeld der Ablauf der Aktionen
in der Anwendung bestimmen läßt. Nehmen Sie mit dem Klassen-Assistenten eine
Funktion für die Klickereignisse der Schaltfläche Beenden, Wiederholen, Ignorieren
auf, und geben Sie den gleichen Code wie in Listing 5.1 ein. Jetzt verwenden Sie jedoch
die Werte MB_ABORTRETRYIGNORE
und MB_ICONQUESTION
und ändern die Aufforderungen
und Meldungen. Sie können sich nun davon überzeugen, wie sich diese andere
Schaltflächenkombination in der gleichen Weise verwenden läßt.
Die Behandlungsroutinen für die Nachrichten der beiden Steuerelemente sind praktisch
gleich. In jeder Funktion nimmt die deklarierte Integer-Variable den Rückgabewert
der Funktion MessageBox
auf. Als nächstes wird die Funktion MessageBox
mit einer
anzuzeigenden Meldung, einem Titel für das Meldungsfeld und einer Kombination
von Schaltflächen-ID und Symbol-ID aufgerufen.
Nachdem man den Rückgabewert der Funktion MessageBox
in der Variablen gesichert
hat, wird dieser Wert in einer switch
-Anweisung ausgewertet, um die gedrückte
Schaltfläche zu bestimmen. Eine Nachricht weist den Benutzer darauf hin, welche
Schaltfläche er im Meldungsfeld angeklickt hat. Die vom Benutzer gewählte Schaltfläche
ließe sich auch leicht mit einer oder zwei if
-Anweisungen auswerten, um die Programmausführung
zu steuern, da aber der Rückgabewert ganzzahlig ist, bietet sich
eine switch
-Anweisung wie von selbst an.
Wenn Sie die Anwendung jetzt kompilieren und ausführen, können Sie auf die beiden oberen Schaltflächen klicken und eine Meldung wie in Abbildung 5.2 sehen. Nachdem Sie auf eine der Schaltflächen des Meldungsfelds geklickt haben, erscheint im Eingabefeld des Hauptdialogfelds eine Meldung, die auf die gewählte Schaltfläche hinweist (siehe Abbildung 5.3).
Abbildung 5.2:
Das Meldungsfeld mit drei Auswahlen
Abbildung 5.3:
Je nach angeklickter Schaltfläche wird eine Meldung angezeigt.
Standarddialogfelder lassen sich nicht so einfach einsetzen wie die Funktion MessageBox
, trotzdem bleibt alles noch überschaubar. Die Microsoft Foundation Classes (MFC)
bieten mehrere C++-Klassen für Windows-Standarddialogfelder. Tabelle 5.6 bringt
eine Übersicht zu diesen Klassen.
Den in diesen Klassen verkapselten Standarddialogfeldern begegnen Sie auf Schritt und Tritt in den meisten Windows-Anwendungen, wenn Sie zum Beispiel Dateien öffnen, Druckeroptionen einstellen, drucken oder Begriffe suchen und ersetzen wollen. Neben diesen Auswahlen bieten verschiedene OLE-Standarddialogklassen mehrere Standardfunktionen für OLE- oder ActiveX-Komponenten und Anwendungen.
Alle derartigen Dialogfelder setzt man in der gleichen Weise ein, auch wenn einzelne Eigenschaften und Klassenfunktionen je nach der Funktionalität des Dialogfelds variieren können. Um ein Standarddialogfeld zu verwenden, führen Sie folgende Schritte aus:
1. Deklarieren Sie eine Variable des Klassentyps.
2. Legen Sie alle erforderlichen Eigenschaften fest, bevor Sie das Dialogfeld dem Benutzer anzeigen.
3. Rufen Sie die Methode DoModal
der Klasse auf, um das Dialogfeld anzuzeigen.
4. Übernehmen Sie den Rückgabewert der Methode DoModal
, um zu ermitteln, ob
der Benutzer auf OK oder Abbrechen geklickt hat.
5. Wenn der Benutzer auf die Schaltfläche OK geklickt hat, lesen Sie alle Eigenschaften, die der Benutzer eventuell im Dialogfeld gesetzt oder geändert hat.
Um die Funktionsweise besser verstehen zu können, fügen Sie der Beispielanwendung
die Klasse CFileDialog
hinzu. Nehmen Sie dazu eine Funktion für das Klickereignis
der Schaltfläche Datei öffnen mit Hilfe des Klassen-Assistenten auf. Schreiben Sie in
diese Funktion den Code aus Listing 5.2.
Listing 5.2: Die Funktion OnFileopen
1: void CDialogeDlg::OnFileopen()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: CFileDialog m_ldFile(TRUE);
10:
11: // Dialogfeld Öffnen zeigen und Ergebnis auffangen
12: if (m_ldFile.DoModal() == IDOK)
13: {
14: // Gewählten Dateinamen ermitteln
15: m_sResults = m_ldFile.GetFileName();
16: // Dialogfeld aktualisieren
17: UpdateData(FALSE);
18: }
19:
20: ///////////////////////
21: // EIGENER CODE, ENDE
22: ///////////////////////
23: }
Diese Funktion deklariert zuerst eine Instanz der Klasse CFileDialog
. Dieser Instanz
wird TRUE
als Argument an den Klassenkonstruktor übergeben. Der Klasse ist damit
bekannt, daß es sich um ein Dialogfeld Datei öffnen handelt. Bei Übergabe von FALSE
erscheint ein Dialogfeld Speichern unter. Zwischen beiden Dialogfeldern gibt es keinen
funktionellen, sondern nur einen visuellen Unterschied. An den Konstruktor können
Sie noch weitere Argumente übergeben und damit die anzuzeigenden Dateierweiterungen,
eine Startdatei und deren Standort sowie Filter zur Anzeige ausgewählter
Dateien festlegen.
Nachdem Sie die Instanz des Dialogfelds Öffnen erzeugt haben, können Sie deren
Funktion DoModal
aufrufen. Es handelt sich dabei um eine Member-Funktion der Basisklasse
CDialog
. Diese Funktion ist in allen Dialogfenstern verfügbar. Die Funktion
DoModal
zeigt das Dialogfeld Öffnen wie in Abbildung 5.4 dargestellt an. Aus dem
Rückgabewert der Funktion DoModal
läßt sich ableiten, auf welche Schaltfläche der
Benutzer geklickt hat. Die Wahl der Schaltfläche Öffnen liefert den Wert IDOK
zurück,
genau wie bei der Funktion MessageBox
. Je nach Benutzerauswahl können Sie nun
anhand des Rückgabewerts festlegen, wie das Programm fortzusetzen ist.
Abbildung 5.4:
Das Dialogfeld Öffnen
Um den Namen der ausgewählten Datei anzuzeigen, setzen Sie die Variable
m_sResults
auf den Rückgabewert der Methode GetFileName
der Klasse CFileDialog
. Diese Methode liefert lediglich den Dateinamen ohne Verzeichnispfad oder Laufwerksbezeichnung,
wie es Abbildung 5.5 verdeutlicht. Mit anderen Methoden der
Klasse kann man auch den Verzeichnispfad (GetPathName
) und die Dateierweiterung
(GetFileExt
) ermitteln.
Abbildung 5.5:
Den ausgewählten Dateinamen anzeigen
Mit Standarddialogfeldern können Sie nun umgehen. Was aber, wenn Sie ein benutzerdefiniertes Dialogfeld für Ihre Anwendung brauchen? Diese Aufgabe ist ziemlich einfach zu lösen, da es sich im wesentlichen um eine Kombination der Schritte handelt, die Sie bereits vom Erstellen des Hauptdialogfelds der Beispielanwendungen und dem Einsatz von Standarddialogfeldern her kennen. Es sind zwar ein paar zusätzliche Schritte erforderlich, die Ihnen aber bald geläufig sein dürften.
Das benutzerdefinierte Dialogfeld für die Beispielanwendung stellt dem Benutzer ein Eingabefeld bereit, in das er Text eingeben, sowie ein Gruppe von Optionsfeldern, aus denen der Benutzer eine Option auswählen kann. Wenn der Benutzer auf die Schaltfläche OK klickt, zeigt die Anwendung den vom Benutzer eingegebenen Text im Anzeigebereich des Hauptdialogfelds der Anwendung an. Über eine weitere Schaltfläche kann sich der Benutzer anzeigen lassen, welches der Optionsfelder ausgewählt ist. Diese Übung zeigt, wie man mit benutzerdefinierten Dialogfeldern Informationen vom Benutzer einholt und wie man die vom Benutzer getroffenen Auswahlen auswertet, nachdem das Dialogfeld geschlossen wird.
Um ein benutzerdefiniertes Dialogfeld für die Anwendung zu erstellen, sind folgende Aufgaben zu erledigen:
Danach können Sie das benutzerdefinierte Dialogfeld in Ihrer Anwendung einsetzen. Die genannten Aufgaben führen Sie in folgenden Schritten aus:
1. Gehen Sie im Arbeitsbereich auf die Registerkarte Ressourcen.
2. Klicken Sie mit der rechten Maustaste auf den Ordner Dialog, und wählen Sie aus dem Kontextmenü den Befehl Dialog einfügen.
3. Klicken Sie mit der rechten Maustaste auf das neue Dialogfeld in der Baumansicht der Ressourcen, und wählen Sie aus dem Kontextmenü den Befehl Eigenschaften .
4. Ändern Sie die Objekt-ID für das neue Dialogfeld in IDD_MESSAGEDLG
.
5. Wenn Sie das neue Dialogfeld bearbeiten, behalten Sie die Schaltflächen OK und Abbrechen bei. Verschieben Sie sie aber auf eine andere Position, wie es Abbildung 5.6 zeigt.
Abbildung 5.6:
Das Layout des benutzerdefinierten Dialogfelds
6. Nehmen Sie den Entwurf für das restliche Dialogfeld vor, und richten Sie die Objekteigenschaften gemäß Tabelle 5.7 ein.
7. Wenn Sie den Entwurf des Dialogfelds abgeschlossen haben, öffnen Sie den Klassen-Assistenten. Es erscheint das Dialogfeld gemäß Abbildung 5.7.
Abbildung 5.7:
Das Dialogfeld Hinzufügen einer Klasse
8. Übernehmen Sie in diesem Dialogfeld die vorgegebene Option Neue Klasse erstellen , und klicken Sie auf OK. Es erscheint ein weiteres Dialogfeld, in dem Sie den Namen für die neue Klasse spezifizieren und die Basisklasse, von dem die neue Klasse abzuleiten ist, festlegen können.
9. Tragen Sie in das Feld Name die Bezeichnung CMsgDlg
ein, und vergewissern Sie
sich, daß im Listenfeld Basisklasse der Eintrag CDialog
ausgewählt ist (siehe Abbildung
5.8).
Abbildung 5.8:
Das Dialogfeld Neue Klasse
10. Lassen Sie die anderen Einstellungen im Dialogfeld unverändert, und klicken Sie auf OK.
11. Nachdem Sie wieder zum Klassen-Assistenten zurückgekehrt sind, weisen Sie den Steuerelementen im neuen Dialogfeld die Variablen entsprechend Tabelle 5.8 zu.
Zwei Dinge sind zu beachten, wenn Sie die Steuerelementeigenschaften und Variablen im benutzerdefinierten Dialogfeld konfigurieren. Erstens sollten Sie nur für das erste Optionsfeld die Eigenschaft Gruppe einschalten. Damit wird gekennzeichnet, daß alle sich anschließenden Optionsfelder zu einer einzigen Gruppe gehören, in der nur ein Optionsfeld zu einem bestimmten Zeitpunkt ausgewählt sein kann. Wenn Sie die Eigenschaft Gruppe für alle Optionsfelder einschalten, sind die Optionsfelder voneinander unabhängig, so daß man mehrere Optionen gleichzeitig auswählen kann. Damit entspricht das Verhalten der Optionsfelder dem von Kontrollkästchen, wobei der Hauptunterschied darin besteht, daß der Benutzer die Optionen nicht wieder ausschalten kann. Das widerspricht dem Standardverhalten, daß immer nur eine Option markiert ist. Der andere Unterschied bezieht sich auf das Erscheinungsbild. Optionsfelder weisen runde Auswahlbereiche auf, während Kontrollkästchen quadratisch sind.
Als nächstes fällt auf, daß nur eine einzige Integer-Variable für die Optionsfelder deklariert wurde, und zwar für das Optionsfeld, für das die Eigenschaft Gruppe eingeschaltet ist. Der Wert dieser Variablen hängt davon ab, welches Optionsfeld ausgewählt ist. Handelt es sich um das erste Optionsfeld, hat die Variable den Wert 0, beim zweiten Optionsfeld den Wert 1 usw. Umgekehrt können Sie bestimmen, welches Optionsfeld ausgewählt sein soll, indem Sie den Wert der Variablen festlegen (auf die Nummer des Optionsfelds in der Gruppe minus 1).
Es sind nun alle Arbeiten abgeschlossen, um das Dialogfeld in der Anwendung einzusetzen.
Vielleicht erwarten Sie, daß die Funktion UpdateData
im Code für das Dialogfeld
aufzurufen ist. Da Sie aber die Schaltflächen OK und Abbrechen nicht aus dem
Dialogfeld entfernt haben, findet der Aufruf von UpdateData
automatisch statt, sobald
der Benutzer auf OK klickt. Damit brauchen Sie für das zweite Dialogfeld überhaupt
keinen Code zu verfassen, sondern nur für das erste.
Nachdem Sie Ihr benutzerdefiniertes Dialogfeld fertiggestellt haben, können Sie es genauso
einsetzen, wie die zu Windows gehörenden Standarddialogfelder. Zuerst müssen
Sie eine Instanz der benutzerdefinierten Dialogfeldklasse deklarieren, die den Konstruktor
der Klasse aufruft und eine Instanz der Klasse erzeugt. Als nächstes rufen Sie
die Methode DoModal
des Dialogfelds auf und speichern den Rückgabewert der Funktion
in einer Variablen. Schließlich werten Sie die Variablen, die Sie den Steuerelementen
des Dialogfelds zugeordnet haben, aus.
Bevor Sie das benutzerdefinierte Dialogfeld in der Anwendung nutzen können, müssen Sie dem Hauptdialogfeld der Anwendung das benutzerdefinierte Dialogfeld sowie dessen Variablen und Methoden bekanntmachen und festlegen, wie das Hauptdialogfeld mit dem benutzerdefinierten Dialogfeld in Wechselwirkung treten kann. Das läßt sich erreichen, indem Sie die Header-Datei für das benutzerdefinierte Dialogfeld in die Quelldatei für das Hauptdialogfeld der Anwendung einbinden. Führen Sie die folgenden Schritte aus:
1. Gehen Sie im Arbeitsbereich auf die Registerkarte Dateien.
2. Erweitern Sie die Ordner Dialoge Dateien
und danach Quellcodedateien
.
3. Doppelklicken Sie auf die Datei DialogeDlg.cpp
. Daraufhin erscheint der Quellcode
für das Hauptdialogfeld der Anwendung im Bearbeitungsbereich des Visual
Studios.
4. Gehen Sie an den Beginn des Quellcodes, wo sich die #include
-Anweisungen befinden,
und fügen Sie eine #include
-Anweisung für die Datei MsgDlg.h
vor die
Datei DialogeDlg.h
ein, wie es Listing 5.3 zeigt.
Listing 5.3: Die eingebundenen Header-Dateien
1: // DialogeDlg.cpp : Implementierungsdatei
2: //
3:
4: #include "stdafx.h"
5: #include "Dialoge.h"
6: #include "MsgDlg.h"
7: #include "DialogeDlg.h"
8:
9: #ifdef _DEBUG
10: #define new DEBUG_NEW
11: #undef THIS_FILE
12: static char THIS_FILE[] = __FILE__;
13: #endif
14:
15: /////////////////////////////////////////////////////////////////////////////
16: // CAboutDlg-Dialogfeld für Anwendungsbefehl "Info"
Die #include
-Anweisung für die Datei MsgDlg.h
muß vor der #include
-Anweisung für
die Datei DialogeDlg.h
stehen, weil Sie eine Variablendeklaration für das benutzerdefinierte
Dialogfeld in die Klasse des Hauptdialogfelds in der Header-Datei des Hauptdialogfelds
aufnehmen. Wenn Sie die Header-Datei MsgDlg.h
nach der Header-Datei
für das Hauptdialogfeld einbinden, beschwert sich der Compiler und weigert sich, Ihre
Anwendung zu kompilieren, bis Sie die #include
-Anweisung der Datei MsgDlg.h
über
die #include
-Anweisung der Datei DialogeDlg.h
verschieben.
Nachdem Sie nun dem Hauptdialogfeld der Anwendung das benutzerdefinierte Dialogfeld bekanntgemacht haben, müssen Sie eine Variable Ihres benutzerdefinierten Dialogfelds deklarieren. Führen Sie dazu folgende Schritte aus:
1. Gehen Sie im Arbeitsbereich auf die Registerkarte Klassen.
2. Klicken Sie mit der rechten Maustaste auf die Klasse CDialogeDlg
, um das Kontextmenü
zu öffnen.
3. Wählen Sie aus dem Kontextmenü den Befehl Member-Variable hinzufügen.
4. Im Dialogfeld Member-Variable hinzufügen legen Sie den Variablentyp mit CMsgDlg
, den Variablennamen mit m_dMsgDlg
und den Zugriffsstatus als Privat fest.
Klicken Sie auf OK, um die Variable in Ihr Hauptdialogfeld aufzunehmen.
Wenn Sie die Klasse CDialogeDlg
in der Baumansicht erweitern, ist die Instanz des
benutzerdefinierten Dialogfelds als Element der Hauptdialogfeldklasse der Anwendung
zu sehen. Das bedeutet, daß Sie nun das benutzerdefinierte Dialogfeld in Ihrer Anwendung
nutzen können.
Sie haben nun das benutzerdefinierte Dialogfeld in das Hauptdialogfeld der Anwendung
aufgenommen, und zwar als Variable, die immer verfügbar ist, und nicht einfach
als lokale Variable, die nur innerhalb einer einzigen Funktion gültig ist (wie bei der Variablen
CFileDialog
). Jetzt können Sie den Code hinzufügen, um das Dialogfeld tatsächlich
zu nutzen. Führen Sie dazu die folgenden Schritte aus:
1. Öffnen Sie den Klassen-Assistenten, und fügen Sie eine Funktion für das Klickereignis
(BN_CLICKED
) der Schaltfläche IDC_BCUSTOMDIALOG
hinzu.
2. Fügen Sie eine Funktion für das Klickereignis der Schaltfläche IDC_BWHICHOPTION
hinzu.
3. Übernehmen Sie in die Funktion OnBcustomdialog
den Code aus Listing 5.4.
Listing 5.4: Die Funktion OnBcustomdialog
1: void CDialogeDlg::OnBcustomdialog()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Meldungsdialog anzeigen und Ergebnis auffangen
10: if (m_dMsgDlg.DoModal () == IDOK)
11: {
12: // OK gewählt. Nachricht anzeigen, die Benutzer
13: // in Nachrichtendialog eingegeben hat
14: m_sResults = m_dMsgDlg.m_sMessage;
15: // Dialogfeld aktualisieren
16: UpdateData(FALSE);
17: // Schaltfläche Welche Option aktivieren
18: m_cWhichOption.EnableWindow(TRUE);
19: }
20:
21: ///////////////////////
22: // EIGENER CODE, ENDE
23: ///////////////////////
24: }
4. Übernehmen Sie in die Funktion OnBwhichoption
den Code aus Listing 5.5.
Listing 5.5: Die Funktion OnBwhichoption
1: void CDialogeDlg::OnBwhichoption()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Gewähltes Optionsfeld ermitteln und mit einer
10: // Meldung die gewählte Option anzeigen.
11: switch(m_dMsgDlg.m_iOption)
12: {
13: case 0: // Erstes Optionsfeld gewählt?
14: m_sResults = "Die erste Option wurde gewählt.";
15: break;
16: case 1: // Zweites Optionsfeld gewählt?
17: m_sResults = "Die zweite Option wurde gewählt.";
18: break;
19: case 2: // Drittes Optionsfeld gewählt?
20: m_sResults = "Die dritte Option wurde gewählt.";
21: break;
22: case 3: // Viertes Optionsfeld gewählt?
23: m_sResults = "Die vierte Option wurde gewählt.";
24: break;
25: default: // Keine Optionsfelder ausgewählt?
26: m_sResults = "Es wurde keine Option gewählt.";
27: break;
28: }
29:
30: // Dialogfeld aktualisieren
31: UpdateData(FALSE);
32:
33: ///////////////////////
34: // EIGENER CODE, ENDE
35: ///////////////////////
36: }
Der Code im ersten Listing ruft die Methode DoModal
des benutzerdefinierten Dialogfelds
auf. Diese Methode zeigt das Dialogfeld an und wartet darauf, daß der Benutzer
auf eine der beiden Schaltflächen im Dialogfeld klickt, wie es Abbildung 5.9 zeigt.
Wählt der Benutzer die Schaltfläche OK, kopieren Sie die vom Benutzer in das benutzerdefinierte
Dialogfeld eingegebene Nachricht in die Variable des Eingabefelds, das
die Nachricht für den Benutzer anzeigen soll. Nach der Aktualisierung der Dialogfeldanzeige
mit den neuen Variablenwerten, aktivieren Sie die Schaltfläche Welche Option
wie in Abbildung 5.10. Entscheidet sich der Benutzer für die Schaltfläche Abbrechen,
brauchen Sie gar nichts zu unternehmen. Die Dialogfeldanzeige ändert sich
nicht.
Abbildung 5.9:
Im benutzerdefinierten Dialogfeld kann der Benutzer eine Nachricht eintippen.
Abbildung 5.10:
Die im benutzerdefinierten Dialogfeld eingegebene Nachricht wird dem Benutzer angezeigt.
Wenn der Benutzer auf die Schaltfläche Welche Option klickt, übergeben Sie Variable
des Optionsfelds im benutzerdefinierten Dialogfeld an eine switch
-Anweisung, um
eine Meldung auszuwählen, die dem Benutzer das gewählte Optionsfeld anzeigt (siehe
Abbildung 5.11). Beachten Sie, daß man in beiden Funktionen direkt auf die Variablen
der Steuerelemente im benutzerdefinierten Dialogfeld vom Hauptdialogfeld aus
zugreifen kann. Das ist darauf zurückzuführen, daß der Klassen-Assistent automatisch
die mit den Steuerelementen verbundenen Variablen als Public deklariert und sie somit
für einen Zugriff von außerhalb der Dialogfeldklasse zugänglich macht. Dieses Verhalten
können Sie ändern, indem Sie den Zugriffsspezifizierer public:
durch private
:
ersetzen. Nach der Zeile //{{AFX_DATA
, wo die Deklaration der Variablen steht,
dürfen Sie keine Änderungen vornehmen, da die Variablen in einem Makro des MFC-
Klassen-Assistenten deklariert werden. Damit können die Assistenten des Visual Studio
ohne Mitwirkung des Visual C++-Compilers bei Bedarf die Variablen lokalisieren
und manipulieren, wenn Sie Ihre Anwendung kompilieren.
Abbildung 5.11:
Die im benutzerdefinierten Dialogfeld gewählte Option wird dem Benutzer angezeigt.
Heute haben Sie gelernt, wie man zusätzliche Dialogfelder in eine Anwendung einbaut,
um die Interaktion des Benutzers mit der Anwendung zu ermöglichen. Es wurde
gezeigt, welche Optionen für die einfache MessageBox
-Funktion verfügbar sind, wie
man dem Benutzer verschiedene Schaltflächenkombinationen anbietet und wie man
die vom Benutzer getroffene Auswahl bestimmt. Anhand dieser Informationen läßt
sich der weitere Ablauf eines Programms festlegen.
Im nächsten Thema ging es um Standarddialogfelder, die in das Betriebssystem Windows integriert sind. Es wurde dargestellt, wie diese Standarddialoge in C++-Klassen der MFC-Klassenbibliothek verkapselt sind. Sie haben gelernt, wie man dem Benutzer die Auswahl von Dateien mit dem Standarddialogfeld Öffnen ermöglicht und wie man ermitteln kann, welche Datei der Benutzer ausgewählt hat.
Schließlich haben Sie erfahren, wie man eigene Dialogfelder entwirft und sie in eine Anwendung einbaut, um Informationen vom Benutzer einzuholen und diese Informationen in der Anwendung auszuwerten.
Frage:
Für das benutzerdefinierte Dialogfeld wurde kein Code geschrieben. Muß ich meine
benutzerdefinierten Dialogfelder immer auf diese Weise erstellen, oder kann
ich für die Dialogfelder Code vorsehen?
Antwort:
Die benutzerdefinierten Dialogfelder unterscheiden sich nicht von den Hauptdialogfeldern,
die Sie in den bisherigen Anwendungen eingesetzt haben.
Wenn Sie das Verhalten des Dialogfelds interaktiv beeinflussen möchten,
können Sie soviel Code hinzufügen wie Sie wollen. Im benutzerdefinierten
Dialogfeld der heutigen Beispielanwendung war kein Code zu schreiben, da er
einfach nicht erforderlich war. Das Dialogfeld hatte lediglich die Funktion UpdateData
aufzurufen, was aber die Funktion OnOK automatisch beim Schließen
des Dialogfelds übernimmt. Da Sie weder die Schaltfläche OK noch die
Schaltfläche Abbrechen aus dem Dialogfeld gelöscht haben, ist diese Funktionalität
bereits vorhanden.
Frage:
Was passiert, wenn ich zwei oder mehr Schaltflächenkombinationen im selben
Aufruf der Funktion MessageBox
angebe?
Antwort:
Nichts. Die Anwendung läßt sich problemlos kompilieren, aber beim Aufruf
der Funktion MessageBox ereignet sich überhaupt nichts. Das Meldungsfeld
wird nicht geöffnet, und der Benutzer hat gar keine Chance, auf die eigentlich
vorgesehenen Fragen zu antworten.
Frage:
Wie kann ich das Dialogfeld Öffnen in meine Anwendung einbauen, so daß es
bereits mit einem vorgegebenen Verzeichnis geöffnet wird?
Antwort:
Die Klasse CFileDialog verfügt über eine öffentliche (public) Eigenschaft namens
m_ofn. Diese Eigenschaft ist als Struktur realisiert, die mehrere Attribute
des Dialogfelds Öffnen enthält. Dazu gehört auch das anfänglich angezeigte
Verzeichnis. Die Struktur ist als OPENFILENAME-Struktur in Listing 5.6
definiert.
Listing 5.6: Die Struktur OPENFILENAME
1: typedef struct tagOFN { // ofn
2: DWORD lStructSize;
3: HWND hwndOwner;
4: HINSTANCE hInstance;
5: LPCTSTR lpstrFilter;
6: LPTSTR lpstrCustomFilter;
7: DWORD nMaxCustFilter;
8: DWORD nFilterIndex;
9: LPTSTR lpstrFile;
10: DWORD nMaxFile;
11: LPTSTR lpstrFileTitle;
12: DWORD nMaxFileTitle;
13: LPCTSTR lpstrInitialDir;
14: LPCTSTR lpstrTitle;
15: DWORD Flags;
16: WORD nFileOffset;
17: WORD nFileExtension;
18: LPCTSTR lpstrDefExt;
19: DWORD lCustData;
20: LPOFNHOOKPROC lpfnHook;
21: LPCTSTR lpTemplateName;
22: } OPENFILENAME;
Diese Attribute können Sie festlegen, bevor Sie die Methode DoModal
der Dialogfeldklasse
aufrufen, um das Verhalten des Dialogfelds Öffnen zu bestimmen. Wenn Sie
zum Beispiel wie in Listing 5.7 das Startverzeichnis auf C:\Temp
setzen, bevor Sie DoModal
aufrufen, erscheint das Dialogfeld Öffnen mit diesem ausgewählten Verzeichnis.
Listing 5.7: Die überarbeitete Funktion OnFileopen
1: void CDialogeDlg::OnFileopen()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-
ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: CFileDialog m_ldFile(TRUE);
10:
11: // Anfangsverzeichnis initialisieren
12: m_ldFile.m_ofn.lpstrInitialDir = "C:\\Temp\\";
13:
14: // Dialogfeld Öffnen anzeigen und Ergebnis auffangen
15: if (m_ldFile.DoModal() == IDOK)
16: {
17: // Gewählten Dateinamen ermitteln
18: m_sResults = m_ldFile.GetFileName();
19: // Dialogfeld aktualisieren
20: UpdateData(FALSE);
21: }
22:
23: ///////////////////////
24: // EIGENER CODE, ENDE
25: ///////////////////////
26: }
1. Wie lauten die möglichen Rückgabewerte, die Ihre Anwendung aus einem Aufruf
der Funktion MessageBox
erhält, wenn Sie die Schaltflächenkombination
MB_RETRYCANCEL
übergeben?
2. Welche Standarddialogfelder des Betriebssystems Windows sind als MFC-Klassen definiert?
3. Worin liegt der Unterschied zwischen einem modalen und einem nichtmodalen Dialogfeld?
4. Wie läßt sich statt dem in der heutigen Beispielanwendung eingesetzten Dialogfeld Öffnen das Dialogfeld Speichern unter anzeigen?
5. Warum war es nicht erforderlich, für das benutzerdefinierte Dialogfeld Funktionen oder Code zu erstellen?
1. Modifizieren Sie Ihre Anwendung, damit das Verzeichnis zusammen mit dem Dateinamen
erscheint. (Hinweis: Die Funktion GetFileName
liefert den Pfad und den
Dateinamen, die im Dialogfeld Öffnen ausgewählt wurden.)
2. Nehmen Sie in das benutzerdefinierte Dialogfeld eine Schaltfläche auf, die den
Aufruf der Funktion MessageBox
mit den Auswahlen Ja und Nein bewirkt. Übergeben
Sie das Ergebnis an das Hauptdialogfeld der Anwendung.