vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 2

Tag 12

Symbolleisten und Statusleisten

Die bisher erstellten SDI- und MDI-Anwendungen verfügen nicht nur über Standardmenüs, sondern weisen auch einfache Symbolleisten auf, die mit den Menüs korrespondieren. Die Symbolleisten sind mit Standardfunktionen (Neu, Öffnen, Speichern, Drucken, Ausschneiden, Kopieren und Einfügen) ausgestattet, die sich in den Symbolleisten der meisten Windows-Anwendungen finden. Die Mehrzahl der Anwendungen beschränkt sich jedoch nicht auf diese vorgegebene Auswahl von Funktionen, sondern paßt die Symbolleisten an, um die konkrete Funktionalität der Anwendung widerzuspiegeln.

Neben den Symbolleisten verfügen die SDI- und MDI-Anwendungen über eine Statusleiste am unteren Rand des Anwendungsfensters, um eine textuelle Beschreibung der Symbolleistenschaltflächen und Menübefehle bereitzustellen. Die Statusleiste verfügt ebenfalls über Standardbereiche, die den Zustand der Feststelltasten für Großbuchstaben, Zahlen und Bildlauf anzeigen.

Heute lernen Sie insbesondere, wie man ...

Symbolleisten, Statusleisten und Menüs

Eine der treibenden Kräfte hinter der Entwicklung von grafischen Benutzeroberflächen wie Windows ist das Ziel, die Benutzerfreundlichkeit von Computern zu verbessern. In diesem Zusammenhang haben die Entwickler der Oberflächen festgelegt, daß alle Anwendungen mit einem Standardsatz von Menüs auszustatten sind und daß die Menüs in einer standardisierten Art und Weise organisiert sein sollen. Der Gestaltung des Betriebssystems Microsoft Windows liegt die gleiche Philosophie zugrunde, d.h., in den meisten Anwendungen kommt ein standardisierter Satz von Menüs zum Einsatz, die in einer standardisierten Reihenfolge angeordnet sind.

Mit der zunehmenden Verbreitung von Windows ereignete sich etwas Wundersames. Die Anwendungsentwickler stellten fest, daß neue Benutzer trotzdem noch Schwierigkeiten hatten, sich in neue Anwendungen einzuarbeiten, und daß fortgeschrittene Benutzer die Menüs zu umständlich fanden. Daraufhin erfanden die Anwendungsgestalter die Symbolleisten als Lösung für beide Probleme.

Eine Symbolleiste ist ein schmales Band, das an einem Fensterrahmen angebunden oder als unverankertes Dialogfeld im Anwendungsrahmen verschiebbar ist. Dieses Band (oder Dialogfeld) verfügt über eine Anzahl kleiner Schaltflächen, die mit Bildern »beschriftet« sind, die man als Alternative zu Menübefehlen verwenden kann. Die Anwendungsentwickler plazieren die am häufigsten benutzten Funktionen ihrer Anwendungen auf diesen Symbolleisten und versuchen, die Bilder auf den Schaltflächen möglichst so zu gestalten, daß der Benutzer die Funktionen ohne weiteres erkennen kann.

Nachdem sich die fortgeschrittenen Benutzer an die Symbolleistenschaltflächen gewöhnt hatten, traten die Symbolleisten ihren Siegeszug an. Allerdings hatten neue Benutzer immer noch Probleme, sich mit dem Zweck der Symbolleistenschaltflächen bekanntzumachen. Daraufhin setzten sich die Entwickler wieder ans Reißbrett, um neue Wege auszuknobeln, wie man neuen Benutzern den Umgang mit Symbolleistenschaltflächen erleichtern kann.

Heraus kam eine Lösung, bei der in einer Informationsleiste, die bereits viele Anwendungen am unteren Rand des Anwendungsfensters vorgesehen hatten, detaillierte Beschreibungen sowohl zu den Menüeinträgen als auch den Symbolleistenschaltflächen angezeigt wurden. Eine weitere Lösung war die Anzeige eines kleinen Hilfe-Popup- Fensters mit einer kurzen Beschreibung der Schaltfläche. Dieses Fenster erscheint, wenn man die Maus ein paar Sekunden über der jeweiligen Schaltfläche ruhen läßt. Die erste Lösung wurde als Statusleiste bekannt, die zweite als QuickInfo. Beide Verfahren sind in den meisten heutigen Windows-Anwendungen gängige Praxis.

Wenn Sie eigene Symbolleisten und Statusleisten in Ihren Anwendungen entwerfen und verwenden möchten, sollten Sie daran denken, daß Visual C++ eine Menge Unterstützung für Ihre Anstrengungen bereitstellt und sogar die Implementierung erleichtert. Immerhin haben selbst die Anwendungsentwickler von Microsoft den Vorreiter bei der Entwicklung dieser Elemente gespielt, und viele, wenn auch nicht alle, Windows-Anwendungen von Microsoft werden mit dem Visual C++ aus dem eigenen Hause entwickelt. Diese Tatsache ist sogar in den Tips und Tricks - die beim Start des Visual Studio erscheinen oder sich über das Hilfe-Menü aufrufen lassen - dokumentiert: »Wir haben es vor Ihnen verwendet! Visual C++ wurde mit Hilfe von Visual C++ entwickelt.« Und auch Sie sitzen heute in der ersten Reihe und erfahren, wie Sie eigene Symbolleisten und Statusleisten für Ihre Anwendungen erstellen.

Eine Symbolleiste entwerfen

Zur Einführung in das Thema Symbolleistenentwurf modifizieren wir die am Tag 10 erstellte SDI-Zeichenanwendung. Hier fügen wir eine Symbolleiste ein, mit der sich die Zeichenfarben auswählen lassen.

Auch wenn die heute verwendete Beispielanwendung eine Erweiterung der am Tag 10 erstellten Anwendung ist, wurden alle Namen für Dateien und Klassen von Tag10 in Toolbar geändert. Wenn Sie die Änderungen im Projekt von Tag 10 vornehmen und der nachstehende Text von Änderungen in der Klasse CToolbarDoc spricht, dann nehmen Sie die Änderungen in der Klasse CTag10Doc vor. Die Bearbeitung der Datei Toolbar.rc entspricht analog einer Bearbeitung der Datei Tag10.rc.

Wenn Sie lediglich ein paar zusätzliche Symbolleistenschaltflächen in die vom Anwendungs-Assistenten für eine SDI- oder MDI-Anwendung erzeugte Standardsymbolleiste aufnehmen möchten, können Sie die Symbolleiste im Symbolleisten-Editor (erreichbar über die Registerkarte Ressourcen des Arbeitsbereichs) von Visual C++ bearbeiten. Genau wie im Menü-Editor befindet sich am Ende der Symbolleiste ein leeres Feld, das Sie mit einer weiteren Symbolleistenschaltfläche ausgestalten können, wie es Abbildung 12.1 zeigt. Dazu brauchen Sie lediglich die leere Schaltfläche zu markieren und nach rechts ziehen, wenn ein Zwischenraum (ein Separator) zwischen ihr und der daneben liegenden Schaltfläche entstehen soll, oder die Schaltfläche an eine andere Position ziehen, wenn Sie die Schaltfläche verschieben möchten. Nachdem Sie die Schaltfläche auf der gewünschten Zielposition plaziert haben, zeichnen Sie ein Symbol auf die Schaltfläche, das deren Funktion charakterisiert, wenn man die Schaltfläche anklickt. Schließlich doppelklicken Sie auf die Schaltfläche in der Symbolleistenansicht, um das Eigenschaftsdialogfeld der Schaltfläche zu öffnen. Hier geben Sie der Schaltfläche die gleiche ID wie dem Menübefehl, der die betreffende Funktion auslöst. Sobald Sie Ihre Anwendung kompilieren und ausführen, haben Sie eine neue Symbolleistenschaltfläche, die den jeweiligen Menübefehl realisiert. Wenn Sie eine Symbolleistenschaltfläche entfernen möchten, ziehen Sie sie in der Symbolleistenansicht aus der Symbolleiste heraus.

Abbildung 12.1:
Der Symbolleisten-Editor

Eine neue Symbolleiste erstellen

Um eine neue Symbolleiste einzufügen, klicken Sie mit der rechten Maustaste auf den Ordner Toolbar und wählen Toolbar einfügen aus dem Kontextmenü. Daraufhin wird eine leere Symbolleiste mit einer einzigen leeren Schaltfläche erzeugt. Sobald Sie ein Symbol auf die jeweils leeren Schaltflächen in der Symbolleiste zeichnen, kommt eine weitere leere Schaltfläche am Ende der Symbolleiste hinzu.

Für unsere Zeichenanwendung füllen Sie acht Schaltflächen mit den acht verfügbaren Farben des Zeichenprogramms.

Nachdem Sie die Schaltflächen in der Symbolleiste mit Symbolen ausgestattet haben, doppelklicken Sie in der Symbolleistenansicht auf die erste Schaltfläche. Daraufhin erscheint das Dialogfeld Schaltfläche für Symbolleiste Eigenschaften.

Im Feld ID geben Sie die ID des Menübefehls ein, den die Schaltfläche realisieren soll (die ID können Sie auch aus der Dropdown-Liste auswählen). In das Feld Statuszeilentext tragen Sie die Beschreibung ein, die in der Statusleiste für diese Schaltfläche erscheinen soll. (Wenn Sie bereits eine Aufforderung für den Menübefehl eingegeben haben, ist in diesem Feld schon die Menübeschreibung enthalten.) Am Ende der Beschreibung für die Statusleiste fügen Sie die Zeichen \n und einen kurzen Text für die QuickInfo der Symbolleistenschaltfläche an.

In C/C++ steht die Zeichenfolge \n für den Befehl »neue Zeile beginnen«. Im Statuszeilentext für Symbolleistenschaltflächen und Menübefehle dient diese Zeichenfolge dazu, die Beschreibung der Menübefehle in der Statusleiste und die QuickInfos (die erscheinen, wenn man den Mauszeiger ein paar Sekunden über die Schaltfläche setzt) zu trennen. Die erste Zeile ist für die Beschreibung der Statusleiste vorgesehen, die zweite für den Text in den QuickInfos. Die Beschreibung für QuickInfos kommt nur bei Symbolleisten zum Einsatz, so daß man bei Menübefehlen ohne Symbolleistenäquivalente darauf verzichten kann.

Beispielsweise können Sie ID_COLOR_BLACK als ID und Zeichenfarbe Schwarz\nSchwarz als Statuszeilentext für die schwarze Schaltfläche auf der Symbolleiste, die Sie für Ihr Zeichenprogramm erstellen, festlegen, wie es Abbildung 12.2 verdeutlicht.

Abbildung 12.2:
Das Dialogfeld Schaltfläche für Symbolleiste Eigenschaften

