vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 1

Tag 2

Steuerelemente

In nahezu jeder Windows-Anwendung begegnet man Schaltflächen, Kontrollkästchen, Textfeldern und Dropdown-Listenfeldern. Man bezeichnet diese Komponenten als Steuerelemente, und viele dieser Steuerelemente sind in das Betriebssystem selbst integriert. In Visual C++ lassen sich diese allgemeinen Steuerelemente einsetzen, indem man sie einfach per Drag & Drop in einem Dialogfeld plaziert. Am heutigen Tag lernen Sie ...

Standardsteuerelemente von Windows

Zum Betriebssystem Windows gehören verschiedene Standardsteuerelemente wie Schieberegler, Strukturansicht, Listenelement oder Statusanzeige. In der heutigen Lektion geht es zunächst einmal um ein halbes Dutzend Steuerelemente, die sich in fast jeder Windows-Anwendung finden:

Diese und andere Steuerelemente stehen zur sofortigen Nutzung in Visual C++-Anwendungen bereit. Sie sind in der Steuerelementpalette im Dialog-Editor des Visual Studios untergebracht (siehe Abbildung 2.1).

Abbildung 2.1:
Die in der Steuerelementpalette verfügbaren Standardsteuerelemente

Text

Das Steuerelement Text verwendet man, um Text für den Benutzer anzuzeigen. Der Benutzer kann diesen Text weder ändern noch in anderer Form mit dem Steuerelement interagieren. Das Steuerelement ist als Nur-Lesen-Element vorgesehen. Allerdings kann man im Code der laufenden Anwendung den durch das Steuerelement angezeigten Text ohne weiteres ändern.

Eingabefelder

In einem Eingabefeld kann der Benutzer Text eingeben oder ändern. Das Steuerelement gehört zu den hauptsächlichen Werkzeugen, die dem Benutzer die Möglichkeit bieten, einer Anwendung bestimmte erforderliche Informationen bereitzustellen. Es ist in der Lage, beliebigen Text aufzunehmen, der sich auslesen und nach Bedarf weiterverarbeiten läßt. Das Eingabefeld akzeptiert ausschließlich reinen Text, Formatierungen stehen dem Benutzer nicht zur Verfügung.

Schaltflächen

Über eine Schaltfläche löst der Benutzer eine bestimmte Aktion aus. Die Beschriftung - der Titel - der Schaltfläche sollte einen Hinweis auf die Aktion liefern, die beim Klikken auf die Schaltfläche stattfindet. Eine Schaltfläche kann auch Bilder enthalten, die man - allein oder zusammen mit einer Textbeschreibung - benutzt, um den Zweck der Schaltfläche zu vermitteln.

Kontrollkästchen

Als Kontrollkästchen bezeichnet man die kleinen quadratischen Elemente, die der Benutzer durch Anklicken ein- (X) bzw. ausschaltet und damit einen bestimmten Wert setzt bzw. zurücksetzt. Grundsätzlich handelt es sich um Umschalter, gelegentlich mit einem dritten Zwischenzustand. Normalerweise verwendet man Kontrollkästchen, um diskrete Variablen vom Typ An/Aus zu steuern.

Optionsfelder

Ein Optionsfeld wird als Kreis dargestellt. Klickt der Benutzer ein Optionsfeld an, erscheint ein Punkt im Kreis. Das Optionsfeld ähnelt dem Kontrollkästchen, wird aber in einer Gruppe verwendet, in der nur ein Optionsfeld eingeschaltet sein kann. Normalerweise setzt man Optionsfelder in Gruppen mit mindestens drei Optionen ein, wobei die Optionsfelder von einem Gruppenfeld umgeben sind. Das Gruppenfeld gewährleistet die Unabhängigkeit der einzelnen Optionsfeldgruppen, wobei gleichzeitig in jeder Gruppe jeweils ein Optionsfeld eingeschaltet sein kann.

Kombinationsfelder

Ein Kombinationsfeld (oder Dropdown-Listenfeld) besteht aus einem Eingabefeld, dem eine Liste mit verfügbaren Werten zugeordnet ist. Mit einem Kombinationsfeld kann man eine Liste von Auswahlen bereitstellen, wobei der Benutzer einen Wert aus der Liste auswählen kann. Manchmal hat der Benutzer die Möglichkeit, selbst einen Wert einzutippen, wenn die Liste keinen passenden Wert enthält.

Steuerelemente in ein Fenster aufnehmen

Die heute zu erstellende Anwendung soll eine Reihe von Steuerelementen in einem Dialogfeld enthalten, wie es aus Abbildung 2.2 hervorgeht. Diese Steuerelemente haben verschiedene Aufgaben. Am oberen Rand des Fensters befindet sich ein Eingabefeld, in das der Benutzer eine Nachricht eintippen kann, die in einem Meldungsfeld erscheint, wenn er auf die Schaltfläche neben dem Feld klickt. Unterhalb dieses Eingabefelds sind zwei Schaltflächen angeordnet, die entweder das Eingabefeld mit einer Standardmeldung füllen oder einen vorhandenen Eintrag löschen. Unter diesen Schaltflächen befindet sich ein Kombinationsfeld mit einer Liste von Windows-Standardanwendungen. Wählt der Benutzer eines dieser Programme aus und klickt auf die Schaltfläche neben der Dropdown-Liste, startet das ausgewählte Programm. Darunter sind zwei Gruppen von Kontrollkästchen angeordnet. Diese wirken auf die Steuerelemente im oberen Teil des Dialogfelds: die Steuerelemente für die Anzeige einer Benutzermeldung und die Steuerelemente für die Ausführung eines anderen Programms. Die Kontrollkästchen auf der linken Seite aktivieren und deaktivieren die einzelnen Gruppen von Steuerelementen. Mit den rechten Kontrollkästchen lassen sich die Gruppen der Steuerelemente anzeigen und ausblenden. Im unteren Teil des Dialogfelds befindet sich eine Schaltfläche, die das Schließen der Anwendung bewirkt.

