Previous PageIndexList Of FiguresList Of TablesNext Page

3 RESSOURCEN

Unter dem Begriff Ressourcen versteht man in der Windows-Programmierung die Daten eines Programms, die in separaten Dateien verwaltet werden. Zu den Ressourcen zählt man unter anderem Symbole (Icons), Cursor, Bitmaps, Zeichenketten und Menüs. Ressourcen legen im wesentliche das äußere Erscheinungsbild eines Programmes fest. Ein Vorteil dieses getrennten Erstellens und Pflegens der Ressourcen liegt darin, daß man Programme für viele verschiedene Sprachen erstellen kann, ohne den Programmcode ändern zu müssen. Es reicht, wenn man die Texte in den Ressourcen an die Landessprache anpaßt. Ebenso können einmal erstellte Ressourcen in vielen Programmen wiederverwendet werden. Als spezielles Werkzeug zur Bearbeitung von Ressourcen liefert Borland seinen "Resource-Workshop" und Microsoft das "App Studio", in denen alle Werkzeuge zur Erstellung und Manipulation von Ressourcen enthalten sind. Mit diesen Werkzeugen können beispielsweise auch die Ressourcen fertiger Programme untersucht werden. In Bild 3.1 sehen Sie, wie App Studio die Ressourcen des Programms PAINTBRUSH.EXE darstellt.

Bild 3.1: Programm "App Studio"
Alle Ressourcen werden in der Regel in einer sogenannten Ressource-Skript-Datei definiert. Diese Textdatei hat die Endung RC. Sie kann mit jedem beliebigen Editor erstellt werden und beschreibt die Eigenschaften der einzelnen Ressourcen. Sie wird vom Ressource-Compiler RC.EXE in eine Binärdatei (.RES) übersetzt und an die EXE-Datei angehängt.
Das folgende Beispiel zeigt ein Skript, in dem drei Ressourcen beschrieben sind:
- ein Symbol, das MyIcon heißt,

- ein Menü mit Namen IconMenu und

- das Dialogfeld AboutBox.

MyIcon		ICON	icon1.ico

IconMenu		MENU
BEGIN
    POPUP        "&Help"
    BEGIN
	MENUITEM "&About Icon...", IDM_ABOUT
    END
END

AboutBox		DIALOG 22, 17, 144, 75
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About Icon"
BEGIN
   CTEXT "Microsoft Windows"	  -1,	 0, 5,144, 8
   CTEXT "Icon Application"	  -1,	 0,14,144, 8
   CTEXT "Version 3.0" 		  -1,	 0,34,144, 8
   DEFPUSHBUTTON "OK"		IDOK,	53,59,32,14,WS_GROUP
   ICON  "MyIcon",			  -1,	12,20, 16,21
END

Bei der Beschreibung der Ressourcen beginnt man mit ihrem Namen, gefolgt vom entsprechenden Typ wie z.B. BITMAP, CURSOR, ICON, DIALOG, MENU, STRINGTABLE. Die weiteren Angaben zu den Ressourcen werden je nach Typ in einer oder mehreren Zeilen gemacht.
In diesem Kapitel werden wir uns nun mit einigen wichtigen Ressourcen beschäftigen und zeigen, wie man sie in ein Programm einbindet. Als Ausgangsprogramm wird Programm PRG2_2 dienen.

3.1 Symbole

Symbole (Icons) dienen der optischen Identifizierung von Programmen. Sie werden verwendet, um das Programm im Programm-Manager oder in verkleinerter Form am unteren Bildschirmrand darzustellen, wie man in Bild 3.2 sehen kann.

Bild 3.2: Symbol
Die Größe eines Symbols beträgt in der Regel 32 mal 32 Pixel (Bildschirmpunkte) mit bis zu 16 Farben. Bei Symbolen und auch bei Cursorn handelt es sich um sogenannte Bitmaps. Bitmaps sind Grafiken, bei denen jeder Bildschirmpunkt durch ein oder mehrere Bits repräsentiert wird.

3.1.1 Symbole entwerfen

Zum Entwerfen von Icons liefern die Compilerhersteller verschiedene Werkzeuge aus. Zu Beginn der Entwicklung von Windows gab es nur das SDK von Microsoft, das das Programm SDKPAINT.EXE beinhaltete, mit dem man Symbole und Cursor entwerfen konnte. Mit Quick-C für Windows und dem SDK 3.1 wurde das SDKPAINT durch IMAGEDIT.EXE ersetzt (siehe Bild 3.3). Dieses wiederum wurde mit dem Erscheinen von Visual C++ durch das App Studio abgelöst. Das App Studio ist nicht nur für das Erstellen von Symbolen und Cursorn zuständig, sondern übernimmt die gesamte Verwaltung der Ressourcen.