Nachdem Sie den Entwurf der Symbolleiste fertiggestellt - die Schaltflächen mit Symbolen ausgestattet und die Eigenschaften für jede Schaltfläche festgelegt - haben, ändern Sie die ID der Symbolleiste. Im Arbeitsbereich klicken Sie mit der rechten Maustaste auf die neu hinzugefügte Symbolleiste und öffnen deren Eigenschaftsdialogfeld. Ändern Sie die ID der Symbolleiste in einen aussagekräftigen Namen.

Beispielsweise können Sie für die Symbolleiste Farben, die Sie für das Zeichenprogramm erstellen, die ID der Symbolleiste in IDR_TBCOLOR ändern.

Die Symbolleiste mit dem Anwendungsgerüst verbinden

In den bisherigen SDI- und MDI-Anwendungen haben Sie keinerlei Funktionalität hinzufügt, die eine Arbeit mit dem Rahmenfenster erfordert hätte. Jetzt, da die Symbolleiste mit dem Rahmen verbunden wird, müssen Sie den Code in diesem Modul hinzufügen und modifizieren. Wenn Sie die Klasse CMainFrame öffnen und zur Funktion OnCreate gehen, sehen Sie, wo die vorhandene Symbolleiste erzeugt und (weiter unten in der Funktion) mit dem Rahmen verbunden wird.

Bevor Sie die Symbolleiste mit dem Anwendungsgerüst verbinden können, müssen Sie zunächst eine Variable in die Klasse CMainFrame hinzufügen, um den Wert der neuen Symbolleiste aufzunehmen. Für diese Variable vom Typ CToolBar legen Sie den Zugriffsstatus Protected fest.

Um die Symbolleiste Farben in Ihre Zeichenanwendung aufzunehmen, klicken Sie mit der rechten Maustaste auf der Registerkarte Klassen des Arbeitsbereichs auf die Klasse CMainFrame. Wählen Sie Member-Variable hinzufügen aus dem Kontextmenü, und legen Sie den Variablentyp mit CToolBar, den Namen als m_wndColorBar und den Zugriff als Protected fest.

Jetzt schreiben Sie noch etwas Code in die Funktion OnCreate der Klasse CMainFrame, um die Symbolleiste hinzuzufügen und sie mit dem Gerüst zu verbinden. Übernehmen Sie die Modifikationen aus Listing 12.1, um die Symbolleiste Farben in Ihre Zeichenanwendung einzubauen.

Listing 12.1: Die modifizierte Funktion OnCreate der Klasse CMainFrame

1: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
2: {
3: if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
4: return -1;
5:
6: if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | ÂCBRS_TOP
7: | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
8: !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
9: {
10: TRACE0("Symbolleiste konnte nicht erstellt werden\n");
11: return -1; // Fehler bei Erstellung
12: }
13:
14: ///////////////////////
15: // EIGENER CODE, ANFANG
16: ///////////////////////
17:
18: // Symbolleiste Farben hinzufügen
19: int iTBCtlID;
20: int i;
21:
22: // Symbolleiste Farben erzeugen
23: if (!m_wndColorBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD |
24: WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS |
25: CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
26: !m_wndColorBar.LoadToolBar(IDR_TBCOLOR))
27: {
28: TRACE0("Symbolleiste konnte nicht erstellt werden\n");
29: return -1; // Fehler bei Erstellung
30: }
31: // Schaltfläche Schwarz auf der Symbolleiste suchen
32: iTBCtlID = m_wndColorBar.CommandToIndex(ID_COLOR_BLACK);
33: if (iTBCtlID >= 0)
34: {
35: // Schleife durch die Schaltflächen, um sie als Optionsfelder wirken Âzu lassen
36: for (i= iTBCtlID; i < (iTBCtlID + 8); i++)
37: m_wndColorBar.SetButtonStyle(i, TBBS_CHECKGROUP);
38: }
39:
40: ///////////////////////
41: // EIGENER CODE, ENDE
42: ///////////////////////
43:
44: if (!m_wndStatusBar.Create(this) ||
45: !m_wndStatusBar.SetIndicators(indicators,
46: sizeof(indicators)/sizeof(UINT)))
47: {
48: TRACE0("Statusleiste konnte nicht erstellt werden\n");
49: return -1; // Fehler bei Erstellung
50: }
51:
52: // ZU ERLEDIGEN: Löschen Sie diese drei Zeilen, wenn Sie nicht wollen, Âdass die Symbolleiste
53: // andockbar ist.
54: m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
55:
56: ///////////////////////
57: // EIGENER CODE, ANFANG
58: ///////////////////////
59:
60: // Andocken für Symbolleiste Farben aktivieren
61: m_wndColorBar.EnableDocking(CBRS_ALIGN_ANY);
62:
63: ///////////////////////
64: // EIGENER CODE, ENDE
65: ///////////////////////
66:
67: EnableDocking(CBRS_ALIGN_ANY);
68: DockControlBar(&m_wndToolBar);
69:
70: ///////////////////////
71: // EIGENER CODE, ANFANG
72: ///////////////////////
73:
74: // Symbolleiste Farben andocken
75: DockControlBar(&m_wndColorBar);
76:
77: ///////////////////////
78: // EIGENER CODE, ENDE
79: ///////////////////////
80:
81: return 0;
82: }

Die Symbolleiste erstellen

Der erste hinzugefügte Codeabschnitt

23: if (!m_wndColorBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD |
24: WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS |
25: CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
26: !m_wndColorBar.LoadToolBar(IDR_TBCOLOR))

enthält zwei separate Funktionen, die für das Erstellen einer Symbolleiste erforderlich sind. Die erste Funktion, CreateEx, erstellt die Symbolleiste selbst, während die zweite Funktion, LoadToolBar, die Symbolleiste lädt, die Sie im Symbolleisten-Editor entworfen haben. Die zweite Funktion, LoadToolBar, erfordert ein Argument: die ID für die zu erzeugende Symbolleiste.

Der Funktion CreateEx können Sie mehrere Argumente übergeben. Das erste - und einzige erforderliche - Argument ist ein Zeiger auf das übergeordnete Fenster. In diesem Fall (der den Normalfall darstellt) ist dieses Argument ein Zeiger auf das Rahmenfenster, mit dem die Symbolleiste verbunden wird.

Das zweite Argument gibt den Stil der Steuerelemente in der zu erzeugenden Symbolleiste an. Es stehen mehrere Stile zur Auswahl, von denen einige mit den beiden letzten Versionen des Internet Explorer eingeführt wurden. Tabelle 12.1 listet die verfügbaren Stile auf.

Tabelle 12.1: Stile für die Steuerelemente von Symbolleisten

Stil

Beschreibung

TBSTYLE_ALTDRAG

Erlaubt dem Benutzer, die Symbolleiste bei niedergehaltener (Alt)-Taste zu verschieben.

TBSTYLE_CUSTOMERASE

Generiert eine NM_CUSTOMDRAW-Nachricht, wenn man die Symbolleiste und den Schaltflächenhintergrund löscht. Damit kann der Programmierer wählen, wann und ob das Löschen des Hintergrunds zu steuern ist.

TBSTYLE_FLAT

Erzeugt eine flache Symbolleiste. Der Schaltflächentext erscheint unter dem Bitmap.

TBSTYLE_LIST

Der Schaltflächentext steht rechts neben dem Bitmap.

TBSTYLE_REGISTERDROP

Beim Drag & Drop von Objekten auf Symbolleistenschaltflächen verwendet.

TBSTYLE_TOOLTIPS

Erzeugt ein QuickInfo-Steuerelement, in dem man eine Beschreibung der Symbolleistenschaltflächen anzeigen kann.

TBSTYLE_TRANSPARENT

Erzeugt eine transparente Symbolleiste.

TBSTYLE_WRAPABLE

Erzeugt eine Symbolleiste, die aus mehreren Schaltflächenreihen bestehen kann.

Das dritte Argument gibt den Stil der Symbolleiste selbst an. Dieses Argument ist normalerweise eine Kombination von Fenster- und Steuerelementstilen. In der Regel verwendet man nur zwei oder drei Fensterstile, während es sich beim Rest der Symbolleistenstile um Steuerelementstile handelt. In Tabelle 12.2 finden Sie die üblicherweise verwendeten Symbolleistenstile.

Tabelle 12.2: Stile für Symbolleisten

Stil

Beschreibung

WS_CHILD

Die Symbolleiste wird als untergeordnetes Fenster geöffnet.

WS_VISIBLE

Die Symbolleiste ist sichtbar, wenn sie erzeugt wird.

CBRS_ALIGN_TOP

Die Symbolleiste läßt sich am oberen Rand des Anzeigebereichs im Rahmenfenster verankern.

CBRS_ALIGN_BOTTOM

Die Symbolleiste läßt sich am unteren Rand des Anzeigebereichs im Rahmenfenster verankern.

CBRS_ALIGN_LEFT

Die Symbolleiste läßt sich an der linken Seite des Anzeigebereichs im Rahmenfenster verankern.

CBRS_ALIGN_RIGHT

Die Symbolleiste läßt sich an der rechten Seite des Anzeigebereichs im Rahmenfenster verankern.

CBRS_ALIGN_ANY

Die Symbolleiste läßt sich an einer beliebigen Seite des Anzeigebereichs im Rahmenfenster verankern.

CBRS_BORDER_TOP

Setzt einen Rahmen am oberen Rand der Symbolleiste, wenn der obere Rand der Symbolleiste nicht verankert ist.

CBRS_BORDER_BOTTOM

Setzt einen Rahmen am unteren Rand der Symbolleiste, wenn der obere Rand der Symbolleiste nicht verankert ist.

CBRS_BORDER_LEFT

Setzt einen Rahmen an den linken Rand der Symbolleiste, wenn der obere Rand der Symbolleiste nicht verankert ist.

CBRS_BORDER_RIGHT

Setzt einen Rahmen an den rechten Rand der Symbolleiste, wenn der obere Rand der Symbolleiste nicht verankert ist.

CBRS_FLOAT_MULTI

Gestattet mehrere unverankerte Symbolleisten in einem einzelnen Minirahmenfenster.

CBRS_TOOLTIPS

Bewirkt die Anzeige von QuickInfos für die Symbolleistenschaltflächen.

CBRS_FLYBY

Bewirkt die gleichzeitige Aktualisierung des Textes in der Statusleiste für Symbolleistenschaltflächen und QuickInfos.

CBRS_GRIPPER

Zeichnet eine Griffleiste auf die Symbolleiste.

Das vierte Argument, welches Sie in Ihrem Code nicht bereitstellen, gibt die Größe der Symbolleistenrahmen an. Dieses Argument wird als normale CRect-Klasse übergeben, um die gewünschte Länge und Höhe für die Symbolleiste bereitzustellen. Der Standardwert ist 0 für alle Abmessungen des Rechtecks, so daß die Symbolleiste keine Rahmen aufweist.

Das fünfte und letzte Argument, das Sie ebenfalls nicht in Ihrem Code verwenden, stellt die ID des untergeordneten Symbolleistenfensters bereit. Der Standardwert lautet AFX_IDW_TOOLBAR, man kann aber alle definierten IDs verwenden, die für die Symbolleiste erforderlich sind oder geeignet erscheinen.