Abbildung 2.2:
Die heutige Anwendung verwendet mehrere Standardsteuerelemente.

Anwendungsgerüst und Layout des Dialogfelds erstellen

Mit den gestern erworbenen Kenntnissen können Sie jetzt ein neues Anwendungsgerüst erstellen und das Layout des Anwendungsdialogfelds entwerfen. Führen Sie dazu die folgenden Schritte aus:

1. Erstellen Sie mit dem Anwendungs-Assistenten einen neuen Projekt-Arbeitsbereich, und nennen Sie das Projekt Tag2.

2. Verwenden Sie im Anwendungs-Assistenten die gleichen Einstellungen wie gestern. Legen Sie den Titel des Dialogfelds mit Visual C++-Steuerelemente fest.

3. Nachdem Sie das Anwendungsgerüst erstellt haben, gestalten Sie das Hauptdialogfeld wie in der weiter oben gezeigten Abbildung 2.2.

4. Konfigurieren Sie die Eigenschaften der Steuerelemente gemäß Tabelle 2.1.

Tabelle 2.1: Eigenschaftseinstellungen für die Steuerelemente im Anwendungsdialogfeld

Objekt

Eigenschaft

Einstellung

Text

ID

Titel

IDC_STATIC

Beispiel einer Visual C++-Anwendung mit einer Reihe von Steuerelementen.

Text

ID

Titel

IDC_STATICMSG

Nachricht &eingeben:

Text

ID

Titel

IDC_STATICPGM

&Programm starten:

Eingabefeld

ID

IDC_MSG

Schaltfläche

ID

Titel

IDC_SHWMSG

Nachricht zei&gen

Schaltfläche

ID

Titel

IDC_DFLTMSG

&Stan&dardnachricht

Schaltfläche

ID

Titel

IDC_CLRMSG

Nachricht &löschen

Schaltfläche

ID

Titel

IDC_RUNPGM

Programm &starten

Schaltfläche

ID

Titel

IDC_EXIT

&Beenden

Kombinationsfeld

ID

IDC_PROGTORUN

Gruppenfeld

ID

Titel

IDC_STATIC

&Aktionen aktivieren

Gruppenfeld

ID

Titel

IDC_STATIC

A&ktionen zeigen

Kontrollkästchen

ID

Titel

IDC_CKENBLMSG

&Nachrichtenaktion aktivieren

Kontrollkästchen

ID

Titel

IDC_CKENBLPGM

Programmaktion akti&vieren

Kontrollkästchen

ID

Titel

IDC_CKSHWMSG

Na&chrichtenaktion zeigen

Kontrollkästchen

ID

Titel

IDC_CKSHWPGM

Progra&mmaktion zeigen

Wenn man ein Kombinationsfeld in das Fenster aufnimmt, ist darauf zu achten, daß man klickt und den Bereich für das Steuerelement so groß zieht, wie die Dropdown-Liste sein soll. Nachdem man das Steuerelement im Fenster gezeichnet hat, kann man die Größe genauso ändern, wie es normalerweise üblich ist. Um die Ausdehnung der Liste nach unten festzulegen, klickt man auf den Pfeil - genauso, als würde man bei laufender Anwendung die Dropdown-Liste aktivieren.

5. Nachdem Sie alle genannten Steuerelemente im Dialogfeld plaziert und deren Eigenschaften konfiguriert haben, öffnen Sie das Eigenschaftsdialogfeld für das Kombinationsfeld erneut. Auf der Registerkarte Daten tragen Sie die folgenden Werte ein, wobei Sie zum zweiten bzw. dritten Eintrag mit der Tastenkombination (Strg)+(¢) weiterschalten (siehe Abbildung 2.3).

Abbildung 2.3:
Die Einträge in der Dropdown-Liste des Kombinationsfeldes legen Sie über das Eigenschaftsdialogfeld fest.

Die Tabulator-Reihenfolge von Steuerelementen festlegen

Nach der Anordnung der Steuerelemente im Fenster müssen Sie noch sicherstellen, daß der Benutzer bei der Navigation mit Hilfe der (ÿ__)-Taste die Steuerelemente in der von Ihnen gewünschten Reihenfolge anspricht. Die Tabulator-Reihenfolge legen Sie mit den nachstehenden Schritten fest:

1. Markieren Sie im Bearbeitungsbereich von Visual Studio entweder das Dialogfeld oder eines der Steuerelemente im Fenster.

2. Wählen Sie Layout / Tabulator-Reihenfolge. Daraufhin erscheinen im Fenster neben den Steuerelementen Nummern. Diese kennzeichnen die Reihenfolge, in der die Navigation durch das Dialogfeld verläuft (siehe Abbildung 2.4).

Abbildung 2.4:
Das Einschalten der Tabulator-Reihenfolge zeigt die Reihenfolge der Navigation durch das Dialogfeld an.

3. Klicken Sie mit der Maus die Nummernfelder in der Reihenfolge an, in der der Benutzer durch das Dialogfeld navigieren soll. Die Steuerelemente numerieren sich automatisch neu, wenn Sie sie nacheinander auswählen.

4. Nachdem Sie die Tabulator-Reihenfolge festgelegt haben, wählen Sie Layout / Tabulator-Reihenfolge erneut, um zum Dialog-Editor zurückzukehren.

Statischer Text, der mit einer Zugriffstaste versehen ist, sollte in der Tabulator-Reihenfolge unmittelbar vor dem zugehörigen Steuerelement stehen. Da der Benutzer nicht mit statischem Text interagieren kann, geht der Fokus bei Wahl der Zugriffstaste direkt zum nächsten Steuerelement laut Tabulator-Reihenfolge.