Bild 3.3: IMAGEDIT.EXE
Bei den Borland Compilern wurde der Schritt von der Werkzeugsammlung hin zu einem integrierten Tool bereits viel früher vollzogen. Hier konnte sich der Programmierer mit dem Resource Workshop die Bearbeitung der Ressourcen wesentlich vereinfachen und beschleunigen.
Gleichgültig, welches Werkzeug Sie benutzen, die Erstellung von Symbolen geschieht immer in ähnlicher Weise. Sie starten das benötigte Programm und geben an, daß Sie ein Icon erstellen möchten. Als Größe des Symbols geben Sie für VGA-Bildschirme 32x32 Pixel an. Während Sie das Symbol mit Stift, Pinsel oder Farbeimer bearbeiten, können Sie das Aussehen des Icons in Originalgröße meist in einem kleinen Zusatzfenster kontrollieren.
Als Besonderheit bei einem Symbol ist zu beachten, daß man Teile dieser Bitmap transparent gestalten kann. Transparent bedeutet, daß das Symbol an bestimmten Stellen die Hintergrundfarbe durchscheinen läßt. In den folgenden beiden Abbildungen sehen Sie ein Symbol, bei dem der Hintergrund nicht transparent, sondern weiß gezeichnet ist. Das fällt so lange nicht auf, wie auch der Fensterhintergrund weiß ist. Sollte diese Farbe jedoch mit Hilfe der Systemsteuerung umgestellt worden sein, wird das Icon so dargestellt, wie in der zweiten Abbildung zu sehen ist.
Weißer Fensterhintergrund:
Grauer Fensterhintergrund:
Häufig ist dieses Aussehen jedoch nicht erwünscht. Die Bereiche, die den Fensterhintergrund durchscheinen lassen sollen, müssen daher transparent gefüllt werden. Das fertige Symbol wird mit der Extension(Dateiendung) .ICO abgespeichert.

3.1.2 Symbole im Programm verwenden

Die Aufgabe von Symbolen beschränkt sich im allgemeinen darauf, das Programm auf dem Bildschirm darzustellen.
Daher reicht es aus, wenn man bei der Registrierung der Fensterklasse dieses Symbol als Standardsymbol definiert und zusätzlich eine Zeile mit Angaben zu diesem Symbol im Ressource-Skript einträgt.
Aufgabe:
Das Programm prg3_1 soll das folgende selbstdefinierte Symbol erhalten.

Gehen Sie dazu folgendermaßen vor:
Um sich Tipparbeit zu ersparen, verwenden Sie bitte eine Kopie von prg2_2, die in prg3_1 umbenannt wird. Erstellen Sie also eine Kopie von prg2_2.c, und nennen Sie sie in prg3_1.c um. Machen Sie das gleiche mit der Datei prg2_2.def. Ändern Sie in beiden Programmen alle Bezeichnungen prg2_2 in prg3_1 um.
Entwerfen Sie mit einem Ressource-Tool das dargestellte Symbol, und speichern Sie es unter dem Namen A.ICO.
Ändern Sie die Zeile 28 in prg3_1.c wie folgt:

/*28**/    wc.hIcon=LoadIcon(dieseInstanz,"GROSSESA");

Erstellen Sie mit einem beliebigen Editor oder mit Hilfe der Entwicklungsumgebung ein Ressource-Skript mit Namen prg3_1.rc. Tragen Sie dort folgende Zeile ein.

GROSSESA        ICON    DISCARDABLE     "A.ICO"

Compilieren und linken Sie das Programm. Fügen Sie zum Schluß die Ressource-Datei hinzu (siehe dazu Kapitel 2.5). Wenn das fertige Programm jetzt auf Symbolgröße verkleinert wird, hat es folgendes Aussehen:

Wie Sie sehen, benötigt die Ressource-Datei nur wenige Angaben für ein Icon. Als erste den Namen GROSSESA. Dieser Name taucht im Programm als Parameter der Funktion LoadIcon wieder auf. Als zweite die Anweisung ICON und als letzte den Namen der Datei a.ico, die das eigentliche Symbol enthält.

3.2 Cursor

Die Erstellung eines Cursors und seine Benutzung im Programm entsprechen weitestgehend dem, was Sie im vorigen Kapitel über Symbole erfahren haben.
Cursor haben nicht nur die Aufgabe, dem Benutzer zu zeigen, an welcher Stelle des Bildschirms er sich gerade befindet. Sie dienen auch dazu, den gerade aktiven Modus eines Programms anzuzeigen. Diese Eigenschaft kann man besonders deutlich im Programm PAINTBRUSH erkennen. Je nachdem, welches Zeichenwerkzeug man hier ausgewählt hat, hat der Cursor eine andere Form.
In den nächsten Kapiteln wollen wir Ihnen zeigen, wie man Cursor entwirft, und wie man sie in Programmen verwendet.

3.2.1 Cursor entwerfen

Zum Gestalten eines Cursors werden dieselben Programme eingesetzt wie auch zum Entwerfen von Symbolen. Nach dem Start eines dieser Programme geben Sie Cursor als gewünschten Dateityp an. Da Windows nur einfarbige Cursor kennt, beschränkt sich Ihre Auswahl auf seine Größe, die Sie mit 32x32 Pixel angeben. Zeichnen Sie nun Ihren Cursor, und speichern Sie ihn mit der Endung CUR ab.
Genau wie bei den Symbolen können Cursor auch Bereiche haben, in denen sie undurchsichtig, durchsichtig oder invertiert sind. Zusätzlich hat er jedoch noch einen sogenannten Hotspot oder Kontaktpunkt. Dieser legt fest, an welcher Stelle der Cursor Kontakt haben muß, um eine Aktion auszulösen. Um einen Hotspot zu definieren, bieten die Zeichenprogramme spezielle Befehle an (siehe Bild 3.4), sobald ein Cursor bearbeitet wird.