Die Stile der Schaltflächen festlegen

An das Erstellen der Symbolleiste schließt sich ein etwas eigentümlicher Codeabschnitt an:

31: // Schaltfläche Schwarz auf der Symbolleiste suchen
32: iTBCtlID = m_wndColorBar.CommandToIndex(ID_COLOR_BLACK);
33: if (iTBCtlID >= 0)
34: {
35: // Schleife durch die Schaltflächen, um sie als Optionsfelder wirken Âzu lassen
36: for (i= iTBCtlID; i < (iTBCtlID + 8); i++)
37: m_wndColorBar.SetButtonStyle(i, TBBS_CHECKGROUP);
38: }

Die erste Zeile in diesem Codefragment verwendet die Symbolleistenfunktion CommandToIndex , um die Steuerelementnummer der Schaltfläche ID_COLOR_BLACK zu ermitteln. Wenn Sie die Symbolleiste in der Reihenfolge der Farben, wie sie im Menü erscheinen, erstellt haben, sollte es sich dabei um das erste Steuerelement mit einem Index von 0 handeln. Es empfiehlt sich, den Index aller Symbolleistenschaltflächen, die man ändern muß, mit der Funktion CommandToIndex zu ermitteln, einfach deshalb, weil man nicht immer davon ausgehen kann, daß die Schaltfläche an der erwarteten Position sitzt. Die Funktion liefert den Index des angegebenen Symbolleistensteuerelements zurück. Diesen Wert verwendet man als Ausgangspunkt, um den Schaltflächenstil der Farbschaltflächen festzulegen.

In der Schleife, in der Sie alle acht Farbschaltflächen der Symbolleiste durchlaufen, steuern Sie mit der Funktion SetButtonStyle das Verhalten der Symbolleistenschaltflächen. Das erste Argument an diese Funktion ist der Index der Schaltfläche, die zu ändern ist. Das zweite Argument gibt den Stil für die betreffende Schaltfläche an. In diesem Fall legen wir fest, daß alle Schaltflächen den Stil TBBS_CHECKGROUP aufweisen. Damit verhalten sich die Schaltflächen wie Optionsfelder, wobei nur eine Schaltfläche in der Gruppe zu einem bestimmten Zeitpunkt ausgewählt sein kann. Die Liste der verfügbaren Schaltflächenstile gibt Tabelle 12.3 wieder.

Tabelle 12.3: Stile für Symbolleistenschaltflächen

Stil

Beschreibung

TBSTYLE_AUTOSIZE

Die Breite der Schaltfläche wird nach dem Text auf der Schaltfläche berechnet.

TBSTYLE_BUTTON

Erzeugt eine Standardschaltfläche.

TBSTYLE_CHECK

Erzeugt eine Schaltfläche, die sich wie ein Kontrollkästchen verhält und zwischen dem gedrückten und nicht gedrückten Zustand umschaltet.

TBSTYLE_CHECKGROUP

Erzeugt eine Schaltfläche, die sich wie ein Optionsfeld verhält. Die Schaltfläche bleibt im gedrückten Zustand, bis eine andere Schaltfläche in der Gruppe betätigt wird. Es handelt sich hier eigentlich um eine Kombination der Schaltflächenstile TBSTYLE_CHECK und TBSTYLE_GROUP.

TBSTYLE_DROPDOWN

Erzeugt eine Schaltfläche in der Art einer Dropdown-Liste.

TBSTYLE_GROUP

Erstellt eine Schaltfläche, die gedrückt bleibt, bis eine andere Schaltfläche in der Gruppe gedrückt wird.

TBSTYLE_NOPREFIX

Der Schaltflächentext weist kein zugeordnetes Präfix auf.

TBSTYLE_SEP

Erzeugt einen Separator, d.h. eine kleine Lücke zwischen den Schaltflächen zu beiden Seiten.

Die Symbolleiste verankern

Der letzte Codeabschnitt, den Sie in die Funktion OnCreate der Klasse CMainFrame aufgenommen haben, sieht folgendermaßen aus:

60: // Andocken für Symbolleiste Farben aktivieren
61: m_wndColorBar.EnableDocking(CBRS_ALIGN_ANY);
...
67: EnableDocking(CBRS_ALIGN_ANY); // (Vom Anwendungs-Assistenten generierte ÂZeile)
...
73:
74: // Symbolleiste Farben andocken
75: DockControlBar(&m_wndColorBar);

In der ersten Zeile steht der Aufruf der Funktion EnableDocking. Diese Funktion erlaubt das Verankern der Symbolleiste mit dem Rahmenfenster. Der an diese Symbolleistenfunktion übergebene Wert muß mit dem Wert übereinstimmen, der im nachfolgenden Aufruf der Funktion EnableDocking für das Rahmenfenster übergeben wird. Die verfügbaren Werte für diese Funktionen sind in Tabelle 12.4 aufgeführt. Mit diesen Funktionen lassen sich die Rahmen der Symbolleiste und das Rahmenfenster für das Andocken aktivieren. Ruft man diese Funktionen nicht auf, kann man die Symbolleiste nicht mit dem Rahmenfenster verankern. Übergibt man eine bestimmte Seite für das Andocken in diesen Funktionen, und die Seite entspricht nicht diesem Wert, läßt sich die Symbolleiste ebenfalls nicht am Rahmenfenster verankern.

Tabelle 12.4: Seiten, an die man Symbolleisten verankern kann

Stil

Beschreibung

CBRS_ALIGN_TOP

Die Symbolleiste läßt sich am oberen Rand des Anzeigebereichs im Rahmenfenster verankern.

CBRS_ALIGN_BOTTOM

Die Symbolleiste läßt sich am unteren Rand des Anzeigebereichs im Rahmenfenster verankern.

CBRS_ALIGN_LEFT

Die Symbolleiste läßt sich an der linken Seite des Anzeigebereichs des Rahmenfensters verankern.

CBRS_ALIGN_RIGHT

Die Symbolleiste läßt sich an der rechten Seite des Anzeigebereichs des Rahmenfensters verankern.

CBRS_ALIGN_ANY

Die Symbolleiste läßt sich an einer beliebigen Seite des Anzeigebereichs im Rahmenfenster verankern.

CBRS_FLOAT_MULTI

Gestattet mehrere unverankerte Symbolleisten in einem einzelnen Minirahmenfenster.

0

Die Symbolleiste läßt sich nicht mit dem Rahmen verankern.

Als letzte Funktion wurde die Fensterfunktion DockControlBar hinzugefügt, der die Adresse der Symbolleistenvariablen übergeben wird. Diese Funktion verankert die Symbolleiste physisch mit dem Rahmenfenster. Da der gesamte Code in der Funktion OnCreate für das Rahmenfenster erscheint, wird die Symbolleiste verankert, bevor der Benutzer das Fenster oder die Symbolleiste zu Gesicht bekommt.

Nachdem Sie nun den gesamten Code in die Funktion OnCreate der Klasse CMainFrame aufgenommen haben, können Sie Ihre Anwendung kompilieren und ausführen. Sie finden eine funktionsfähige Symbolleiste Farben vor, über die sich die Zeichenfarbe auswählen läßt (siehe Abbildung 12.3).

Abbildung 12.3:
Die Symbolleiste Farben im Zeichenprogramm

Die Sichtbarkeit der Symbolleiste steuern

Nunmehr verfügen Sie über eine Symbolleiste Farben, die Sie mit dem Rahmen Ihres Zeichenprogramms verankern können. Es wäre schön, wenn man die Symbolleiste genauso über das Menü Ansicht anzeigen und ausblenden könnte, wie es mit der Standardsymbolleiste und der Statusleiste möglich ist. Diese Funktionalität läßt sich recht einfach implementieren, aber es funktioniert nicht unbedingt so, wie Sie es vielleicht erwarten.

Als erstes ist ein Menübefehl hinzuzufügen, um die Sichtbarkeit der Farbpalette umzuschalten. Diese Aufgabe erledigen Sie über den Menü-Editor, mit dem Sie einen neuen Menübefehl in das Menü Ansicht aufnehmen. Legen Sie die Eigenschaften des Menüs gemäß Tabelle 12.5 fest.

Tabelle 12.5: Eigenschaften des Menübefehls Farbpalette

Eigenschaft

Einstellung

ID

ID_VIEW_COLORBAR

Titel

&Farbpalette

Statuszeilentext

Blendet die Farbpalette ein oder aus\nFarbpalette ein/aus

Das Menü aktualisieren

Um zu ermitteln, ob die Symbolleiste sichtbar oder ausgeblendet ist, kann man den aktuellen Stil der Symbolleiste lesen und das Stilflag WS_VISIBLE ausmaskieren. Wenn das Flag im aktuellen Symbolleistenstil enthalten ist, ist die Symbolleiste sichtbar. Indem man diese Auswertung in die Funktion SetCheck in der Behandlungsroutine UPDATE_COMMAND_UI schreibt, läßt sich das Kontrollhäkchen neben dem Menüeintrag für die Farbpalette umschalten.

Diese Funktionalität läßt sich im Zeichenprogramm mit einer Behandlungsroutine für das Ereignis UPDATE_COMMAND_UI des Menüs ID_VIEW_COLORBAR realisieren. Achten Sie darauf, diese Behandlungsroutine in die Klasse CMainFrame aufzunehmen. In die Funktion schreiben Sie den Code von Listing 12.2.

Listing 12.2: Die Funktion OnUpdateViewColorbar der Klasse CMainFrame

1: void CMainFrame::OnUpdateViewColorbar(CCmdUI* pCmdUI)
2: {
3: // TODO: Code für die Befehlsbehandlungsroutine zum Aktualisieren der ÂBenutzeroberfläche hier einfügen
4: ///////////////////////
5: // EIGENER CODE, ANFANG
6: ///////////////////////
7:
8: // Zustand der Farbpalette prüfen
9: pCmdUI->SetCheck(((m_wndColorBar.GetStyle() & WS_VISIBLE) != 0));
10:
11: ///////////////////////
12: // EIGENER CODE, ENDE
13: ///////////////////////
14: }

Die Sichtbarkeit der Symbolleiste umschalten

Da die Klasse CToolBar von der Klasse CWnd (über die Klasse CControlBar) abgeleitet ist, könnte man meinen, daß man die Funktion ShowWindow auf der Symbolleiste selbst aufrufen kann, um die Symbolleiste anzuzeigen und auszublenden. Das ist zwar möglich, aber der Hintergrund für die Symbolleiste wird nicht zusammen mit der Symbolleiste ausgeblendet. Der Benutzer stellt lediglich fest, daß die Symbolleistenschaltflächen erscheinen und verschwinden. (Natürlich ist das die Wirkung, die Sie erzielen möchten, aber Ihre Benutzer werden davon nicht sehr angetan sein.)