Eine Zugriffstaste ist durch das unterstrichene Zeichen - den sogenannten mnemonischen Code - in der Beschriftung (dem Titel) einer Schaltfläche, eines Kontrollkästchens, eines Menüs oder eines anderen Steuerelements gekennzeichnet. Der Benutzer kann den unterstrichenen Buchstaben in Kombination mit der (Alt)-Taste drücken, um direkt zu diesem Steuerelement zu gelangen oder das angeklickte Ereignis auf dem Steuerelement auszulösen. Um eine Zugriffstaste festzulegen, schreibt man bei Eingabe des Titels ein kaufmännisches Und-Zeichen (&) unmittelbar vor das betreffende Zeichen. Achten Sie darauf, daß Sie für mehrere Zugriffstasten nicht dieselben Zeichen im selben Fenster oder derselben Menügruppe vorsehen, da es den Benutzer nur verwirrt, wenn er eine Zugriffstaste drückt und nicht die erwartete Reaktion eintritt.

Bevor Sie sich mit dem Code der Anwendung beschäftigen, sollten Sie abschließend die Zugriffstasten auf Konflikte prüfen. Führen Sie dazu die folgenden Schritte aus:

1. Markieren Sie im Dialog-Editor das Dialogfeld oder eines der Steuerelemente. Klicken Sie mit der rechten Maustaste, und wählen Sie Zugriffstasten prüfen.

2. Wenn keine Konflikte bei Ihren mnemonischen Codes aufgetreten sind, zeigt Visual C++ ein entsprechendes Meldungsfeld an (siehe Abbildung 2.5).

Abbildung 2.5:
Eine Prüfung der Zugriffstasten zeigt, ob Konflikte vorliegen.

3. Falls Konflikte vorhanden sind, kennzeichnet das Dialogfeld den betreffenden Buchstaben und gibt Ihnen die Möglichkeit, die Steuerelemente mit den gegensätzlichen Einträgen auswählen zu lassen (siehe Abbildung 2.6).

Abbildung 2.6:
Doppelte mnemonische Codes lassen sich automatisch auswählen.

Variablen mit Steuerelementen verbinden

Wenn Sie bereits mit Visual Basic oder PowerBuilder programmiert haben, ahnen Sie sicherlich schon, daß es nun an der Zeit ist, etwas Code zu verfassen. Mit Visual C++ läuft dieser Prozeß allerdings nicht genauso ab. Bevor Sie mit der Codierung beginnen können, müssen Sie allen Steuerelementen, denen ein Wert zugewiesen ist, Variablen zuordnen - allen, außer dem statischem Text und den Schaltflächen. Auf die Variablen greifen Sie zurück, wenn Sie den Code für die Anwendung schreiben. Die Werte, die der Benutzer in die Bildschirmsteuerelemente eingibt, übernimmt das Programm zur Weiterverarbeitung in diese Variablen. Analog dazu werden alle Werte, die der Code Ihrer Anwendung in diese Variablen stellt, in den Steuerelementen des Fensters aktualisiert, damit sie der Benutzer sieht.

Wie deklariert man nun diese Variablen und verbindet sie mit den Steuerelementen, die man im Fenster plaziert hat? Führen Sie die folgenden Schritte aus:

1. Öffnen Sie den Klassen-Assistenten, wie Sie es gestern gelernt haben.

2. Aktivieren Sie die Registerkarte Member-Variablen (siehe Abbildung 2.7).

Abbildung 2.7:
Über die Registerkarte Member-Variablen des Klassen-Assistenten fügen Sie den Steuerelementen Variablen hinzu.

3. Markieren Sie die ID eines der Steuerelemente, denen Sie eine Variable zuordnen möchten, beispielsweise IDC_MSG.

4. Klicken Sie auf Variable hinzufügen.

5. Im Dialogfeld Member-Variable hinzufügen geben Sie den Variablennamen ein und legen die Kategorie sowie den Typ der Variablen fest wie es Abbildung 2.8 zeigt. Klicken Sie auf OK.

Abbildung 2.8:
Einem Steuerelement eine Variable zuordnen

6. Wiederholen Sie die Schritte 3 bis 5 für alle anderen Steuerelemente, für die Sie Variablen zuordnen müssen. In der heutigen Anwendung betrifft das die Variablen gemäß Tabelle 2.2.

Tabelle 2.2: Variablen für die Steuerelemente der Anwendung

Steuerelement

Variablenname

Kategorie

Typ

IDC_MSG

m_strMessage

Wert

CString

IDC_PROGTORUN

m_strProgToRun

Wert

CString

IDC_CKENBLMSG

m_bEnableMsg

Wert

BOOL

IDC_CKENBLPGM

m_bEnablePgm

Wert

BOOL

IDC_CKSHWMSG

m_bShowMsg

Wert

BOOL

IDC_CKSHWPGM

m_bShowPgm

Wert

BOOL

Alle hier verwendeten Variablen beginnen mit dem Präfix m_, da es sich um Member-Variablen (oder Elementvariablen) einer Klasse handelt. Diese Konvention hat sich bei der Vergabe von Namen für Elemente von MFC- Klassen eingebürgert. Nach dem m_ verwendet man eine Form der Ungarischen Notation, bei der die nächsten Buchstaben den Variablentyp beschreiben. Im obigen Beispiel bedeutet b einen Booleschen Wert, während str eine Variable als String (Zeichenfolge) kennzeichnet. Diese Namenskonvention finden Sie im vorliegenden Buch und auch in anderen Büchern, die sich dem Thema Programmierung mit Visual C++ und MFC widmen. Durch diese Schreibweise läßt sich der Code für andere Programmierer leichter erfassen, was umgekehrt auch auf Sie zutrifft.