Bild 3.4: Werkzeug zur Hotspot-Markierung

3.2.2 Cursor im Programm verwenden

In diesem Schritt wollen wir für das Programm prg3_1 einen eigenen Cursor definieren.
Aufgabe:
Das Fenster von Programm prg3_1 soll den folgenden Cursor erhalten.

Zeichnen Sie hierzu den dargestellten Cursor. Der Kontaktpunkt soll das Pixel in der Mitte des Rechtecks sein.
Die Zeile 29 des Programms prg3_1 wird so geändert:

wc.hCursor=LoadCursor(dieseInstanz,"QUADRAT");

In der Ressource-Datei wird diese Zeile hinzugefügt:

QUADRAT     CURSOR   "QUADRAT.CUR"

Nach dem Erstellen und Starten des Programms sollte sich das Fenster mit seinem neuen Cursor so darstellen:

Bild 3.5: Selbstdefinierter Cursor

3.2.3 Cursor vorübergehend ändern

Wie Sie wissen, ändert der Cursor in Windows immer dann seine Form in eine Sanduhr, wenn länger andauernde Operationen durchgeführt werden. Dieses Ändern erfolgt nicht automatisch, sondern muß von Ihnen programmiert werden. Der dazu benötigte Befehl lautet SetCursor. Die genaue Syntax dieser Funktion finden Sie im Anhang. Um den Einsatz von SetCursor zu demonstrieren, nehmen wir wieder einige Änderungen in unserem Beispielprogramm vor. Fügen Sie als erstes folgende Zeile hinter 66A ein:

/*66B*/HCURSOR vorigerCursor;

Dann ersetzen Sie die Zeile 68B und 68D durch die folgenden beiden Zeilen.

/*68B*/     vorigerCursor=SetCursor(LoadCursor(NULL,IDC_WAIT));
/*68D*/     SetCursor(vorigerCursor);

Übersetzen und starten Sie das Programm jetzt. Drücken Sie die linke Maustaste. Wenn Sie loslassen, verwandelt sich der Cursor in eine Sanduhr. Nach einigen Augenblicken, abhängig von der Schnelligkeit Ihres Rechners, erscheint der ursprüngliche quadratische Cursor wieder. Was ist dabei im einzelnen geschehen?
Sehen wir uns dazu die eingefügten Zeilen im Detail an!
Zeile 66B: In dieser Zeile wird eine Variable namens vorigerCursor deklariert. Sie soll vom Typ HCURSOR sein. Der Typ HCURSOR steht für unsigned int und ist identisch mit den anderen Bezügen wie HWND oder HICON. Die unterschiedlichen Namen für die Datentypen sind im wesentlichen gewählt worden, um bereits beim Lesen des Programmcodes feststellen zu können, welche Aufgabe die so deklarierte Variable hat.
Zeile 68B: Diese Zeile hat die Aufgabe, das Aussehen des Mauszeigers zu ändern. Dazu muß als erstes der gewünschte Cursor geladen werden. In diesem Fall ist es die Sanduhr, die mit dem Befehl LoadCursor(NULL,IDC_WAIT) geladen wird. Der Rückgabewert dieser Funktion ist ein Bezug (HCURSOR) auf den geladenen Mauszeiger. Dieser Bezug wiederum wird von der Funktion SetCursor als Parameter benötigt, um den Cursor schließlich anzuzeigen. Als letzte Aktion in dieser Zeile speichern wir den Rückgabewert von SetCursor in der Variablen vorigerCursor. Wie der Variablenname schon andeutet, liefert SetCursor nämlich den Bezug des alten Cursors, in unserem Fall das kleine Quadrat, zurück.
Zeile 68D: Hier wird der Cursor wieder in seine ursprüngliche Form zurückgesetzt. Den Bezug zu diesem Cursor hatten wir uns in Zeile 68B gemerkt.
Die Funktion scheint recht einfach zu benutzen zu sein, was auch der Fall ist. Man sollte allerdings noch etwas tiefer in die Abläufe schauen, um sie besser zu verstehen.
Damit die Sanduhr erscheinen kann, muß man die linke Maustaste gedrückt und wieder losgelassen haben. Mit dem Loslassen generiert Windows die Nachricht WM_LBUTTONUP. Da wir in unserem Programm diesen Fall abgefangen haben, kann jetzt das Umschalten des Cursors, die Pause und das Zurückschalten auf den Ursprungscursor erfolgen. So weit so gut! Löschen Sie jetzt die Zeile 68D vorübergehend, oder ändern Sie sie in Kommentar. Wenn Sie nun das Programm erneut starten, die linke Maustaste loslassen und dann sofort auch die Maus loslassen, behält der Mauszeiger die Form einer Sanduhr, obwohl die Zeit für die Schleifendurchläufe schon vergangen ist. Dieses Verhalten hatten wir auch erwartet.
Bewegen Sie jetzt die Maus! Schon erscheint der alte Cursor wieder! Und das, obwohl der Befehl SetCursor zum Zurücksetzen nicht mehr wirksam ist. Die Lösung des Rätsels liegt darin, daß die Funktion DefWindowProc bei jeder Mausbewegung die Nachricht WM_SETCURSOR erhält und daraufhin von sich aus den Mauszeiger wieder in seiner ursprünglichen Form darstellt. Überprüfen kann man das, indem man zusätzlich noch die folgenden Zeilen in die Fensterfunktion eingibt:

  case WM_SETCURSOR:
    return 0;