Statt dessen greifen Sie auf eine Funktion ShowControlBar für das Rahmenfenster zurück, um die Symbolleiste anzuzeigen und auszublenden. Diese Funktion übernimmt drei Argumente. Das erste Argument ist die Adresse für die Symbolleistenvariable. Das zweite Argument ist ein Boolescher Wert, der angibt, ob die Symbolleiste anzuzeigen ist. (TRUE zeigt die Symbolleiste an, FALSE blendet sie aus.) Schließlich spezifiziert das dritte Argument, ob die Symbolleiste verzögert erscheinen soll. (TRUE zeigt die Symbolleiste verzögert, FALSE sofort an.)

Nachdem eine Symbolleiste ein- oder ausgeschaltet ist, müssen Sie eine weitere Funktion für das Rahmenfenster, RecalcLayout, aufrufen. Diese Funktion bewirkt, daß der Rahmen alle Symbolleisten, Statusleisten und alles innerhalb des Rahmenbereichs neu positioniert. Diese Funktion ist dafür verantwortlich, daß sich die Symbolleiste Farben nach oben oder unten verschiebt, wenn Sie die Standardsymbolleiste ein- und ausschalten.

Diese Funktionalität nehmen Sie in Ihr Zeichenprogramm mit Hilfe einer Behandlungsfunktion für das Ereignis COMMAND des Menübefehls ID_VIEW_COLORBAR auf. Achten Sie darauf, daß Sie diese Behandlungsfunktion in die Klasse CMainFrame aufnehmen. In die Funktion schreiben Sie den Code aus Listing 12.3.

Listing 12.3: Die Funktion OnViewColorbar der Klasse CMainFrame

1: void CMainFrame::OnViewColorbar()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8: BOOL bVisible;
9:
10: // Zustand der Farbpalette prüfem
11: bVisible = ((m_wndColorBar.GetStyle() & WS_VISIBLE) != 0);
12:
13: // Symbolleiste Farben umschalten
14: ShowControlBar(&m_wndColorBar, !bVisible, FALSE);
15: // Elemente im Rahmenfenster neu anordnen
16: RecalcLayout();
17:
18: ///////////////////////
19: // EIGENER CODE, ENDE
20: ///////////////////////
21: }

Wenn Sie Ihre Anwendung jetzt kompilieren und ausführen, sollten Sie die Symbolleiste Farben über das Menü Ansicht ein- und ausschalten können.

Die Symbolleiste mit einem Kombinationsfeld ausstatten

Mittlerweile ist es üblich, daß die Symbolleisten einer Anwendung neben einfachen Schaltflächen auch noch andere Elemente enthalten. Sehen Sie sich zum Beispiel das Visual Studio an. Hier finden Sie Kombinationsfelder, die Ihnen die Navigation durch den Code erlauben, indem Sie die Klasse, die ID und die zu bearbeitende Funktion einfach über die Symbolleiste auswählen. Wie fügt man nun ein Kombinationsfeld in eine Symbolleiste ein? Der Symbolleisten-Editor stellt es nicht zur Verfügung. Hier finden Sie nur Schaltflächen, auf die Sie Symbole zeichnen können. Mit den Assistenten von Visual C++ lassen sich keine Kombinationsfelder in Symbolleisten aufnehmen. Zu diesem Zweck müssen Sie ein wenig C++-Code schreiben.

Als Einstieg fügen Sie ein Kombinationsfeld in die Symbolleiste Farben ein, die Sie gerade erstellt haben. Mit dem Kombinationsfeld wählt der Benutzer die Breite des Zeichenstifts aus. (Wenn Sie die Unterstützung für unterschiedliche Zeichenbreiten gemäß Übung am Ende von Tag 10 noch nicht realisiert haben, sollten Sie das jetzt nachholen.)

Die Projektressourcen bearbeiten

Um ein Kombinationsfeld in die Symbolleiste aufzunehmen, ist zuerst das zu tun, was Ihnen Visual C++ verweigert. Sie müssen die Ressourcendatei selbst bearbeiten. Über das Visual Studio für Visual C++ ist das nicht möglich. Wenn Sie versuchen, die Ressourcendatei im Visual Studio zu öffnen, gelangen Sie unweigerlich auf die Registerkarte Ressourcen des Arbeitsbereichs, wo die verschiedenen Ressourcen-Editoren untergebracht sind. Nein, Sie müssen diese Datei in einem anderen Editor, wie etwa dem normalen Windows-Editor, bearbeiten.

Schließen Sie Visual C++. Nur so läßt sich garantieren, daß Sie nicht über Ihre Änderungen schreiben. Öffnen Sie den Editor, und gehen Sie in Ihr Projektverzeichnis. Öffnen Sie die Ressourcendatei, die nach dem Projekt benannt ist und eine .rc-Erweiterung aufweist. Blättern Sie in der Datei nach unten bis zu den Symbolleistendefinitionen. (Sie können nach dem Wort »Toolbar« suchen.) Dann gehen Sie ans Ende der Symbolleistendefinition und fügen zwei Separatorlinien am unteren Rand der Symbolleistendefinition ein.

In Ihrer Zeichenanwendung müssen Sie zum Beispiel in das Projektverzeichnis Toolbar gehen und die Datei Toolbar.rc öffnen. (Falls Sie diese Symbolleisten in die MDI- Zeichenanwendung einfügen, wäre das die Datei Tag11.rc.) Suchen Sie nach dem Symbolleistenabschnitt, und fügen Sie dann zwei SEPARATOR-Zeilen unmittelbar vor dem Ende des Abschnitts IDR_TBCOLOR ein, wie es Listing 12.4 zeigt. Dann speichern Sie die Datei, verlassen den Editor, starten Visual C++ erneut und laden wieder das Projekt.

Listing 12.4: Die modifizierte Ressourcendatei des Projekts (Toolbar.rc)

1: /////////////////////////////////////////////////////////////////////////////
2: //
3: // Toolbar
4: //
5:
6: IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15
7: BEGIN
8: BUTTON ID_FILE_NEW
9: BUTTON ID_FILE_OPEN
10: BUTTON ID_FILE_SAVE
11: SEPARATOR
12: BUTTON ID_EDIT_CUT
13: BUTTON ID_EDIT_COPY
14: BUTTON ID_EDIT_PASTE
15: SEPARATOR
16: BUTTON ID_FILE_PRINT
17: BUTTON ID_APP_ABOUT
18: END
19:
20: IDR_TBCOLOR TOOLBAR DISCARDABLE 16, 15
21: BEGIN
22: BUTTON ID_COLOR_BLACK
23: BUTTON ID_COLOR_BLUE
24: BUTTON ID_COLOR_GREEN
25: BUTTON ID_COLOR_CYAN
26: BUTTON ID_COLOR_RED
27: BUTTON ID_COLOR_MAGENTA
28: BUTTON ID_COLOR_YELLOW
29: BUTTON ID_COLOR_WHITE
30: SEPARATOR
31: SEPARATOR
32: END

Die beiden SEPARATOR-Zeilen haben Sie in die Symbolleistendefinition aufgenommen, damit der zweite Separator als Platzhalter für das Kombinationsfeld dienen kann, das Sie in die Symbolleiste einbauen wollen. Es gibt zwei Gründe dafür, daß Sie diese Bearbeitung manuell erledigen müssen und nicht den Symbolleisten-Editor von Visual C++ bemühen können. Erstens erlaubt der Symbolleisten-Editor nicht, daß man mehrere Separatoren an das Ende der Symbolleiste anfügt. Zweitens: Wenn Sie nichts anderes nach dem Separator an das Ende der Symbolleiste anfügen, nimmt der Symbolleisten-Editor einen Fehler an und entfernt den Separator. Mit anderen Worten: Mit dem Symbolleisten-Editor von Visual C++ läßt sich kein Platzhalter für das Kombinationsfeld in die Symbolleiste einbauen.

Als nächstes sind die Textzeichenfolgen hinzuzufügen, die Sie in das Kombinationsfeld laden. Um diese Strings aufzunehmen, öffnen Sie die Zeichenfolgentabelle auf der Registerkarte Ressourcen des Arbeitsbereichs. Hier finden Sie alle Strings, die Sie als Statuszeilentext in verschiedenen Eigenschaftsdialogfeldern eingegeben haben. Diese Tabelle enthält eine Anzahl von IDs, die Werte dieser IDs und die Strings, die mit diesen IDs verbunden sind (siehe Abbildung 12.4). Die Strings, die Sie in das Kombinationsfeld eintragen möchten, müssen Sie in die Zeichenfolgentabelle schreiben. Jede Zeile in der Dropdown-Liste muß über eine eindeutige ID und einen Eintrag in der Zeichenfolgentabelle verfügen.

Abbildung 12.4:
Der Zeichenfolgen-Editor

Um zum Beispiel die Strings für das Kombinationsfeld hinzuzufügen, das Sie in die Symbolleiste Farben einbauen möchten, wählen Sie entweder Einfügen / Neue Zeichenfolge oder klicken mit der rechten Maustaste auf die Zeichenfolgentabelle und wählen Neue Zeichenfolge aus dem Kontextmenü.

Im Eigenschaftsdialogfeld des Strings legen Sie die ID für den String fest und geben dann den String so ein, wie er in der Dropdown-Liste erscheinen soll. Schließen Sie das Eigenschaftsdialogfeld, um den String hinzuzufügen. Für die Strings im Kombinationsfeld Breite, das Sie in die Symbolleiste Farben aufnehmen, tragen Sie die Strings gemäß Tabelle 12.6 ein.

Tabelle 12.6: Strings für das Kombinationsfeld Breite in der Symbolleiste

ID

Titel

IDS_WIDTH_VTHIN

Sehr dünn

IDS_WIDTH_THIN

Dünn

IDS_WIDTH_MEDIUM

Mittel

IDS_WIDTH_THICK

Dick

IDS_WIDTH_VTHICK

Sehr dick

Das Kombinationsfeld für die Symbolleiste erstellen

Bevor Sie das Kombinationsfeld in die Symbolleiste Farben aufnehmen können, müssen Sie eine Variable für das Kombinationsfeld erzeugen. Da sich das Kombinationsfeld nicht über die Editoren hinzufügen läßt, müssen Sie es als Variable in die Klasse CMainFrame aufnehmen.

Die Variable für das Kombinationsfeld nehmen Sie über die Registerkarte Klassen des Arbeitsbereichs in die Hauptrahmenklasse für die Symbolleiste Farben auf. Klicken Sie mit der rechten Maustaste auf die Klasse CMainFrame, und wählen Sie dann Member- Variable hinzufügen aus dem Kontextmenü. Legen Sie den Variablentyp als CComboBox , den Namen als m_ctlWidth und den Zugriff als Protected fest.

Nachdem Sie die Variable für das Kombinationsfeld in die Hauptrahmenklasse aufgenommen haben, sind verschiedene Aufgaben zu erledigen, wenn die Symbolleiste erzeugt wurde:

1. Die Breite und die ID des Platzhalters für das Kombinationsfeld in der Symbolleiste auf die Breite und die ID des Kombinationsfelds setzen.