7. Nachdem Sie alle erforderlichen Variablen hinzugefügt haben, klicken Sie auf OK, um den Klassen-Assistenten zu schließen.

Steuerelemente mit Funktionalität ausstatten

Bevor Sie den Code für alle Steuerelemente in Ihrem Anwendungsfenster schreiben, ist zunächst etwas Code erforderlich, um die Variablen zu initialisieren, d.h. Startwerte für die meisten Variablen festzulegen. Führen Sie dazu folgende Schritte aus:

1. Starten Sie den Klassen-Assistenten, gehen Sie auf die Registerkarte Nachrichtenzuordnungstabellen , und markieren Sie die Funktion OnInitDialog in der Liste der Member-Funktionen. Die Funktion suchen Sie im Listenfeld Member- Funktionen auf, oder Sie wählen das Objekt CTag2Dlg in der Liste Objekt-IDs aus und markieren dann WM_INITDIALOG im Listenfeld Nachrichten, wie es Abbildung 2.9 zeigt.

Abbildung 2.9:
Vorhandene Funktionen lassen sich mit dem Klassen-Assistenten auffinden.

2. Klicken Sie auf die Schaltfläche Code bearbeiten. Daraufhin gelangen Sie in den Quellcode für die Funktion OnInitDialog.

3. Gehen Sie zur Markierung ZU ERLEDIGEN, die die Stelle kennzeichnet, wo Sie mit der Codeeingabe beginnen. Geben Sie hier den Code aus Listing 2.1 ein.

Listing 2.1: TAG2DLG.CPP - In die Funktion OnInitDialog geben Sie den Initialisierungscode ein.

1: BOOL CTag2Dlg::OnInitDialog()
2: {
3: CDialog::OnInitDialog();
4:
5: .
6: .
7: .
8:
9: // ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
10:
11: ///////////////////////
12: // EIGENER CODE, ANFANG
13: ///////////////////////
14:
15: // Standardtext in Eingabefeld eintragen
16: m_strMessage = "Nachricht hier eingeben";
17:
18: // Alle Kontrollkästchen einschalten
19: m_bShowMsg = TRUE;
20: m_bShowPgm = TRUE;
21: m_bEnableMsg = TRUE;
22: m_bEnablePgm = TRUE;
23:
24: // Dialogfeld mit den Werten aktualisieren
25: UpdateData(FALSE);
26:
27: ///////////////////////
28: // EIGENER CODE, ENDE
29: ///////////////////////
30:
31: return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll den ÂFokus erhalten
32: }

Listing 2.1 zeigt nur einen Ausschnitt der Funktion OnInitDialog. Die Listings im gesamten Buch konzentrieren sich nur auf den Code, der hinzuzufügen oder zu modifizieren ist, und zeigen der Übersichtlichkeit wegen nicht den gesamten Code aller Funktionen. (Damit bleibt auch der Umfang des Buches in einem vernünftigen Rahmen.) Um Ihre Kenntnisse zu MFC und Visual C++ zu erweitern, sollten Sie sich auch den Code ansehen, der hier ausgelassen wurde. Versuchen Sie zu verstehen, was der Code bewirkt.

Wenn Sie bereits in C oder C++ programmiert haben, ist Ihnen sicherlich aufgefallen, daß der Wert der Variablen m_strMessage in einer C-untypischen Art und Weise festgelegt wird. Das Ganze erinnert mehr an die Festlegung einer Stringvariablen in Visual Basic oder PowerBuilder. Das hängt damit zusammen, daß diese Variable vom Typ CString ist. Die Klasse CString erlaubt es, in einer Visual C++-Anwendung mit Strings zu arbeiten, genau wie man mit Strings in einer der anderen Programmiersprachen umgeht. Da es sich jedoch um die Programmiersprache C++ handelt, müssen Sie dennoch ein Semikolon am Ende jedes Befehls schreiben.

Der Initialisierungscode ist nicht weiter kompliziert. Das Programm stellt als erstes in das Eingabefeld eine anfängliche Nachricht, die Sie dem Benutzer anzeigen wollen, und setzt dann alle Kontrollkästchen in den eingeschalteten Zustand. Die letzte Zeile des hinzugefügten Codes verdient etwas mehr Beachtung.

Die Funktion UpdateData bildet den Schlüssel für die Arbeit mit Steuerelementvariablen in Visual C++. Die Funktion übernimmt die Daten aus den Variablen und aktualisiert mit den Werten die Steuerelemente auf dem Bildschirm. Umgekehrt übernimmt die Funktion die Daten aus den Steuerelementen und füllt die zugeordneten Variablen mit allen vom Benutzer geänderten Werten. Die Richtung der Datenübertragung steuert man mit dem an die Funktion UpdateData übergebenen Argument. Ist das Argument auf FALSE gesetzt, werden die Werte in den Variablen an die Steuerelemente im Fenster übertragen. Übergibt man TRUE als Argument, erhalten die Variablen die aktuellen Werte der Steuerelemente im Fenster. Welcher Wert an die Funktion zu übergeben ist, hängt also davon ab, in welcher Richtung die Aktualisierung stattfinden soll. Nachdem Sie eine oder mehrere Variablen in Ihrem Code aktualisiert haben, müssen Sie UpdateData aufrufen und FALSE als Argument übergeben. Wenn Sie die Variablen lesen müssen, um deren aktuellen Wert zu erhalten, ist UpdateData mit dem Argument TRUE aufzurufen, bevor Sie irgendeinen Wert aus den Variablen verarbeiten. Ein Gefühl für diese Vorgehensweise werden Sie entwickeln, wenn Sie mehr Code in Ihre Anwendung aufnehmen.

Die Anwendung schließen