Damit bewirkt man, daß die Nachricht WM_SETCURSOR nicht an DefWindowProc weitergeleitet, sondern abgefangen wird. Wenn Sie jetzt die linke Maustaste loslassen und dann die Maus bewegen, behält der Cursor seine Form bei, es sei denn, Sie bewegen ihn in ein anderes Fenster. Dann nimmt der Cursor die dort gültige Form an. Kehren Sie in prg3_1 zurück, bleibt die neue Cursorform auch hier erhalten, da unser Programm ja die Nachricht zum Darstellen des Cursors ignoriert. Ein Programm, das den Cursor in seinem Fenster ändern muß, sollte sicherstellen, daß der Cursor für die Fensterklasse mit wc.hCursor=NULL auf NULL gesetzt wurde.
Machen Sie nun eventuelle Änderungen (WM_SETCURSOR) rückgängig, die Sie für diesen Test gemacht haben.

3.3 Meldungsfelder

Meldungsfelder gehören zwar nicht zu den Ressourcen, wir können sie aber als Vorstufe zu den Dialogen betrachten (siehe Bild 3.6) und wollen sie daher an dieser Stelle kurz vorstellen.
Meldungsfelder dienen dazu, dem Benutzer die Bestätigung eines ausgeführten Befehls zu geben oder ihn auf kritische Situationen hinzuweisen. Um Meldungsfelder zu erzeugen, benutzt man die Funktion MessageBox. Eine ausführliche Beschreibung der Funktion finden Sie im Anhang.
Fügen Sie folgende Zeile vor der Funktion PostQuitMessage ein, und starten Sie das Programm.

/*69B*/  MessageBox(fenster,"Ich mach Schluß!"
,NULL,MB_ICONSTOP | MB_OK);

Wenn nach dem Schließen des Fensters die Nachricht WM_DESTROY erzeugt wird, erscheint folgendes Meldungsfenster:

Bild 3.6: Meldungsfeld
Da Meldungsfelder eine einfache Art der Informationsausgabe auf dem Bildschirm sind, werden wir sie in den folgenden Beispielen häufiger benutzen.

3.4 Zeichenketten

Zeichenketten können wahlweise im Programmcode oder als Ressourcen definiert werden. Die Auslagerung in Ressourcen hat den Vorteil, daß man ziemlich einfach internationale Versionen von Programmen erstellen kann. Es muß dann nur noch die Ressource-Datei geändert werden; der Programmcode bleibt unangetastet.
Der erste Schritt bei der Festlegung der Zeichenketten-Ressource ist wieder der entsprechende Eintrag im Ressource-Skript. Für unser Beispiel wollen wir nur eine Zeichenkette definieren. Dazu wird folgendes in der Datei prg3_1.rc eingetragen:

STRINGTABLE
BEGIN
            1,      "That's all folks!"
END

Die Definition der Textressourcen wird durch das Schlüsselwort STRINGTABLE eingeleitet. Daran schließt sich ein Block an, der durch BEGIN und END markiert ist. Wenn Sie es übersichtlicher finden, können Sie das BEGIN auch durch eine öffnende geschweifte Klammer { und das END durch eine schließende } ersetzen. Innerhalb des Blocks werden dann alle Zeichenketten definiert. Dazu vergibt man eine eindeutige Nummer für jeden String. Die Zeichenketten dürfen dabei maximal 255 Zeichen lang sein.
Im Programm müssen zwei Zeilen hinzugefügt und eine geändert werden. Machen Sie diese Ergänzungen jetzt im Programm.

/*66C*/char zeichenkette[256];
/*69A*/     LoadString(Instanz,1,zeichenkette,sizeof(zeichenkette));
/*69B*/     MessageBox(fenster,zeichenkette,"Ende",MB_ICONSTOP | MB_OK);

Ist das Programm fehlerfrei erstellt worden, erscheint beim Schließen des Fensters die Meldung aus Bild 3.7.

Bild 3.7: Meldungsfeld mit geladener Textressource
Nun zu den Änderungen im Programm:
Zeile 66C: Die Variable zeichenkette dient zur Aufnahme des Strings.
Zeile 69A: Genau wie bei LoadIcon und LoadCursor muß die Textressource vor ihrer Benutzung geladen werden. Dazu dient die Funktion LoadString. Als ersten Parameter erwartet sie die Instanz des Programms. Diesen Bezug hat das Programm bei seinem Start von Windows mitgeteilt bekommen. In weiser Voraussicht haben wird uns diesen Wert in der globalen Variablen Instanz gemerkt und können ihn der Funktion jetzt mitgeben. Als zweites geben wir die Nummer der einzulesenden Zeichenkette an. Im Beispiel ist das die 1. Als dritter Parameter zeichenkette wird ein Puffer benötigt, in den der eingelesene String abgelegt wird. Der vierte und letzte Parameter gibt die maximale Länge an, bis zu der ein Text eingelesen werden soll.
Zeile 69B: In dieser Zeile sind zwei Änderungen gemacht worden; Erstens wurde der Text "Ich mach Schluß!" durch die Variable zeichenkette ersetzt, zweitens wurde statt der Standardüberschrift des Fensters (NULL erzeugt die Standardüberschrift "Fehler") der Text "Ende" gewählt.