2. Die Position des Platzhalters in der Symbolleiste ermitteln und danach Größe und Lage des Kombinationsfelds festlegen.

3. Das Kombinationsfeld erzeugen. Dabei die Symbolleiste als übergeordnetes Fenster des Kombinationsfelds spezifizieren.

4. Die Strings in die Dropdown-Liste des Kombinationsfelds laden.

Damit diese Abläufe einigermaßen übersichtlich bleiben, empfiehlt es sich, das Erstellen der Symbolleiste Farben in einer eigenen Funktion zu realisieren, die sich aus der Funktion OnCreate der Hauptrahmenklasse aufrufen läßt. Um diese Funktion zu erzeugen, klicken Sie im Arbeitsbereich mit der rechten Maustaste auf die Klasse CMainFrame und wählen Member-Funktion hinzufügen aus dem Kontextmenü. Legen Sie den Funktionstyp mit BOOL, die Funktionsdeklaration als CreateColorBar und den Zugriffsstatus als Public fest. In die Funktion schreiben Sie den Code von Listing 12.5.

Listing 12.5: Die Funktion CreateColorBar der Klasse CMainFrame

1: BOOL CMainFrame::CreateColorBar()
2: {
3: int iTBCtlID;
4: int i;
5:
6: if (!m_wndColorBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | ÂCBRS_TOP
7: | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
8: !m_wndColorBar.LoadToolBar(IDR_TBCOLOR))
9: {
10: TRACE0("Symbolleiste konnte nicht erstellt werden\n");
11: return FALSE; // Fehler bei Erstellung
12: }
13: iTBCtlID = m_wndColorBar.CommandToIndex(ID_COLOR_BLACK);
14: if (iTBCtlID >= 0)
15: {
16: for (i= iTBCtlID; i < (iTBCtlID + 8); i++)
17: m_wndColorBar.SetButtonStyle(i, TBBS_CHECKGROUP);
18: }
19: // Kombinationsfeld hinzufügen
20: int nWidth = 100;
21: int nHeight = 125;
22:
23: // Platzhalter des Kombinationsfelds konfigurieren
24: m_wndColorBar.SetButtonInfo(9, IDC_CBWIDTH, TBBS_SEPARATOR, nWidth);
25:
26: // Höhe der Farbpalette ermitteln
27: CRect rect;
28: m_wndColorBar.GetItemRect(9, &rect);
29: rect.bottom = rect.top + nHeight;
30:
31: // Kombinationsfeld erzeugen
32: m_ctlWidth.Create(WS_CHILD | WS_VISIBLE | WS_VSCROLL |
33: CBS_DROPDOWNLIST, rect, &m_wndColorBar, IDC_CBWIDTH);
34:
35: // Kombinationsfeld füllen
36: CString szStyle;
37: if (szStyle.LoadString(IDS_WIDTH_VTHIN))
38: m_ctlWidth.AddString((LPCTSTR)szStyle);
39: if (szStyle.LoadString(IDS_WIDTH_THIN))
40: m_ctlWidth.AddString((LPCTSTR)szStyle);
41: if (szStyle.LoadString(IDS_WIDTH_MEDIUM))
42: m_ctlWidth.AddString((LPCTSTR)szStyle);
43: if (szStyle.LoadString(IDS_WIDTH_THICK))
44: m_ctlWidth.AddString((LPCTSTR)szStyle);
45: if (szStyle.LoadString(IDS_WIDTH_VTHICK))
46: m_ctlWidth.AddString((LPCTSTR)szStyle);
47:
48: return TRUE;
49: }

Zeile 24 von Listing 12.5 gibt an, daß das Kombinationsfeld mit der Objekt-ID IDC_CBWIDTH zu erstellen ist. Diese Objekt-ID kennzeichnet das Kombinationsfeld, wenn es eine Ereignisnachricht an die Anwendung sendet oder wenn man festlegen muß, welcher Listeneintrag im Bearbeitungsfeld anzuzeigen ist. Allerdings existiert diese Objekt-ID nicht in Ihrer Anwendung. Bevor Sie die Anwendung kompilieren können, müssen Sie diese ID zu den Projektressourcen-IDs hinzufügen, wie Sie es am Tag 4 bei der Behandlung von Timern kennengelernt haben. Gehen Sie dazu im Arbeitsbereich auf die Registerkarte Ressourcen. Markieren Sie den Beginn des Ressourcenbaumes, und klicken Sie mit der rechten Maustaste, um das Kontextmenü einzublenden. Wählen Sie Ressourcensymbole aus dem Kontextmenü, und fügen Sie die Objekt-ID IDC_CBWIDTH hinzu. Vergewissern Sie sich, daß Sie für die neue Objekt-ID einen eindeutigen numerischen Wert vergeben, damit keine Konflikte mit anderen Objekten Ihrer Anwendung auftreten.

Den Platzhalter konfigurieren

Nachdem die Symbolleiste erstellt und die Symbolleisteneigenschaften festgelegt sind, konfigurieren Sie als nächstes den Separator, der als Platzhalter für das zu erzeugende Kombinationsfeld dient. Dazu verwenden Sie die Symbolleistenfunktion SetButtonInfo wie folgt:

m_wndColorBar.SetButtonInfo(9, IDC_CBWIDTH, TBBS_SEPARATOR, nWidth);

Diese Funktion übernimmt vier Argumente. Das erste gibt den aktuellen Index des Steuerelements in der Symbolleiste an - in diesem Fall das zehnte Steuerelement in der Symbolleiste (acht Farbschaltflächen und zwei Separatoren). Im zweiten Argument übergibt man die neue ID des Symbolleistensteuerelements. Dabei handelt es sich um die ID, die in die Nachrichtenwarteschlange gestellt wird, wenn ein Steuerelementereignis auftritt. Das dritte Argument ist der Typ des Symbolleistensteuerelements. Das vierte und letzte Argument ist etwas irreführend. Wenn Sie sich die Funktionsdokumentation ansehen, gibt das vierte Argument den neuen Index des Steuerelements in der Symbolleiste an. Das ist die Position, auf die das Steuerelement verschoben wird. Wenn das Steuerelement jedoch ein Separator ist, gibt dieses Argument die Breite des Steuerelements an und verschiebt es nicht an eine andere Stelle. Da es sich im vorliegenden Fall um einen Separator handelt, legt man mit diesem Argument die Breite des zu erzeugenden Kombinationsfelds fest.

Die Position des Kombinationsfelds in der Symbolleiste ermitteln

Der Separator als Platzhalter für das Kombinationsfeld in der Symbolleiste ist nun konfiguriert. Als nächstes ermitteln Sie die Position des Platzhalters auf der Symbolleiste, damit sich die Lage des Kombinationsfelds festlegen läßt:

m_wndColorBar.GetItemRect(9, &rect);
rect.bottom = rect.top + nHeight;

In der ersten Zeile steht der Aufruf der Funktion GetItemRect, um die Position und Größe des Platzhalters für das Kombinationsfeld zu ermitteln. Die nächste Zeile addiert die Höhe der Dropdown-Liste zur Höhe, die das Kombinationsfeld schließlich einnimmt.

Das Kombinationsfeld erstellen

Die Größe des Platzhalters ist nun genau festgelegt, und Sie verfügen über Lage und Größe für das Kombinationsfeld. Nun ist es an der Zeit, das Kombinationsfeld zu erzeugen. Dazu dient die Funktion Create des Kombinationsfelds:

m_ctlWidth.Create(WS_CHILD | WS_VISIBLE | WS_VSCROLL |
CBS_DROPDOWNLIST, rect, &m_wndColorBar, IDC_CBWIDTH);

Das erste Argument der Funktion Create für das Kombinationsfeld ist der Stil des Kombinationsfelds. Normalerweise kombiniert man verschiedene Stilattribute, um einen Stilwert zu bilden. Tabelle 12.7 listet die Attribute auf, die Sie in diesem Wert verwenden können.

Tabelle 12.7: Stile für Kombinationsfelder

Stil

Beschreibung

WS_CHILD

Kennzeichnet das Kombinationsfeld als untergeordnetes Fenster (erforderlich).

WS_VISIBLE

Macht das Kombinationsfeld sichtbar.

WS_DISABLED

Deaktiviert das Kombinationsfeld.

WS_VSCROLL

Stattet die Dropdown-Liste mit vertikalen Bildlaufleisten aus.

WS_HSCROLL

Stattet die Dropdown-Liste mit horizontalen Bildlaufleisten aus.

WS_GROUP

Gruppiert Steuerelemente.

WS_TABSTOP

Schließt das Kombinationsfeld in die Tabulator-Reihenfolge ein.

CBS_AUTOHSCROLL

Rollt den Text im Bearbeitungsfeld automatisch nach rechts, wenn der Benutzer ein Zeichen am Ende der Zeile eingibt. Damit kann der Benutzer Text eingeben, der breiter ist, als das Eingabefeld des Kombinationsfelds.

CBS_DROPDOWN

Ähnlich zu CBS_SIMPLE. Allerdings wird die Liste nur dann angezeigt, wenn der Benutzer das Symbol neben dem Eingabefeld wählt.

CBS_DROPDOWNLIST

Ähnlich zu CBS_DROPDOWN. Allerdings wird das Eingabefeld durch ein statisches Textfeld ersetzt, das den momentan in der Liste markierten Eintrag anzeigt.

CBS_HASSTRINGS

Der Besitzer des Listenfelds ist für den Inhalt des Listenfelds verantwortlich. Die Elemente des Listenfelds bestehen aus Strings.

CBS_OEMCONVERT

Der in das Eingabefeld eingegebene Text wird vom ANSI-Zeichensatz in den OEM-Zeichensatz und wieder zurück nach ANSI konvertiert.

CBS_OWNERDRAWFIXED

Der Besitzer des Listenfelds ist für den Inhalt des Listenfelds verantwortlich. Die Einträge in der Liste haben alle die gleiche Höhe.

CBS_OWNERDRAWVARIABLE

Der Besitzer des Listenfelds ist für den Inhalt des Listenfelds verantwortlich. Die Höhe der Listeneinträge ist variabel.

CBS_SIMPLE

Das Listenfeld wird immer angezeigt.

CBS_SORT

Sortiert automatisch die Strings im Listenfeld.

CBS_DISABLENOSCROLL

Die Liste zeigt eine deaktivierte Bildlaufleiste, wenn nur soviel Einträge in der Liste vorhanden sind, daß sich ein Bildlauf erübrigt.

CBS_NOINTEGRALHEIGHT

Legt fest, daß das Kombinationsfeld genau die angegebene Größe einnimmt.

Das zweite Argument beschreibt das Rechteck, das das Kombinationsfeld einnehmen soll. Dieses Argument gibt die Position innerhalb des übergeordneten Fensters - in diesem Fall der Symbolleiste - an, wo das Kombinationsfeld untergebracht ist. Es verschiebt sich mit dem übergeordneten Fenster (der Symbolleiste) und bleibt immer auf der gleichen Relativposition.