Als erstes sollten Sie sich darum kümmern, daß der Benutzer die Anwendung schließen kann. Da Sie die Schaltflächen OK und Abbrechen gelöscht und eine neue Schaltfläche für das Schließen des Anwendungsfensters hinzugefügt haben, müssen Sie Code in die Funktion aufnehmen, die von der Schaltfläche Beenden ausgelöst wird, um das Fenster zu schließen. Führen Sie dazu die folgenden Schritte aus:

1. Fügen Sie mit dem Klassen-Assistenten eine Funktion zur Objekt-ID IDC_EXIT für die Nachricht BN_CLICKED hinzu, wie Sie es gestern kennengelernt haben.

2. Klicken Sie auf die Schaltfläche Code bearbeiten, um in den Quelltext der neu hinzugefügten Funktion zu gelangen.

3. Geben Sie den Code von Listing 2.2 ein.

Die Markierungen TODO und ZU ERLEDIGEN sind vollkommen identisch. An manchen Stellen ist im Visual Studio offensichtlich nur die deutsche Übersetzung verlorengegangen - oder vergessen worden. Lassen Sie sich durch diesen Schönheitsfehler nicht verwirren.

Listing 2.2: TAG2DLG.CPP - Die Funktion OnExit

1: void CTag2Dlg::OnExit()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Programm beenden
10: OnOK();
11:
12: ///////////////////////
13: // EIGENER CODE, ENDE
14: ///////////////////////
15: }

Ein einziger Funktionsaufruf in der Funktion OnExit schließt das Fenster und beendet die Anwendung. Woher kommt diese OnOK-Funktion, und warum mußten Sie sie nicht in der gestrigen Anwendung aufrufen? Zwei Funktionen, OnOK und OnCancel, sind in der Basisklasse CDialog definiert, von der Ihre Klasse CTag2Dlg abgeleitet ist. In der Klasse CDialog hat die Nachrichtenzuordnungstabelle bereits die Objekt-IDs der Schaltflächen OK und Abbrechen mit den Funktionen OnOK bzw. OnCancel verbunden, so daß Schaltflächen mit diesen IDs automatisch die entsprechenden Funktionen aufrufen. Wenn Sie die Objekt-ID der Schaltfläche Beenden mit IDOK festgelegt hätten, müßten Sie der Schaltfläche keinerlei Code zuordnen, solange Sie nicht die grundlegende Funktionalität von OnOK überschreiben möchten.

Die Nachricht des Benutzers anzeigen

Es sollte ein Leichtes sein, die vom Benutzer in das Eingabefeld eingegebene Nachricht anzuzeigen, da dieser Vorgang den gestern beschriebenen Abläufen ähnelt. Sie können der Schaltfläche Nachricht zeigen eine Funktion zuordnen und die Funktion MessageBox aufrufen, wie es aus Listing 2.3 hervorgeht.

Listing 2.3: TAG2DLG.CPP - Die Funktion OnShwmsg zeigt die Benutzernachricht an.

1: void CTag2Dlg::OnShwmsg()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Nachricht anzeigen
10: MessageBox(m_strMessage);
11:
12: ///////////////////////
13: // EIGENER CODE, ENDE
14: ///////////////////////
15: }

Wenn Sie die Anwendung in dieser Phase kompilieren und ausführen, tritt ein Problem mit diesem Code zutage. Es erscheint der String, mit dem Sie die Variable m_strMessage in der Funktion OnInitDialog initialisiert haben, und nicht die Nachricht, die der Benutzer in das Eingabefeld eingibt.

Das ist darauf zurückzuführen, daß Sie die Variable noch nicht mit dem Inhalt des Steuerelements im Fenster aktualisiert haben. Es ist UpdateData mit auf TRUE gesetztem Argument aufzurufen, um die Werte der Steuerelemente zu lesen und die Variablen damit zu initialisieren, bevor Sie die Funktion MessageBox aufrufen. Ändern Sie die Funktion OnShwmsg gemäß Listing 2.4 ab.

Listing 2.4: TAG2DLG.CPP - Aktualisierte Version der Funktion OnShwmsg

1: void CTag2Dlg::OnShowmsg()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Nachrichtenvariable mit Benutzereingabe aktualisieren
10: UpdateData(TRUE);
11:
12: // Nachricht anzeigen
13: MessageBox(m_strMessage);
14:
15: ///////////////////////
16: // EIGENER CODE, ENDE
17: ///////////////////////
18: }

Wenn Sie Ihre Anwendung jetzt kompilieren und ausführen, sollte die in das Eingabefeld eingegebene Meldung angezeigt werden, wie es Abbildung 2.10 verdeutlicht.

Abbildung 2.10:
Die in das Eingabefeld eingetippte Nachricht wird dem Benutzer angezeigt.

Die Nachricht des Benutzers löschen

Falls der Benutzer ein leeres Eingabefeld vorfinden möchte, bevor er eine Nachricht eintippt, können Sie der Schaltfläche Nachricht löschen eine Funktion zuordnen, um den Inhalt des Eingabefeldes zu leeren. Die Funktion fügen Sie in der gewohnten Weise über den Klassen-Assistenten hinzu. Die Funktionalität realisieren Sie ganz einfach, indem Sie die Variable m_strMessage auf einen leeren String setzen und dann die Steuerelemente im Fenster aktualisieren, um diesen Wert wiederzugeben. Der entsprechende Code ist in Listing 2.5 zu sehen.

Listing 2.5: TAG2DLG.CPP - Die Funktion OnClrmsg

1: void CTag2Dlg::OnClrmsg()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Nachricht löschen
10: m_strMessage = "";
11:
12: // Bildschirm aktualisieren
13: UpdateData(FALSE);
14:
15: ///////////////////////
16: // EIGENER CODE, ENDE
17: ///////////////////////
18: }

