vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 1

Tag 5

Dialogfelder

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

Vordefinierte (oder System-) Dialogfelder

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.

Meldungsfelder

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.

Die Funktion MessageBox

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.

Wenn Sie mit dem dritten Argument an die Funktion MessageBox die Schaltflächen oder das anzuzeigende Symbol spezifizieren, ist das zweite Argument (der Titel des Meldungsfelds) nicht mehr optional. In diesem Fall müssen Sie einen Wert für die Titelleiste des Meldungsfelds bereitstellen.

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.

Tabelle 5.1: IDs zur Festlegung der Schaltflächenkombination in der Funktion MessageBox

ID

Schaltflächen

MB_ABORTRETRYIGNORE

Beenden, Wiederholen, Ignorieren

MB_OK

OK

MB_OKCANCEL

OK, Abbrechen

MB_RETRYCANCEL

Wiederholen, Abbrechen

MB_YESNO

Ja, Nein

MB_YESNOCANCEL

Ja, Nein, Abbrechen

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.

Tabelle 5.2: IDs zur Festlegung der Symbole in der Funktion MessageBox

ID

Symbol

MB_ICONINFORMATION

Info-Symbol

MB_ICONQUESTION

Fragezeichen-Symbol

MB_ICONSTOP

Stop-Symbol

MB_ICONEXCLAMATION

Ausrufezeichen-Symbol

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.

Tabelle 5.3: Rückgabewerte der Funktion MessageBox

ID

Gewählte Schaltfläche

IDABORT

Beenden

IDRETRY

Wiederholen

IDIGNORE

Ignorieren

IDYES

Ja

IDNO

Nein

IDOK

OK

IDCANCEL

Abbrechen

Eine Dialogfeld-Anwendung erstellen

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

Tabelle 5.4: Eigenschaften der Steuerelemente für das Hauptdialogfeld

Objekt

Eigenschaft

Einstellung

Schaltfläche

ID

Titel

IDC_YESNOCANCEL

&Ja, Nein, Abbrechen

Schaltfläche

ID

Titel

IDC_ABORTRETRYIGNORE

Beenden, &Wiederholen, Ignorieren

Schaltfläche

ID

Titel

IDC_FILEOPEN

Datei ö&ffnen

Schaltfläche

ID

Titel

IDC_BCUSTOMDIALOG

Benutzerdefiniertes &Dialogfeld

Schaltfläche

ID

Titel

IDC_BWHICHOPTION

Welche &Option?

Schaltfläche

ID

Titel

IDC_EXIT

&Beenden

Text

ID

Titel

IDC_STATIC

Ergebnis der Dialogfelder:

Eingabefeld

ID

Mehrzeilig

Auto Vert. Bildlauf

IDC_RESULTS

Eingeschaltet

Eingeschaltet

4. Verbinden Sie mit Hilfe des Klassen-Assistenten die Variablen mit den in Tabelle 5.5 aufgeführten Steuerelementen.

Tabelle 5.5: Variablen der Steuerelemente

Objekt

Name

Kategorie

Typ

IDC_RESULTS

m_sResults

Wert

CString

IDC_BWHICHOPTION

m_cWhichOption

Control

CButton

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.

Die Meldungsfelder codieren

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

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.

Tabelle 5.6: Klassen für Standarddialogfelder

Klasse

Dialogfeldtyp

CFileDialog

Dateiauswahl

CFontDialog

Schriftauswahl

CColorDialog

Farbauswahl

CPageSetupDialog

Seite zum Drucken einrichten

CPrintDialog

Drucken

CFindReplaceDialog

Suchen und Ersetzen

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.

Ein Dialogfeld kann man in zwei unterschiedlichen Modi anzeigen. Den ersten Modus bezeichnet man als modales Fenster. Solange es angezeigt wird, kann der Benutzer keinerlei Aktionen in der Anwendung ausführen, bis er das Dialogfeld schließt. Das Meldungsfeld ist ein typisches Beispiel eines modalen Fensters. Hier kann der Benutzer erst dann weiterarbeiten, wenn er eine der Schaltflächen im Meldungsfeld betätigt.

Der zweite Modus, in dem sich ein Dialogfeld anzeigen läßt, ist das nichtmodale Fenster. Dieses kann geöffnet sein, während der Benutzer andere Aktionen in der Anwendung ausführt. Typische Beispiele für nichtmodale Fenster sind das Dialogfeld Suchen sowie das Dialogfeld Suchen und Ersetzen in Microsoft Word. Diese Dialogfelder können geöffnet bleiben, während man weiter an dem Dokument arbeitet, das man durchsucht.

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

Eigene Dialogfelder erstellen

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 Dialogfeld erzeugen

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.

Tabelle 5.7: Eigenschaftseinstellungen der Steuerelemente für das benutzerdefinierte Dialogfeld

Objekt

Eigenschaft

Einstellung

Text

ID

Titel

IDC_STATIC

&Nachricht eingeben:

Eingabefeld

ID

Mehrzeilig

Auto Vert. Bildlauf

IDC_MESSAGE

Eingeschaltet

Eingeschaltet

Gruppenfeld

ID

Titel

IDC_STATIC

Option auswählen

Optionsfeld

ID

Titel

Gruppe

IDC_OPTION1

Option &1

eingeschaltet

Optionsfeld

ID

Titel

IDC_OPTION2

Option &2

Optionsfeld

ID

Titel

IDC_OPTION3

Option &3

Optionsfeld

ID

Titel

IDC_OPTION4

Option &4

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.

Tabelle 5.8: Variablen der Steuerelemente

Objekt

Name

Kategorie

Typ

IDC_MESSAGE

m_sMessage

Wert

CString

IDC_OPTION1

m_iOption

Wert

int

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

In der Programmiersprache C++ beginnen alle Numerierungen mit 0 und nicht mit 1. Die erste Position in einem Array oder in einer Gruppe von Steuerelementen ist demnach die Position 0, die zweite die Position 1, das dritte Element hat den Index 2 usw.

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.

Das Dialogfeld in der Anwendung einsetzen

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.

Die Instanz des Dialogfelds erzeugen

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.

In den Programmiersprachen C und C++ bezeichnet man die #include- Anweisung als Compilerdirektive. Sie teilt dem Compiler mit, den Inhalt der angegebenen Datei in den zu kompilierenden Quellcode einzulesen. Man verwendet diese Direktiven, um Deklarationen von Klassen, Strukturen und Funktionen in separate Dateien zu schreiben, die sich in jeden Quellcode aufnehmen lassen, der auf die Informationen in der Header-Datei angewiesen ist. Weitere Informationen zur Funktionsweise der #include-Anweisungen und warum man sie verwendet finden Sie im Anhang A.

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.

Das Dialogfeld aufrufen und die Variablen lesen

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.

Zusammenfassung

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.

Fragen und Antworten

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: }

Workshop

Kontrollfragen

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?

Übungen

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.



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


Ein Imprint des Markt&Technik Buch- und Software-Verlag GmbH.
Elektronische Fassung des Titels: Visual C++ 6 in 21 Tagen, ISBN: 3-8272-2035-1