Das dritte Argument ist ein Zeiger auf das übergeordnete Fenster. Es handelt sich hierbei um die Adresse der Variablen für die Symbolleiste Farben.

Im vierten Argument wird die Objekt-ID für das Kombinationsfeld übergeben.

Das Kombinationsfeld füllen

Als letztes beim Erstellen des Kombinationsfelds auf der Symbolleiste Farben ist noch die Dropdown-Liste mit den verfügbaren Elementen, aus denen der Benutzer auswählen kann, zu füllen. Das Ganze wird mit einer Kombination von zwei Funktionen realisiert:

if (szStyle.LoadString(IDS_WIDTH_VTHIN))
m_ctlWidth.AddString((LPCTSTR)szStyle);

Die erste Funktion ist die Funktion LoadString der Klasse CString. Diese Funktion übernimmt eine String-ID und lädt den zugehörigen String aus der Zeichenfolgentabelle. Die zweite Funktion ist die Funktion AddString des Kombinationsfelds, die den als Argument übergebenen String in die Dropdown-Liste hinzufügt. Indem man diese Kombination von Funktionen für alle Elemente, die in der Dropdown-Liste erscheinen sollen, aufruft, kann man das Kombinationsfeld aus der Zeichenfolgentabelle der Anwendung füllen.

Die Funktion OnCreate aktualisieren

Nachdem wir den gesamten Code zum Erstellen der Symbolleiste Farben in eine separate Funktion verschoben haben, können wir die Funktion OnCreate auf den neuesten Stand bringen, so daß sie die Funktion CreateColorBar aufruft, wo die Symbolleiste Farben erzeugt wird. Der entsprechende Code ist in Listing 12.6 wiedergegeben.

Listing 12.6: Die modifizierte Funktion OnCreate der Klasse CMainFrame

1: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
2: {
3: if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
4: return -1;
5:
6: if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | ÂCBRS_TOP
7: | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
8: !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
9: {
10: TRACE0("Symbolleiste konnte nicht erstellt werden\n");
11: return -1; // Fehler bei Erstellung
12: }
13:
14: ///////////////////////
15: // EIGENER CODE, ANFANG
16: ///////////////////////
17:
18: // Symbolleiste Farben hinzufügen
19: if (!CreateColorBar())
20: {
21: TRACE0("Symbolleiste Farben konnte nicht erstellt werden\n");
22: return -1; // // Fehler bei Erstellung
23: }
24:
25: ///////////////////////
26: // EIGENER CODE, ENDE
27: ///////////////////////
28:
29: if (!m_wndStatusBar.Create(this) ||
30: !m_wndStatusBar.SetIndicators(indicators,
31: sizeof(indicators)/sizeof(UINT)))
32: {
33: TRACE0("Statusleiste konnte nicht erstellt werden\n");
34: return -1; // Fehler bei Erstellung
35: }
36:
37: // ZU ERLEDIGEN: Löschen Sie diese drei Zeilen, wenn Sie nicht wollen, Âdass die Symbolleiste
38: // andockbar ist.
39: m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
40:
41: ///////////////////////
42: // EIGENER CODE, ANFANG
43: ///////////////////////
44:
45: // Andocken für Symbolleiste Farben aktivieren
46: m_wndColorBar.EnableDocking(CBRS_ALIGN_ANY);
47:
48: ///////////////////////
49: // EIGENER CODE, ENDE
50: ///////////////////////
51:
52: EnableDocking(CBRS_ALIGN_ANY);
53: DockControlBar(&m_wndToolBar);
54:
55: ///////////////////////
56: // EIGENER CODE, ANFANG
57: ///////////////////////
58:
59: // Symbolleiste Farben andocken
60: DockControlBar(&m_wndColorBar);
61:
62: ///////////////////////
63: // EIGENER CODE, ENDE
64: ///////////////////////
65:
66: return 0;
67: }

Wenn Sie nun die Anwendung kompilieren und ausführen, sollte sich am Ende der Symbolleiste Farben ein Kombinationsfeld befinden, wie es Abbildung 12.5 zeigt. Allerdings bewirkt das Kombinationsfeld noch keine Aktionen.

Abbildung 12.5:
Die Symbolleiste Farben mit dem Kombinationsfeld Breite

Ereignisse des Kombinationsfelds der Symbolleiste behandeln

Eine Behandlungsroutine für das Kombinationsfeld läßt sich leicht erstellen, auch wenn man das manuell erledigen muß (da der Klassen-Assistent gar nicht weiß, daß das Kombinationsfeld existiert). Es ist ein Eintrag ON_CBN_SELCHANGE in die Nachrichtenzuordnungstabelle aufzunehmen und dann die eigentliche Behandlungsfunktion in die Klasse CMainFrame einzufügen.

Als erstes nehmen wir die Behandlungsfunktion auf. Markieren Sie dazu die Klasse CMainFrame im Arbeitsbereich, und wählen Sie Member-Funktion hinzufügen aus dem Kontextmenü. Geben Sie den Funktionstyp mit afx_msg void, die Funktionsdeklaration mit OnSelChangeWidth und den Zugriff mit Protected an. Den Code für die Funktion übernehmen Sie aus dem ersten Teil von Listing 12.7. Um die Breite im Dokument zu setzen, wird in OnSelChangeWidth die Funktion SetWidth aufgerufen.

Diese Funktion müssen Sie noch in die Klasse CToolbarDoc einfügen. Markieren Sie im Arbeitsbereich auf der Registerkarte Klassen die Klasse CToolbarDoc, und wählen Sie Member-Funktion hinzufügen aus dem Kontextmenü. Legen Sie als Funktionstyp void, als Deklaration SetWidth(UINT nWidth) und als Zugriff Public fest. In die Funktion schreiben Sie den zweiten Teil von Listing 12.7.

Listing 12.7: Die Funktionen OnSelChangeWidth und SetWidth

1: void CMainFrame::OnSelChangeWidth()
2: {
3: // Neue Auswahl des Kombinationsfelds ermitteln
4: int nIndex = m_ctlWidth.GetCurSel();
5: if (nIndex == CB_ERR)
6: return;
7:
8: // Aktives Dokument ermitteln
9: CToolbarDoc* pDoc = (CToolbarDoc*)GetActiveDocument();
10: // Handelt es sich um ein gültiges Dokument?
11: if (pDoc)
12: // Neue Zeichenbreite setzen
13: pDoc->SetWidth(nIndex);
14:
15: }
16:
17: void CToolbarDoc::SetWidth(UINT nWidth)
18: {
19: // Breite setzen
20: m_nWidth = nWidth;
21: }

Die Funktion OnSelChangeWidth ermittelt zuerst die aktuelle Auswahl des Kombinationsfelds. Da wir die Einträge in der richtigen Reihenfolge eingetragen und beim Erstellen des Kombinationsfelds das Flag CBS_SORT (zum Sortieren der Einträge) nicht angegeben haben, entspricht der Index den Breiten im Dokument. Daher kann man einen Zeiger auf die aktuelle Instanz des Dokuments mit der Funktion GetActiveDocument ermitteln und dann die neue Breite an das Dokument mit der Funktion SetWidth übergeben.

Um die Behandlungsfunktion aufzurufen, wenn der Benutzer die Auswahl im Kombinationsfeld ändert, müssen Sie den entsprechenden Eintrag in die Nachrichtenzuordnungstabelle von CMainFrame einfügen. Gehen Sie im Quellcode von CMainFrame nach oben, bis Sie den Abschnitt der Nachrichtenzuordnungstabelle finden, und fügen Sie hier Zeile 12 von Listing 12.8 ein.

Listing 12.8: Die modifizierte Nachrichtenzuordnungstabelle von CMainFrame

1: ///////////////////////////////////////////////////////////////////////////
2: // CMainFrame
3:
4: IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
5:
6: BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
7: //{{AFX_MSG_MAP(CMainFrame)
8: ON_WM_CREATE()
9: ON_COMMAND(ID_VIEW_COLORBAR, OnViewColorbar)
10: ON_UPDATE_COMMAND_UI(ID_VIEW_COLORBAR, OnUpdateViewColorbar)
11: //}}AFX_MSG_MAP
12: ON_CBN_SELCHANGE(IDC_CBWIDTH, OnSelChangeWidth)
13: END_MESSAGE_MAP()

Der Eintrag

ON_CBN_SELCHANGE(IDC_CBWIDTH, OnSelChangeWidth)

in der Nachrichtenzuordnungstabelle legt fest, daß die Funktion OnSelChangeWidth aufzurufen ist, wenn Ereignisse mit der Objekt-ID des Kombinationsfelds in der Symbolleiste Farben aufgrund von Änderungen der Auswahl im Kombinationsfeld auftreten. Wenn Sie nun die Anwendung kompilieren und ausführen, sollten Sie die Stiftbreite zum Zeichnen über das Kombinationsfeld der Symbolleiste Farben ändern können.

Das Kombinationsfeld der Symbolleiste aktualisieren

Für das Kombinationsfeld ist noch ein Problem zu lösen. Falls der Benutzer einen neuen Wert aus dem Menü und nicht über das Kombinationsfeld auswählt, soll das Kombinationsfeld ebenfalls den neuen Wert widerspiegeln. Die aktuelle Auswahl im Kombinationsfeld läßt sich am effizientesten setzen, wenn das beim Auslösen irgendeines Menübefehls geschieht. Dazu ist eine Funktion in der Hauptrahmenklasse erforderlich, die sich von der Dokumentklasse aufrufen läßt. Die Funktion im Hauptrahmen muß lediglich die aktuelle Auswahl im Kombinationsfeld setzen.

Um diese Funktion im Hauptrahmen zu implementieren, fügen Sie eine neue Member-Funktion in die Klasse CMainFrame ein und legen den Funktionstyp mit void, die Deklaration mit UpdateWidthCB(int nIndex) und den Zugriff mit Public fest. In die Funktion schreiben Sie den Code aus Listing 12.9.

Listing 12.9: Die Funktion UpdateWidthCB der Klasse CMainFrame

1: void CMainFrame::UpdateWidthCB(int nIndex)
2: {
3: // Die neue Auswahl im Kombinationsfeld setzen
4: m_wndColorBar.m_ctlWidth.SetCurSel(nIndex);
5: }

Die Funktion UpdateWidthCB ruft die Kombinationsfeldfunktion SetCurSel auf, die die aktuelle Auswahl in der Dropdown-Liste des Kombinationsfelds auf den Eintrag mit dem angegeben Index setzt. Das Eingabefeld des Kombinationsfelds wird mit dem neu ausgewählten Listeneintrag aktualisiert. Wenn man dem Kombinationsfeld einen Index anbietet, der nicht in der Dropdown-Liste existiert, liefert die Funktion einen Fehler zurück.