3.5 Menüleisten und Befehle

Was unserem Programm bis jetzt noch fehlt, ist die übliche Menüleiste. Sie gehört auch zur Gruppe der Ressourcen und wird daher außerhalb des eigentlichen Programmcodes verwaltet. Auch hier liegt der Vorteil des separaten Verwaltens wieder darin, daß das Umstellen eines Programms in eine andere Sprache wesentlich erleichtert wird.
Die Definition eines Menüs sehen Sie in den folgenden Zeilen. Tragen Sie diese Zeilen in der Datei prg3_1.rc ein:

MenueFuerPrg3_1 MENU
{
	POPUP "&Datei"
	{
		MENUITEM "&Laden",		11,		
		MENUITEM "&Speichern",	12,	GRAYED
		MENUITEM SEPARATOR
		MENUITEM "&Beenden",	13
	}
	MENUITEM "&Vollbild",		2
	POPUP "\a&Hilfe"
	{
		MENUITEM "&Inhalt",	31
		MENUITEM SEPARATOR
		MENUITEM "&Info...",	32
	}	
}

Mit diesen Angaben haben Sie das Aussehen des Menüs bereits definiert. Jetzt muß nur noch dem Programm mitgeteilt werden, daß das Fenster ein Menü besitzt. Diese Eintragung machen Sie in Zeile 31.

/*31*/     wc.lpszMenuName="MenueFuerPrg3_1";

Das Ergebnis dieser Änderungen sehen Sie in Bild 3.8. Damit erweckt unser Minimalprogramm nach außen hin schon den Anschein eines vollständigen Programms, auch wenn die Auswahl eines Menüpunktes - abgesehen vom Systemmenü - noch keine Aktion auslöst.

Bild 3.8: Fenster mit Menüleiste
Nun zur Beschreibung der Menüdefinition in der Ressourcedatei. Dieser Abschnitt fängt mit dem Namen des Menüs an (MenueFuerPrg3_1), gefolgt vom Schlüsselwort MENU. Der folgende Block, der wieder wahlweise mit BEGIN und END oder { und } gebildet wird, enthält die Definition der Menüpunkte und Popups. Dabei werden einzelne Menüpunkte, gleichgültig ob sie in der Menüleiste oder in einem Popup sind, mit MENUITEM definiert. Sollen Menüpunkte in einem eigenen Fenster erscheinen, werden sie mit dem Schlüsselwörtern POPUP zusammengefaßt. Hinter den Schlüsselworten POPUP und MENUITEM folgt der Text des Menüpunktes. Soll ein Menüpunkt über ein Zeichen der Tastatur zu erreichen sein, wird vor das entsprechende Zeichen ein kaufmännisches Und (&) gesetzt. Dieses Zeichen wird nicht angezeigt, sondern bewirkt, daß das folgende Zeichen unterstrichen dargestellt wird. Hinter den Texten der Menuitems folgt dann noch eine eindeutige Nummer für diesen Befehl.
Bild 3.9 zeigt das Menü, das durch folgende Zeilen definiert wurde:

	POPUP "&Datei"
	{
		MENUITEM "&Laden",		11,		
		MENUITEM "&Speichern",	12,	GRAYED
		MENUITEM SEPARATOR
		MENUITEM "&Beenden",	13
	}


Bild 3.9: Geöffnetes Menü
Damit dürfte auch klar sein, welche Wirkung die Schlüsselwörter GRAYED bzw. SEPARATOR haben. GRAYED blendet einen Menüpunkt ab, so daß er nicht mehr anwählbar ist. SEPARATOR erzeugt eine Trennlinie im Menü, die die Übersichtlichkeit der Befehle verbessert. CHECKED würde ein Häkchen neben dem Befehl erzeugen.
Im Vorgriff auf die folgenden Programme können wir Ihnen auch gleich sagen, wie unser Programm erfährt, welcher Befehl aus dem Menü gewählt wurde. Wie Sie inzwischen wissen, läuft in Windows fast alles in Form von Nachrichten. Hier ist das nicht anders. Wählt der Benutzer einen Menüpunkt aus, so erzeugt Windows unter anderem die Nachricht WM_COMMAND mit der Nummer des gewählten Befehls. Und das war's schon. Jetzt kann das Programm auf den Befehl reagieren und die gewünschte Aktion ausführen.

3.6 Dialogfelder