Die Nachrichtensteuerelemente deaktivieren und ausblenden

In bezug auf die Nachrichtensteuerelemente ist als letztes noch die Funktionalität für die Kontrollkästchen Nachrichtenaktion aktivieren und Nachrichtenaktion zeigen zu implementieren. Das erste dieser Kontrollkästchen aktiviert oder deaktiviert die Steuerelemente, die sich auf die Anzeige der Benutzernachricht beziehen. Wenn das Kontrollkästchen eingeschaltet ist, sind alle Steuerelemente aktiviert. Weist das Kontrollkästchen den ausgeschalteten Zustand auf, sind die betreffenden Steuerelemente deaktiviert. Analog dazu dient das zweite Kontrollkästchen dazu, dieselbe Gruppe der Steuerelemente anzuzeigen bzw. auszublenden. Listing 2.6 zeigt den Code für beide Funktionen.

Listing 2.6: TAG2DLG.CPP - Die Funktionen für die Kontrollkästchen Nachrichtenaktion aktivieren/zeigen.

1: void CTag2Dlg::OnCkenblmsg()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Aktuelle Werte vom Bildschirm holen
10: UpdateData(TRUE);
11:
12: // Kontrollkästchen 'Nachrichtenaktion aktivieren' eingeschaltet?
13: if (m_bEnableMsg == TRUE)
14: {
15: // Ja, dann alle Steuerelemente aktivieren,
16: // die für Anzeige der Nachricht relevant sind.
17: GetDlgItem(IDC_MSG)->EnableWindow(TRUE);
18: GetDlgItem(IDC_SHWMSG)->EnableWindow(TRUE);
19: GetDlgItem(IDC_DFLTMSG)->EnableWindow(TRUE);
20: GetDlgItem(IDC_CLRMSG)->EnableWindow(TRUE);
21: GetDlgItem(IDC_STATICMSG)->EnableWindow(TRUE);
22: }
23: else
24: {
25: // Nein, dann alle Steuerelemente deaktivieren,
26: // die für Anzeige der Nachricht relevant sind.
27: GetDlgItem(IDC_MSG)->EnableWindow(FALSE);
28: GetDlgItem(IDC_SHWMSG)->EnableWindow(FALSE);
29: GetDlgItem(IDC_DFLTMSG)->EnableWindow(FALSE);
30: GetDlgItem(IDC_CLRMSG)->EnableWindow(FALSE);
31: GetDlgItem(IDC_STATICMSG)->EnableWindow(FALSE);
32: }
33:
34: ///////////////////////
35: // EIGENER CODE, ENDE
36: ///////////////////////
37: }
38:
39: void CTag2Dlg::OnCkshwmsg()
40: {
41: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
42:
43: ///////////////////////
44: // EIGENER CODE, ANFANG
45: ///////////////////////
46:
47: // Aktuelle Werte vom Bildschirm holen
48: UpdateData(TRUE);
49:
50: // Kontrollkästchen 'Nachrichtenaktion zeigen' eingeschaltet?
51: if (m_bShowMsg == TRUE)
52: {
53: // Ja, dann alle Steuerelemente anzeigen, die
54: // für Anzeige der Nachricht relevant sind.
55: GetDlgItem(IDC_MSG)->ShowWindow(TRUE);
56: GetDlgItem(IDC_SHWMSG)->ShowWindow(TRUE);
57: GetDlgItem(IDC_DFLTMSG)->ShowWindow(TRUE);
58: GetDlgItem(IDC_CLRMSG)->ShowWindow(TRUE);
59: GetDlgItem(IDC_STATICMSG)->ShowWindow(TRUE);
60: }
61: else
62: {
63: // Nein, dann alle Steuerelemente ausblenden, die
64: // für Anzeige der Nachricht relevant sind
65: GetDlgItem(IDC_MSG)->ShowWindow(FALSE);
66: GetDlgItem(IDC_SHWMSG)->ShowWindow(FALSE);
67: GetDlgItem(IDC_DFLTMSG)->ShowWindow(FALSE);
68: GetDlgItem(IDC_CLRMSG)->ShowWindow(FALSE);
69: GetDlgItem(IDC_STATICMSG)->ShowWindow(FALSE);
70: }
71:
72: ///////////////////////
73: // EIGENER CODE, ENDE
74: ///////////////////////
75: }

Den ersten Teil dieser Funktionen sollten Sie mittlerweile verstehen. Als erstes werden die Variablen mit den aktuellen Werten der Steuerelemente im Fenster aktualisiert. Es folgt ein Test der Booleschen Variablen, die mit dem jeweiligen Kontrollkästchen verbunden ist. Enthält die Variable den Wert TRUE, soll das Programm das Steuerelement aktivieren oder anzeigen. Hat die Variable den Wert FALSE, ist das Steuerelement zu deaktivieren bzw. auszublenden.

Von jetzt an ist der Code nicht mehr ganz so durchsichtig. Die erste Funktion, GetDlgItem , erhält als Parameter die ID des zu ändernden Steuerelements. Die Funktion liefert das Objekt für das Steuerelement zurück. Mit dieser Funktion läßt sich das Objekt für beliebige Steuerelemente im Fenster bei laufender Anwendung abrufen. Der nächste Teil jedes Befehls ruft eine Member-Funktion des Steuerelementobjekts auf. Die zweite Funktion ist eine Member-Funktion des von der ersten Funktion zurückgegebenen Objekts. Falls Ihnen dieser Ablauf nicht ganz klar sein sollte, empfiehlt sich ein Studium von Anhang A.