Auf der Seite des Dokuments muß man die Funktion im Hauptrahmen immer dann aufrufen, wenn die entsprechenden Behandlungsfunktionen für das Menü aufgerufen werden. Da das in verschiedenen Funktionen vorkommen kann, ist es sinnvoll, die erforderliche Funktionalität in einer einzigen Funktion unterzubringen. Diese Funktion benötigt einen Zeiger auf die mit dem Dokument verbundene Ansicht und ermittelt dann - über die Ansicht - einen Zeiger auf den Rahmen. Diesen Zeiger kann man dann im Aufruf der Funktion UpdateWidthCB, die wir eben der Hauptrahmenklasse hinzugefügt haben, verwenden.

Um die Funktion in die Anwendung aufzunehmen, markieren Sie die Klasse CToolbarDoc im Arbeitsbereich und wählen Member-Funktion hinzufügen aus dem Kontextmenü. Legen Sie als Funktionstyp void, als Funktionsdeklaration UpdateColorbar(int nIndex) und als Zugriffsstatus Privat fest. In die Funktion übernehmen Sie den Code aus Listing 12.10.

Listing 12.10: Die Funktion UpdateColorbar der Klasse CToolbarDoc

1: void CToolbarDoc::UpdateColorbar(int nIndex)
2: {
3: // Position der ersten Ansicht ermitteln
4: POSITION pos = GetFirstViewPosition();
5: // Ist die Position gültig?
6: if (pos != NULL)
7: {
8: // Zeiger auf Ansicht in dieser Position holen
9: CView* pView = GetNextView(pos);
10: // Ist Zeiger auf Ansicht gültig?
11: if (pView)
12: {
13: // Zeiger auf Rahmen über Ansicht holen
14: CMainFrame* pFrame = (CMainFrame*)pView->GetTopLevelFrame();
15: // Zeiger auf Rahmen erhalten?
16: if (pFrame)
17: // Kombinationsfeld in Symbolleiste Farben
18: // über den Rahmen aktualisieren
19: pFrame->UpdateWidthCB(nIndex);
20: }
21: }
22: }

Diese Funktion folgt dem Pfad, um den Anwendungsrahmen aus der Dokumentklasse zu erhalten. Da in einem Dokument mehrere Ansichten gleichzeitig geöffnet sein können, ermitteln Sie mit der Funktion GetFirstViewPosition die Position der ersten Ansicht, die mit dem Dokument verbunden ist.

Die nächste Funktion, GetNextView, gibt einen Zeiger auf die Ansicht zurück, die durch die Position spezifiziert wird. Diese Funktion aktualisiert ebenfalls die Positionsvariable mit dem Zeiger auf die nächste Ansicht in der Liste der Ansichten, die mit dem aktuellen Dokument verbunden sind.

Nachdem Sie über einen Zeiger auf die Ansicht verfügen, können Sie die Fensterfunktion GetTopLevelFrame aufrufen, die einen Zeiger auf das Rahmenfenster der Anwendung zurückgibt. Diese Funktion müssen Sie über die Ansicht aufrufen, da das Dokument nicht von der Klasse CWnd abgeleitet ist, während das bei der Ansicht der Fall ist.

Nunmehr besitzen Sie einen Zeiger auf das Rahmenfenster und können diesen Zeiger verwenden, um die weiter vorn erzeugte Funktion aufzurufen und das Kombinationsfeld in der Symbolleiste zu aktualisieren. Wenn Sie jetzt diese neue Funktion aus der Behandlungsroutine des Menübefehls Breite aufrufen, wie es in Listing 12.11 geschieht, wird das Kombinationsfeld in der Symbolleiste Farben automatisch aktualisiert und spiegelt die momentan ausgewählte Stiftbreite zum Zeichnen wider, unabhängig davon, ob die Auswahl über das Menü oder das Kombinationsfeld erfolgt ist.

Listing 12.11: Eine aktualisierte Behandlungsroutine für den Menübefehl Breite

1: void CToolbarDoc::OnWidthVthin()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4: // Neue Breite setzen
5: m_nWidth = 0;
6: // Kombinationsfeld in der Symbolleiste Farben aktualisieren
7: UpdateColorbar(0);
8: }

Ein neues Element für die Statusleiste

Weiter oben in der heutigen Lektion haben Sie gelernt, wie man Meldungen in der Statusleiste und QuickInfos für Symbolleistenschaltflächen und Menübefehle spezifiziert. Wie verhält es sich nun, wenn Sie dem Benutzer in der Statusleiste weitergehende Informationen anbieten möchten? Wie läßt sich analog zu Visual Studio für Visual C++ erreichen, daß man Informationen über die momentan ausgeführten Aktionen, die gerade im Dokument bearbeitete Stelle oder den aktuellen Zustand der Anwendung anzeigen kann? Diese Angaben gehen über die Anzeigen der Feststelltasten hinaus, die Visual C++ automatisch in der Statusleiste meldet.

Es ist tatsächlich einfach, zusätzliche Ausschnitte in die Statusleiste aufzunehmen oder auch bereits vorhandene Ausschnitte zu entfernen. Um sich mit diesen Vorgängen bekannt zu machen, nehmen Sie einen neuen Ausschnitt in die Statusleiste Ihrer Zeichenanwendung auf, der die momentan gültige Farbe meldet.

Ein neuer Ausschnitt für die Statusleiste

Bevor Sie einen neuen Ausschnitt in die Statusleiste einbinden, müssen Sie einen neuen Eintrag in der Zeichenfolgentabelle der Anwendung für den Statusleisten-Ausschnitt erstellen. Der Eintrag in der Zeichenfolgentabelle realisiert für den Statusleisten-Ausschnitt zwei Aufgaben. Erstens stellt er die Objekt-ID für den Statusleisten- Ausschnitt bereit. Diese ID verwenden Sie, um den Ausschnitt in der Statusleiste zu aktualisieren, wenn ein neuer Text in diesem Feld auszugeben ist. Die zweite Funktion des Eintrags in der Zeichenfolgentabelle bezieht sich auf die Größe des Ausschnitts. Um die korrekte Größe des Ausschnitts festzulegen, müssen Sie einen Titel für den Eintrag in der Zeichenfolgentabelle bereitstellen, der mindestens so lang wie der längste String ist, den Sie im Statusleisten-Ausschnitt anzeigen möchten.

In die Zeichenfolgentabelle fügen Sie einen neuen Eintrag mit den gleichen Schritten hinzu, die Sie weiter vorn beim Text für das Kombinationsfeld in der Symbolleiste Farben ausgeführt haben. Legen Sie die String-ID mit ID_INDICATOR_COLOR und den Titel mit MAGENTA (der längste String, der im Ausschnitt der Statusleiste anzuzeigen ist) fest.

Ein kleiner Teil im ersten Abschnitt des Quellcodes für den Hauptrahmen definiert das Layout der Statusleiste. Diese kleine Tabelle enthält die Objekt-IDs der Statusleisten- Ausschnitte als Tabellenelemente, und zwar in der Reihenfolge, in der sie von links nach rechts in der Statusleiste erscheinen.

Um den Ausschnitt für die Farbe in die Statusleiste aufzunehmen, fügen Sie die ID des Farbenausschnittes in die Tabellendefinition für die Statusleistenanzeige unmittelbar im Anschluß an die Nachrichtenzuordnungstabelle in der Quellcodedatei für den Hauptrahmen ein. Schreiben Sie die ID für den Farbenausschnitt in der Tabellendefinition an die Stelle, die der Ausschnitt auf der Statusleiste einnehmen soll, wie es aus Zeile 18 von Listing 12.12 hervorgeht.

Listing 12.12: Eine modifizierte Tabellendefinition für Statusleistenanzeigen

1: ///////////////////////////////////////////////////////////////////////////
2: // CMainFrame
3:
4: IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
5:
6: BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
7: //{{AFX_MSG_MAP(CMainFrame)
8: ON_WM_CREATE()
9: ON_COMMAND(ID_VIEW_COLORBAR, OnViewColorbar)
10: ON_UPDATE_COMMAND_UI(ID_VIEW_COLORBAR, OnUpdateViewColorbar)
11: //}}AFX_MSG_MAP
12: ON_CBN_SELCHANGE(IDC_CBWIDTH, OnSelChangeWidth)
13: END_MESSAGE_MAP()
14:
15: static UINT indicators[] =
16: {
17: ID_SEPARATOR, // Statusleistenanzeige
18: ID_INDICATOR_COLOR,
19: ID_INDICATOR_CAPS,
20: ID_INDICATOR_NUM,
21: ID_INDICATOR_SCRL,
22: };
23:
24: ///////////////////////////////////////////////////////////////////////////
25: // CMainFrame Konstruktion/Zerstörung

Falls Sie eine der Anzeigen für die Feststelltasten aus der Statusleiste entfernen möchten, löschen Sie einfach den entsprechenden Eintrag in der Tabellendefinition. Weiter unten in der Funktion OnCreate, die die Statusleiste (unmittelbar nach den Symbolleisten) erstellt, sehen Sie auch, wo diese Tabelle zum Einsatz kommt, um die Statusleiste mit dem folgenden Code zu erzeugen:

if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))

Nachdem die Statusleiste erzeugt wurde, folgt ein Aufruf der Funktion SetIndicators auf der Statusleiste, um die Ausschnitte gemäß der Definition in der Tabelle der Statusleistenanzeigen in die Statusleiste aufzunehmen. Die mit den IDs in der Tabelle der Statusleistenanzeigen verbundenen Strings dienen dazu, die Ausschnitte zu initialisieren und deren Größe festzulegen. Wenn Sie jetzt die Anwendung kompilieren und ausführen, sehen Sie den neuen Farbenausschnitt in der Statusleiste. Der Ausschnitt zeigt den Titel aus der Zeichenfolgentabelle an.

Text für einen Statusleisten-Ausschnitt festlegen

Nachdem Sie den Ausschnitt in die Statusleiste aufgenommen haben, können Sie über das Ereignis UPDATE_COMMAND_UI alle Aktualisierungen des Ausschnitts erledigen lassen. Dazu müssen Sie lediglich eine Behandlungsroutine für das Ereignis auf der Objekt-ID des Ausschnitts hinzufügen und dieses Ereignis verwenden, um den Text im Ausschnitt festzulegen. Da die Statusleiste immer sichtbar ist, wird das Ereignis UPDATE_COMMAND_UI für die Ausschnitte in der Statusleiste jedesmal ausgelöst, wenn die Anwendung im Leerlauf arbeitet. Das bedeutet, daß das Ereignis auftritt, nachdem die Anwendung die Abarbeitung aller Tastenbetätigungen und Mausbewegungen abgeschlossen hat. In etwa einer Woche, am Tag 18, lernen Sie bei der Behandlung des Multitasking, wie häufig und wann Tasks, die im Leerlauf einer Anwendung arbeiten, ausgelöst werden.

In der Behandlungsroutine müssen Sie einen String erzeugen, der den Namen der aktuellen Farbe enthält (oder was auch immer für ein Text im Ausschnitt der Statusleiste erscheinen soll). Als nächstes ist sicherzustellen, daß der Ausschnitt aktiviert ist. Schließlich müssen Sie den Text des Ausschnitts auf den erzeugten String setzen.