Dialogfelder werden immer dann eingesetzt, wenn der Benutzer mehr Informationen eingeben muß, als sinnvoll über ein Menü auszuwählen sind. Zur Gruppe der Dialogfunktionen gehören ungefähr drei Dutzend Funktionen. Diese Tatsache allein zeigt schon, daß Dialoge ein wichtiger Bestandteil des Windows-Systems sind. In diesem letzten Teil des dritten Kapitels wollen wir uns mit den modalen Dialogen befassen.
Die Erstellung von Dialogfeldern ist verhältnismäßig aufwendig. Im einzelnen sind dazu Erweiterungen in folgenden Dateien nötig:
RC Definieren des Dialogfeldes mit allen benötigten Elementen wie zum Beispiel Schaltflächen, Texten oder Listboxen.

C Schreiben einer Funktion, die auf die Dialogbox reagiert. Diese Funktion ähnelt der Fensterfunktion.

DEF Eintragen der Dialogboxfunktion im Abschnitt EXPORTS.

Als ersten Schritt zur Erstellung eines Dialoges legen wir nun das Aussehen des Dialogfensters fest. Es kann direkt in der Ressourcedatei eingegeben werden oder mit einem entsprechenden Hilfsprogramm auf dem Bildschirm entworfen werden. Diese sogenannten Dialogeditoren sind als eigenständige Programme zu finden, oder sie sind in andere Tools integriert. Die Beschreibung selbst einer einfachen Dialogbox ist bereits recht umfangreich. Auch sind die Koordinaten der einzelnen Elemente nur mühselig manuell auszurechnen. Aus diesem Grund wird man immer einen Dialogeditor benutzen, um das Aussehen der Box zu definieren. Allenfalls kleinere Korrekturen werden von Hand durchgeführt. Für unser Beispiel werden wir den Eintrag in der Ressource-Datei ausnahmsweise manuell vornehmen.
Tragen Sie bitte die folgenden Zeilen in die Datei prg3_1.rc ein:

InfoBox  DIALOG  10, 10, 177, 92
STYLE    WS_DLGFRAME | WS_POPUP
CAPTION  "Info über PRG3_1"
BEGIN
  CTEXT     "InfoBox von PRG3_1",-1,55,20,79,12
  ICON      "GROSSESA",-1,12,20,0,0
  CTEXT     "V. Reher / H.Erlenk\366tter 1993",-1,37,44,107,12
  DEFPUSHBUTTON   "OK" IDOK,65,66,50,14
END

Zusätzlich wird die Zeile

#include <windows.h>

in prg3_1.rc benötigt, und zwar als erste Zeile.
Die Beschreibung einer Dialogbox beginnt mit dem Namen dieser Box. In unserem Beispiel haben wir sie InfoBox genannt. Hinter dem Namen folgen das Schlüsselwort DIALOG und die Koordinaten des Fensters. Die ersten beiden Werte geben die x- und y-Werte der linken oberen Ecke an. Die beiden letzten Werte bestimmen Breite und Höhe. Die Einheiten leiten sich aus den Abmessungen des Systemzeichensatzes her. Horizontale Einheiten entsprechen 1/4 der Grundeinheit, vertikale Einheiten 1/8 der Grundeinheit.
STYLE

CAPTION

BEGIN und END

CTEXT

ICON

DEFPUSHBUTTON

Die Änderungen im C-Programm sehen Sie unten. Als erstes fügen Sie bitte die folgende Funktion dem Programm hinzu:

/*75*/
/*76*/ BOOL FAR PASCAL InfoBoxFunktion(HWND BezugDialog,
/*77*/                                 WORD nachricht,
/*78*/                                 WORD parameter1,
/*79*/                                 LONG parameter2)
/*80*/ {
/*81*/   switch (nachricht)
/*82*/   {
/*83*/     case WM_INITDIALOG:
/*84*/       return TRUE;
/*85*/     case WM_COMMAND:
/*86*/       switch (parameter1)
/*87*/       {
/*88*/         case IDOK:
/*89*/         case IDCANCEL:
/*90*/           EndDialog(BezugDialog,0);
/*91*/           return TRUE;
/*92*/       }
/*93*/   }
/*94*/   return FALSE;
/*95*/ }

Diese Dialogfeldfunktion entspricht in vielen Punkten einer Fensterfunktion. Der wesentliche Unterschied ist wohl, daß eine Dialogfeldfunktion weitaus weniger zu tun hat als eine Fensterfunktion. Außerdem werden nicht behandelte Nachrichten nicht an eine Standardfunktion (DefWindowProc) weitergereicht, sondern in diesem Fall wird der Wert FALSE zurückgegeben. Wird die OK-Schaltfläche gedrückt oder die <Esc>-Taste betätigt, endet der Dialog mit EndDialog. Für jedes Dialogfeld im Programm gibt es eine eigene Dialogfeldfunktion.
Die Zeile 10 sorgt dafür, daß die Dialogfunktion einen Prototyp bekommt.

/*10*/ BOOL FAR PASCAL InfoBoxFunktion(HWND,WORD,WORD,LONG);

Neben dieser Dialogfeldfunktion müssen noch einige Änderungen im Programm erfolgen, damit die Dialogbox auch auf dem Bildschirm erscheinen kann. In der Zeile 66D wird eine Variable deklariert, die sich, vereinfacht gesagt, merkt, wo die Dialogfunktion zu finden ist.

/*66D*/static FARPROC ZeigerAufInfoBox;

In den Zeilen 68F-68P werden die Vorkehrungen getroffen, um die Dialogbox zu öffnen.