Die zweiten Funktionen in diesen Aufrufen, EnableWindow und ShowWindow, sehen eher wie Funktionen für Fenster aber nicht für Steuerelemente aus. Natürlich sind sie für Fenster vorgesehen. Zufällig sind es aber auch Elemente der Klasse CWnd, die der Vorfahr der Klasse CDialog ist, von der Sie Ihre Klasse CTag2Dlg abgeleitet haben. In Windows sind nun mal alle Steuerelemente selbst Fenster, die völlig unabhängig von dem Fenster sind, in dem sie sich befinden. Damit kann man Steuerelemente als Fenster behandeln und Fensterfunktionen auf ihnen aufrufen. In der Tat sind alle Steuerelementklassen von der Klasse CWnd abgeleitet, was ihr wahres Gesicht als Fenster offenbart.

Wenn Sie jetzt Ihre Anwendung kompilieren und ausführen, können Sie die Kontrollkästchen Nachrichtenaktion aktivieren und Nachrichtenaktion zeigen ausprobieren. Die Funktionsweise sollte Abbildung 2.11 entsprechen.

Abbildung 2.11:
Die Steuerelemente für Benutzernachrichten lassen sich nun deaktivieren.

Eine andere Anwendung starten

Als letzte größere Aufgabe müssen wir noch die Funktionalität für die Steuerelemente implementieren, die dem Start eines anderen Programms dienen. Weiter vorn haben Sie die Namen von drei Windows-Anwendungen in das Kombinationsfeld aufgenommen. Wenn Sie die Anwendung starten, erscheinen diese Namen in der Dropdown- Liste. Man kann einen Eintrag auswählen, und im Wertbereich des Kombinationsfelds erscheint der Name der jeweiligen Anwendung. Damit dieser Teil auch funktioniert, müssen Sie lediglich für die Schaltfläche Programm starten Code hinzufügen, um tatsächlich den Wert aus dem Kombinationsfeld zu ermitteln und das passende Programm zu starten. Nachdem Sie das Funktionsgerüst für die Schaltfläche Programm starten mit dem Klassen-Assistenten erstellt haben, fügen Sie den Code aus Listing 2.7 in die Funktion ein.

Listing 2.7: TAG2DLG.CPP - Die Funktion OnRunpgm startet andere Windows-Anwendungen.

1: void CTag2Dlg::OnRunpgm()
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Aktuelle Werte vom Bildschirm holen
10: UpdateData(TRUE);
11:
12: // Lokale Variable zur Aufnahme des Programmnamens deklarieren
13: CString strPgmName;
14:
15: // Programmname in die lokale Variable kopieren
16: strPgmName = m_strProgToRun;
17:
18: // Programmname in Großbuchstaben umwandeln
19: strPgmName.MakeUpper();
20:
21: // Programm Paint gewählt?
22: if (strPgmName == "PAINT")
23: // Ja, Paint starten
24: WinExec("pbrush.exe", SW_SHOW);
25:
26: // Editor (Notepad) gewählt?
27: if (strPgmName == "EDITOR")
28: // Ja, Editor starten
29: WinExec("notepad.exe", SW_SHOW);
30:
31: // Solitär gewählt?
32: if (strPgmName == "SOLITÄR")
33: // Ja, Solitär starten
34: WinExec("sol.exe", SW_SHOW);
35:
36: ///////////////////////
37: // EIGENER CODE, ENDE
38: ///////////////////////
39: }

Wie zu erwarten, findet in dieser Funktion zunächst der Aufruf von UpdateData statt, um die Variablen mit den Werten der Steuerelemente im Fenster zu aktualisieren. Der nächste Teil erscheint allerdings ein wenig eigentümlich. Es wird eine neue CString- Variable deklariert und in diese der Wert des Kombinationsfeldes kopiert. Ist es wirklich notwendig, wenn der Wert bereits in einer CString-Variablen steht? Das hängt davon ab, wie sich Ihre Anwendung verhalten soll. Die nächste Codezeile enthält einen Aufruf der CString-Funktion MakeUpper, die den String in Großbuchstaben konvertiert. Wenn man die CString-Variable verwendet, die mit dem Kombinationsfeld verbunden ist, wird beim nächsten Aufruf von UpdateData mit dem Argument FALSE der Wert im Kombinationsfeld ebenfalls in Großbuchstaben angezeigt. Unter diesen Umständen ist das wahrscheinlich ein ungünstiger Zeitpunkt, und das Verhalten entspricht nicht den Vorstellungen. Deshalb kommt in der Funktion ein zusätzlicher CString zum Einsatz.

An die Umwandlung des Strings in Großbuchstaben schließt sich eine Folge von if- Anweisungen an, die den String mit den Namen der verschiedenen Programme vergleichen. Bei einer gefundenen Übereinstimmung ruft der Code die Funktion WinExec auf, um die betreffende Anwendung zu starten. Wenn Sie Ihre Anwendung jetzt kompilieren und ausführen, können Sie eine der Anwendungen aus der Dropdown-Liste auswählen und sie durch Klicken auf die Schaltfläche Programm starten öffnen.

In C und C++ ist der Unterschied zwischen einem einfachen Gleichheitszeichen (=) und einem doppelten Gleichheitszeichen (==) zu beachten. Das einfache Gleichheitszeichen führt eine Zuweisung des Wertes auf der rechten Seite des Gleichheitszeichens an die Variable auf der linken Seite durch. Steht auf der linken Seite des Gleichheitszeichens eine Konstante, wird das Programm nicht kompiliert, und Sie erhalten die Fehlermeldung, daß man keinen Wert der rechten Seite an eine Konstante auf der linken Seite zuweisen kann. Das doppelte Gleichheitszeichen ist für Vergleiche vorgesehen. Achten Sie darauf, das doppelte Gleichheitszeichen zu verwenden, wenn Sie zwei Werte miteinander vergleichen möchten. Wenn Sie in diesem Fall versehentlich das einfache Gleichheitszeichen verwenden, ändern Sie den Wert der Variablen auf der linken Seite. Hier liegt eine der größten Quellen für logische Fehler in C/C++-Programmen.