Um das Ganze in Ihrer Anwendung zu implementieren, erzeugen Sie eine Behandlungsroutine für die Nachricht UPDATE_COMMAND_UI. Auch in diesem Fall ist der Klassen-Assistent nicht über den Ausschnitt in der Statusleiste informiert, so daß Sie die Behandlungsroutine manuell erzeugen und in die Nachrichtenzuordnungstabelle eintragen müssen. Um die Behandlungsroutine zu erstellen, fügen Sie der Dokumentklasse (CToolbarDoc) eine neue Member-Funktion mit dem Typ afx_msg void, der Deklaration OnUpdateIndicatorColor (CCmdUI * pCmdUI) und dem Zugriffsstatus Protected hinzu. In die Funktion nehmen Sie den Code von Listing 12.13 auf.

Listing 12.13: Die Funktion OnUpdateIndicatorColor

1: void CToolbarDoc::OnUpdateIndicatorColor(CCmdUI *pCmdUI)
2: {
3: CString strColor;
4:
5: // Wie heißt die aktuelle Farbe?
6: switch (m_nColor)
7: {
8: case 0: // Schwarz
9: strColor = "SCHWARZ";
10: break;
11: case 1: // Blau
12: strColor = "BLAU";
13: break;
14: case 2: // Grün
15: strColor = "GRÜN";
16: break;
17: case 3: // Cyan
18: strColor = "CYAN";
19: break;
20: case 4: // Rot
21: strColor = "ROT";
22: break;
23: case 5: // Magenta
24: strColor = "MAGENTA";
25: break;
26: case 6: // Gelb
27: strColor = "GELB";
28: break;
29: case 7: // Weiß
30: strColor = "WEISS";
31: break;
32: }
33: // Statusleisten-Ausschnitt aktivieren
34: pCmdUI->Enable(TRUE);
35: // Text im Ausschnitt der Statusleiste
36: // auf die aktuelle Farbe setzen
37: pCmdUI->SetText(strColor);
38: }

Diese Funktion befolgt genau drei Schritte: sie erzeugt einen String mit dem Namen der aktuellen Farbe, stellt sicher, daß der Ausschnitt in der Statusleiste aktiviert ist, und setzt den Text im Feld auf den erzeugten String.

Um nun sicherzustellen, daß der Aufruf der neuen Behandlungsroutine wie erwartet erfolgt, müssen Sie einen ON_UPDATE_COMMAND_UI-Eintrag in die Nachrichtenzuordnungstabelle am Beginn des Quellcodes der Dokumentdatei aufnehmen, wie es Listing 12.14 zeigt.

Listing 12.14: Die modifizierte Nachrichtenzuordnungstabelle von CToolbarDoc

1: ///////////////////////////////////////////////////////////////////////////
2: // CToolbarDoc
3:
4: IMPLEMENT_DYNCREATE(CToolbarDoc, CDocument)
5:
6: BEGIN_MESSAGE_MAP(CToolbarDoc, CDocument)
7: ON_UPDATE_COMMAND_UI(ID_INDICATOR_COLOR, OnUpdateIndicatorColor)
8: //{{AFX_MSG_MAP(CToolbarDoc)
9: ON_UPDATE_COMMAND_UI(ID_WIDTH_VTHIN, OnUpdateWidthVthin)
10: .
11: .
12: ON_COMMAND(ID_WIDTH_VTHIN, OnWidthVthin)
13: //}}AFX_MSG_MAP
14: END_MESSAGE_MAP()

Nachdem Sie die Behandlungsroutine und den Eintrag in die Nachrichtenzuordnungstabelle hinzugefügt haben, können Sie nun Ihre Anwendung kompilieren und ausführen. In der Statusleiste sollte der Farbenausschnitt automatisch aktualisiert werden, um die momentane Zeichenfarbe anzugeben, wie es Abbildung 12.6 zeigt.

Abbildung 12.6:
Die Zeichenanwendung zeigt die aktuelle Farbe in der Statusleiste an.

Zusammenfassung

Der heutige Lehrstoff war recht umfangreich. (Zeichnet sich hier ein Trend ab?) Sie haben gelernt, wie man eigene Symbolleisten entwirft und erstellt. In diesem Zusammenhang haben Sie auch erfahren, wie man Aufforderungen in der Statusleiste für die Symbolleistenschaltflächen und Menüs festlegt sowie QuickInfos anzeigt, wenn man die Maus ein paar Sekunden über einer Symbolleistenschaltfläche ruhen läßt. Sie wissen nun, wie man diese Symbolleisten erstellt und sie mit dem Anwendungsgerüst verbindet. Weiterhin haben Sie gelernt, wie man über einen Menübefehl steuert, ob die Symbolleiste sichtbar ist.

Als nächstes sind wir darauf eingegangen, wie man ein Kombinationsfeld in einer Symbolleiste unterbringt, damit man dem Benutzer der Anwendung die gleiche Bequemlichkeit bieten kann, die er von anderen bekannten Softwarepaketen her gewohnt ist. Gleichzeitig haben Sie erfahren, wie man ein Kombinationsfeld per Code erzeugt, ohne daß man mit dem Dialog-Editor arbeiten muß, und wie man die Dropdown-Liste des Kombinationsfelds mit Texteinträgen füllt. Dann wurde gezeigt, wie man das Kombinationsfeld in die Anwendung einbindet, indem man Behandlungsroutinen für die Ereignisse des Kombinationsfelds erstellt, und wie man das Kombinationsfeld aktualisiert, um die am Anwendungsmenü vorgenommenen Änderungen widerzuspiegeln.

Schließlich hat der heutige Tag gezeigt, wie man eigene Ausschnitte in die Statusleiste aufnimmt und wie man den Ausschnitt aktualisiert, um den momentanen Status der Anwendung wiederzugeben.

Fragen und Antworten

Frage:
In manchen Anwendungen hat man bei Symbolleisten die Option, Text anzuzeigen, beispielsweise im Internet Explorer. Wie läßt sich Text für meine Symbolleistenschaltflächen hinzufügen?

Antwort:
Leider bietet der Symbolleisten-Editor keine Möglichkeit, um Symbolleistenschaltflächen einen Text zuzuordnen. Das bedeutet, daß man den Text per Anwendungscode in die Schaltflächen aufnehmen muß, genauso wie man für alle Schaltflächen der Symbolleiste Farbe das Verhalten als Optionsfelder realisiert. Mit der Funktion SetButtonText legen Sie den Text auf jeder Symbolleistenschaltfläche individuell fest. Diese Funktion übernimmt zwei Argumente: das erste ist der Index der Schaltfläche, das zweite enthält den Text für die Schaltfläche. Wenn Sie wirklich Text auf den Symbolleistenschaltflächen unterbringen möchten, müssen Sie außerdem die Symbolleiste in der Größe ändern, um Platz für den anzuzeigenden Text zu schaffen.

Frage:
Ich habe im Symbolleisten-Editor einige Änderungen an der Symbolleiste Farben vorgenommen und erhalte nun jedesmal einen Assertion-Fehler, wenn ich die Anwendung auszuführen versuche. Was ist passiert?

Antwort:
Das Problem besteht darin, daß der Symbolleisten-Editor die Separatoren gefunden hat, die Sie in die Ressourcendatei als Platzhalter für das Kombinationsfeld aufgenommen haben. Der Symbolleisten-Editor nimmt an, daß es sich hier um Fehler handelt, und entfernt die Platzhalter automatisch. Der Fehler, den Sie erhalten, tritt deshalb auf, weil Sie versuchen, mit einem Steuerelement in der Symbolleiste Farben zu arbeiten, das nicht existiert. Um das Problem zu umgehen, öffnen Sie die Ressourcendatei erneut im Editor und fügen die beiden Separatoren wieder am Ende der Definition der Farben-Symbolleiste an. Laden Sie dann das Projekt in Visual C++, und kompilieren Sie die Anwendung neu.

Frage:
Das Kombinationsfeld in meinen Symbolleisten sieht zu groß aus. Wie kann ich erreichen, daß es sich harmonischer in die Symbolleiste einfügt?

Antwort:
Um das Kombinationsfeld in die Symbolleiste einzupassen, wie es zum Beispiel im Visual Studio von Visual C++ zu sehen ist, sind eine Reihe von Dingen zu erledigen. Zuerst verringern Sie den oberen Teil des Kombinationsfelds um 3. Damit entsteht ein schmaler Rand zwischen dem oberen Rand des Kombinationsfelds und dem Rand der Symbolleiste. Als nächstes wählen Sie für das Kombinationsfeld eine kleinere Schrift, die sich besser in die Symbolleiste einfügt. Experimentieren Sie etwas mit Schriften und Schriftabständen, bis Sie das Optimum für das Kombinationsfeld in der Symbolleiste gefunden haben.

Frage:
Wie kann ich den Text im ersten Abschnitt der Statusleiste festlegen, ohne Menü- und Symbolleistenaufforderungen zu verwenden?

Antwort:
Mit SetWindowText können Sie den Text im ersten Ausschnitt der Statusleiste festlegen. Per Voreinstellung ist der erste Ausschnitt in der Statusleiste ein Separator, der sich automatisch erweitert und dann die Breite der Statusleiste abzüglich der anderen nach rechts ausgerichteten Ausschnitte in der Leiste einnimmt. Ruft man die Funktion SetWindowText auf der Statusleistenvariablen auf, wird nur der Text im ersten Ausschnitt festgelegt. Wenn Sie den Text in einem der anderen Ausschnitte ändern möchten und das zu anderen Zeiten als in der Behandlungsroutine der Nachricht ON_UPDATE_COMMAND_UI, können Sie mit der Funktion SetPaneText arbeiten. Es gibt zwei Möglichkeiten, um den Text im Hauptteil der Statusleiste zu setzen. Die erste sieht folgendermaßen aus:

CString myString = "Das ist mein Statusleistentext"
m_wndStatusBar.SetWindowText(myString);
CString* myString = " Das ist mein Statusleistentext "
m_wndStatusBar.SetPaneText(0, myString);

Workshop

Kontrollfragen

1. Wie verbinden Sie eine Symbolleistenschaltfläche mit einem Menübefehl, der dieselbe Funktion auslöst?

2. Wie kann man sicherstellen, daß eine Symbolleiste mit dem Rahmenfenster verankert ist?

3. Wie läßt sich die Statusanzeige für die numerische Feststelltaste aus der Statusleiste entfernen?

4. Warum muß man die Ressourcendatei bearbeiten, um ein Kombinationsfeld in eine Symbolleiste aufzunehmen?

Übungen

1. Fügen Sie einen weiteren Ausschnitt in die Statusleiste ein, um die momentan ausgewählte Breite anzuzeigen.

2. Nehmen Sie in die Hauptsymbolleiste eine Schaltfläche auf, mit der man die Symbolleiste Farben ein-/ausschalten kann, wie es Abbildung 12.7 zeigt.

Abbildung 12.7:
Der Umschalter für die Symbolleiste Farben



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