/*68F*/    case WM_CREATE:
/*68G*/      ZeigerAufInfoBox=MakeProcInstance(InfoBoxFunktion,Instanz);
/*68H*/      return 0;
/*68I*/    case WM_COMMAND:
/*68J*/      switch(parameter1)
/*68K*/       {
/*68L*/         case 32:
/*68M*/           DialogBox(Instanz,"InfoBox",fenster,ZeigerAufInfoBox);
/*68N*/           return 0;
/*68O*/       }
/*68P*/       break;

Zeile 68F: Die Nachricht WM_CREATE erscheint ganz zu Beginn beim Anlegen eines Fensters. Daher wird diese Nachricht häufig dazu benutzt, Initialisierungen durchzuführen.
Zeile 68G: In dieser Zeile besorgen wir uns die Adresse der Dialogfunktion mit der Funktion MakeProcInstance und speichern sie in der Variable ZeigerAufInfoBox. Deren Wert benötigen wir für das Öffnen des Dialoges in Zeile 68M.
Zeile 68I: Die Nachricht WM_COMMAND teilt dem Programm mit, daß ein Befehl aus der Menüleiste gewählt wurde. Die Kennziffer des Menüpunkts wird in der Variablen parameter1 geliefert. Den Wert dieser Kennziffer hatten wir bei Definition des Menüs in der Datei prg3_1.rc festgelegt.
Zeile 68L: Der Wert 32 bezieht sich auf die Kennziffer des Menüpunktes Info... in der Menüdefinition der Ressourcedatei.

/*68M*/           DialogBox(Instanz,"InfoBox",fenster,ZeigerAufInfoBox);

Zeile 68M: Die Funktion DialogBox erwartet als erstes die Instanz des Programms, hier in der Variablen Instanz gespeichert. Als zweites folgt der Name des Dialogs, wie er in der Ressourcedatei festgelegt wurde. Der dritte Wert ist der Bezug (engl.: handle) des Fensters, zu dem die Dialogbox gehört. Und der letzte Parameter sagt Windows, wo es die Dialogbox findet. Diesen Wert hatten wir mit der Funktion MakeProcInstance in Zeile 68G geholt.
Der letzte Schritt der Änderungen besteht darin, in der Datei prg3_1.def im Abschnitt EXPORTS die Zeile

InfoBoxFunktion @2

zu ergänzen.
Starten Sie jetzt das Programm, und wählen Sie den Befehl Info... Aus dem Menü Hilfe erscheint ein Dialogfenster wie in Bild 3.10 zu sehen.

Bild 3.10: Einfaches Dialogfeld
Damit haben wir die wesentlichen Ressourcen kennengelernt. In den folgenden Kapiteln werden wir sie immer wieder für die verschiedensten Aufgaben verwenden, um sicherer in ihrem Gebrauch zu werden. Ausgeklammert haben wir im Rahmen dieser Einführung die Abkürzungsbefehle für Menüs, die sogenannten ACCELERATORS.
Zum Abschluß des Kapitels finden Sie nochmals das C-Programm, die Ressourcedatei und die Definitionsdatei mit den Änderungen, die Sie im Laufe dieses Kapitels durchgeführt haben.
prg3_1.c


/*prg3_1.c*/
       #include <windows.h>