Die Funktion WinExec ist eine veraltete Windows-Funktion. Eigentlich sollte man statt dessen die Funktion CreateProcess verwenden. Allerdings weist die Funktion CreateProcess eine Reihe von Argumenten auf, die in dieser frühen Phase der Programmierung mit Visual C++ nicht so leicht zu verstehen sind. Die Funktion WinExec ist weiterhin verfügbar und als Makro implementiert, das die Funktion CreateProcess aufruft. Damit können Sie auf die wesentlich einfachere Funktion WinExec zurückgreifen, um eine andere Anwendung zu starten, wobei gesichert ist, daß Windows die eigentlich erwartete Funktion benutzt.

Die API-Funktion ShellExecute läßt sich ebenfalls für den Start einer anderen Anwendung einsetzen. Diese Funktion war ursprünglich vorgesehen, um Dateien zu öffnen oder zu drucken, man kann sie aber auch zum Starten anderer Programme nutzen.

Zusammenfassung

Heute haben Sie gelernt, wie man Standardsteuerelemente von Windows in einer Visual C++-Anwendung einsetzt. Es wurde gezeigt, wie man Variablen deklariert, sie mit den Steuerelementen verbindet und wie man die Werte der Variablen mit den Steuerelementen synchronisiert. Weiterhin haben Sie gelernt, wie man Steuerelemente manipuliert, indem man die Steuerelementobjekte mittels ihrer Objekt-ID abruft, und wie man das Steuerelement manipuliert, indem man es als Fenster behandelt. Als nächstes wurde auf die Tabulator-Reihenfolge der Steuerelemente in einer Anwendung eingegangen. Damit legt man die Richtung und Reihenfolge fest, in der der Benutzer durch eine Windows-Anwendung navigiert. Schließlich haben Sie gelernt, wie man die Funktionalität einer Anwendung mit den Steuerelementen im Anwendungsfenster verbindet, wobei die verschiedenen Aktionen ausgelöst werden, wenn der Benutzer mit den jeweiligen Steuerelementen interagiert. Als Bonus wurde gezeigt, wie man andere Windows-Anwendung aus der eigenen Anwendung heraus aufrufen kann.

Fragen und Antworten

Frage:
Nachdem ich die Objekt-IDs der Steuerelemente im Fenster festgelegt habe, weisen drei Steuerelemente dieselbe ID, IDC_STATIC, auf. Bei diesen Steuerelementen handelt es sich um den Text im oberen Teil des Fensters und die beiden Gruppenfelder. Die zwei anderen statischen Textsteuerelemente hatten zuerst die gleiche ID, bis ich sie geändert habe. Wieso haben diese Steuerelemente die gleiche ID, und warum mußte ich die IDs der beiden statischen Textsteuerelemente an dieser Stelle ändern?

Antwort:
Alle Steuerelemente, die normalerweise nicht für eine Benutzerinteraktion vorgesehen sind, beispielsweise statischer Text und Gruppenfelder, erhalten per Vorgabe die gleiche Objekt-ID. Das funktioniert, solange Ihre Anwendung keine Aktionen auf diesen Steuerelementen ausführen muß. Wenn Sie eine Interaktion mit einem dieser Steuerelemente beabsichtigen, wie es für den statischen Text mit den Aufforderungen für das Eingabefeld und das Kombinationsfeld geschehen ist, müssen Sie den betreffenden Steuerelementen eine eindeutige ID zuweisen. In diesem Fall war die eindeutige ID erforderlich, damit Sie das Steuerelementobjekt abrufen können, um das Steuerelement zu aktivieren/zu deaktivieren bzw. anzuzeigen/auszublenden. Ebenfalls müssen Sie eine eindeutige ID zuweisen, wenn Sie eine Variable mit einem Steuerelement verbinden möchten, um die Beschriftung auf dem Steuerelement dynamisch ändern zu können.

Frage:
Gibt es eine andere Möglichkeit, die Steuerelemente zu manipulieren, als die Steuerelementobjekte unter Verwendung ihrer Objekt-IDs abzurufen?

Antwort:
Man kann Variablen in der Kategorie Control deklarieren. Damit erhält man grundsätzlich ein Objekt, das die MFC-Klasse des Steuerelements darstellt, und man kann dann direkt das Steuerelement ändern und damit interagieren. Für das Steuerelement lassen sich dann alle Funktionen der Klasse CWnd aufrufen, wie Sie es beim Aktivieren/Deaktivieren bzw. Anzeigen/Ausblenden der Steuerelemente in Ihrer Anwendung vorgenommen haben. Sie können auch die Klassenmethoden der Steuerelemente aufrufen. Das bietet Ihnen die Möglichkeit, im Code spezielle Aufgaben für den jeweiligen Steuerelementtyp zu realisieren. Wenn Sie zum Beispiel dem Kombinationsfeld eine weitere Variable zuordnen und festlegen, daß es sich um eine Variable der Kategorie Control handelt, können Sie über diese Variable die Elemente in der Dropdown-Liste des Steuerelements hinzufügen.

Workshop

Kontrollfragen

1. Warum muß man die Tabulator-Reihenfolge der Steuerelemente im Anwendungsfenster festlegen?

2. Wie kann man eine Zugriffstaste in ein statisches Textfeld einbinden, das den Benutzer zum Eingabefeld oder Kombinationsfeld neben dem Textsteuerelement bringt?

3. Warum muß man den statischen Textfeldern vor dem Eingabefeld und den Kombinationsfeldern eindeutige Objekt-IDs zuweisen?

4. Warum muß man die Funktion UpdateData aufrufen, bevor man den Wert eines Steuerelements überprüft?

Übungen



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