/* 3*/
/*==========================< Globale Variable >=========================== */
/* 5*/ HANDLE Instanz;
/* 6*/
/*=============================< Prototypen >============================== */
/* 8*/ int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);
/* 9*/ LONG FAR PASCAL FensterFunktion(HWND,WORD,WORD,LONG);
/*10*/ BOOL FAR PASCAL InfoBoxFunktion(HWND,WORD,WORD,LONG);
/*===========================< Hauptprogramm >============================= */
/*12*/ int PASCAL WinMain(HANDLE dieseInstanz,
/*13*/                    HANDLE vorigeInstanz,
/*14*/                    LPSTR  kommando,
/*15*/                    int    fenstertyp)
/*16*/ {
/*17*/ MSG  meldung;
/*18*/ HWND Hauptfenster;
/*19*/   Instanz = dieseInstanz;
/*20*/   if (!vorigeInstanz)
/*21*/   {
/*22*/   WNDCLASS wc;
/*23*/     wc.style=NULL;
/*24*/     wc.lpfnWndProc=FensterFunktion;
/*25*/     wc.cbClsExtra=0;
/*26*/     wc.cbWndExtra=0;
/*27*/     wc.hInstance=dieseInstanz;
/*28**/    wc.hIcon=LoadIcon(dieseInstanz,"grossesA");
/*29**/    wc.hCursor=LoadCursor(dieseInstanz,"QUADRAT");
/*30**/    wc.hbrBackground=GetStockObject(GRAY_BRUSH);
/*31*/     wc.lpszMenuName="MenueFuerPrg3_1";
/*32*/     wc.lpszClassName="Einfach";
/*33*/     if (!RegisterClass(&wc))
/*34*/     {
/*35*/       return 255;
/*36*/     }
/*37*/   }
/*38*/   Hauptfenster=CreateWindow( "Einfach",
/*39**/                      "Hello WinWorld 2!",
/*40*/                      WS_OVERLAPPEDWINDOW,
/*41*/                              CW_USEDEFAULT,
/*42*/                              CW_USEDEFAULT,
/*43*/                              CW_USEDEFAULT,
/*44*/                              CW_USEDEFAULT,
/*45*/                              NULL,
/*46*/                              NULL,
/*47*/                              dieseInstanz,
/*48*/                              NULL);
/*49*/   if (!Hauptfenster)
/*50*/   {
/*51*/      return 255;
/*52*/   }
/*53*/   ShowWindow(Hauptfenster, fenstertyp);
/*53A*/  UpdateWindow(Hauptfenster);
/*54*/   while (GetMessage(&meldung,0,0,0))
/*55*/   {
/*55A*/    TranslateMessage(&meldung);
/*56*/     DispatchMessage(&meldung);
/*57*/   }
/*58*/   return meldung.wParam;
/*59*/ }
/*60*/
/*===========================< Fensterfunktion >=========================== */
/*62*/ LONG FAR PASCAL FensterFunktion( HWND fenster,
/*63*/                      WORD nachricht,
/*64*/                      WORD parameter1,
/*65*/                      LONG parameter2)
/*66*/ {
/*66A*/long int x,y;
/*66B*/HCURSOR vorigerCursor;
/*66C*/char zeichenkette[256];
/*66D*/static FARPROC ZeigerAufInfoBox;
/*67*/   switch (nachricht)
/*68*/   {
/*68A*/    case WM_LBUTTONUP:
/*68B*/      vorigerCursor=SetCursor(LoadCursor(NULL,IDC_WAIT));
/*68C*/      for(x=1; x<=200000; x++) y++;
/*68D*/      SetCursor(vorigerCursor);
/*68E*/      return 0;
/*68F*/    case WM_CREATE:
/*68G*/      ZeigerAufInfoBox=MakeProcInstance(InfoBoxFunktion,Instanz);
/*68H*/      return 0;
/*68I*/    case WM_COMMAND:
/*68J*/      switch(parameter1)
/*68K*/       {
/*68L*/         case 32:
/*68M*/           DialogBox(Instanz,"InfoBox",fenster,ZeigerAufInfoBox);
/*68N*/           return 0;
/*68O*/       }
/*68P*/       break;
/*69*/     case WM_DESTROY:
/*69A*/      LoadString(Instanz,1,zeichenkette,sizeof(zeichenkette));
/*69B*/      MessageBox(fenster,zeichenkette,"Ende",MB_ICONSTOP | MB_OK);
/*70*/       PostQuitMessage(0);
/*71*/       return 0;
/*72*/   }
/*73*/   return DefWindowProc(fenster,nachricht,parameter1,parameter2);
/*74*/ }
/*75*/
/*76*/ BOOL FAR PASCAL InfoBoxFunktion(HWND BezugDialog,
/*77*/                                 WORD nachricht,
/*78*/                                 WORD parameter1,
/*79*/                                 LONG parameter2)
/*80*/ {
/*81*/   switch (nachricht)
/*82*/   {
/*83*/     case WM_INITDIALOG:
/*84*/       return TRUE;
/*85*/     case WM_COMMAND:
/*86*/       switch (parameter1)
/*87*/       {
/*88*/         case IDOK:
/*89*/         case IDCANCEL:
/*90*/           EndDialog(BezugDialog,0);
/*91*/           return TRUE;
/*92*/       }
/*93*/   }
/*94*/   return FALSE;
/*95*/ }

prg3_1.rc

#include <windows.h>

GROSSESA                ICON    DISCARDABLE     "A.ICO"


QUADRAT                 CURSOR  DISCARDABLE     "QUADRAT.CUR"


STRINGTABLE
BEGIN
	    1,      "That's all folks!"
END

MenueFuerPrg3_1 MENU
{
	POPUP "&Datei"
	{
		MENUITEM "&Laden",		11,
		MENUITEM "&Speichern",	12,	GRAYED
		MENUITEM SEPARATOR
		MENUITEM "&Beenden",	13
	}
	MENUITEM "&Vollbild",		2
	POPUP "\a&Hilfe"
	{
		MENUITEM "&Inhalt",	31
		MENUITEM SEPARATOR
		MENUITEM "&Info...",	32
	}
}

InfoBox  DIALOG  10, 10, 177, 92
STYLE    WS_DLGFRAME | WS_POPUP
CAPTION  "Info über PRG3_1"
BEGIN
  CTEXT     "InfoBox von PRG3_1",-1,55,20,79,12
  ICON      "GROSSESA",-1,12,20,0,0
  CTEXT     "V. Reher / H.Erlenk\366tter 1993",-1,37,44,107,12
  DEFPUSHBUTTON   "OK" IDOK,65,66,50,14
END

prg3_1.def

;Definitionsdatei PRG3_1.DEF

NAME PRG3_1
EXETYPE Windows
DESCRIPTION "Programm prg3_1"

STUB "WINSTUB.EXE"
CODE PRELOAD MOVABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE  1024
STACKSIZE 5120

EXPORTS
 FensterFunktion @1
 InfoBoxFunktion @2

Previous PageTop Of PageIndexList Of FiguresList Of TablesNext Page

This Web page was created using a Trial Version of HTML Transit 3.0.