Fensterklassen

Inhaltsverzeichnis

Fensterklassen
Beispiel
Erklärungen
EDIT
BUTTON
STATIC
SCROLLBAR
LISTBOX
COMBOBOX
Zusammenfassung

Im vorherigen Kapitel haben wir unsere eigene Fensterklasse My_Class erzeugt. Jede Fensterklasse wird durch eine Struktur des Typs WNDCLASSEX definiert. Dabei geht es sowohl um initiale Attribute der Fensterklasse als auch das Verhalten des Fensters. Dies wird hauptsächlich durch den Strukturmember lpszClassName (der Klassenname) und lpfnWndProc (der Zeiger auf die Window- Prozedur mit den Reaktionen auf bestimmte Ereignisse) realisiert.
Jedes Fenster, das mit einer bestimmten Fensterklasse erzeugt wird (durch CreateWindowEx()), hat die gleiche Window-Prozedur und damit das gleiche Verhalten. Dieses kann durch verschiedene Mechanismen verändert oder erweitert werden.

Windows stellt bereits 9 vordefinierte Fensterklassen zur Verfügung, mit denen sich alle üblichen Bedienelemente erzeugen lassen. Bei den in der Tabelle aufgeführten Fensterklassen handelt es sich um ASCIIZ-Strings. Die Angabe der Fensterklasse erfolgt beim Aufruf der Funktion CreateWindowEx():

.CONST
ID_EDIT EQU 39001

.DATA
cEditClass "edit",0

.CODE
  ..
  ..
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cEditClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR WS_HSCROLL OR WS_VSCROLL OR WS_BORDER \
         OR ES_LEFT OR ES_MULTILINE OR ES_AUTOHSCROLL OR ES_AUTOVSCROLL,
         0,0,100,100,hWin,ID_EDIT,hInstance,NULL
   ..

Der zweite Parameter (lpszClassName) gibt die Fensterklasse an (Groß/Kleinschreibung spielt hier keine Rolle), im vierten Parameter (dwStyle) kann das konkrete Erscheinungsbild bestimmt werden. Im Normalfall werden hier die Konstanten WS_CHILD und WS_VISIBLE mit anderen (bei der Fensterklasse genannten) Konstanten OR- verknüpft.

vordefinierte Fensterklassen
Fensterklasse Bedeutung
BUTTON Erzeugt eine rechteckige Schaltfläche, ein Kontrollkästchen, ein Optionsfeld, eine Gruppierungsbox oder eine selbstdefinierte Schaltfläche. Buttons können einzeln oder in Gruppen auftauchen, sie können eine Beschriftung haben und sie wechseln üblicherweise ihr Erscheinungsbild, wenn sie angeklickt werden.
Für den Parameter dwStyle können folgende zusätzlichen Stile verwendet werden: BS_PUSHBUTTON, BS_DEFPUSHBUTTON, BS_CHECKBOX, BS_AUTOCHECKBOX, BS_RADIOBUTTON, BS_3STATE, BS_AUTO3STATE, BS_GROUPBOX, BS_AUTORADIO, BS_OWNERDRAW
COMBOBOX Erzeugt ein Kombinationsfeld aus einer Dropdown-Listbox sowie einem Bearbeitungsfeld. Bei Eingabe in das Bearbeitungfeld wird automatisch das Element in der Listbox markiert, das mit den eingegebenen Zeichen beginnt.
CBS_LOWERCASE und CBS_UPPERCASE konvertieren die in das Bearbeitungsfeld eingegebenen Zeichen automatisch in Klein- bzw. Großbuchstaben. CBS_NOINTEGRALHEIGHT bewirkt die Benutzung der bei der Erzeugung des Controls angebenen Größe. Normalerweise sorgt Windows dafür, dass durch automatische Anpassung nur komplette Elemente angezeigt werden. Durch CBS_SIMPLE wird eine jederzeit aufgeklappte Listbox erzeugt, mit CBS_DROPDOWN wird die Liste erst nach Klick auf das Control angezeigt. CBS_SORT bewirkt eine alphanumerische Sortierung der Listenelemente.
EDIT Erzeugt ein Bearbeitungsfeld zur Texteingabe, das eine oder mehrere Zeilen umfassen kann. Das Eingabefeld übernimmt dabei die gesamte Tastatur- und Maussteuerung. Es wird sogar ein Kontextmenü für die Standard-Bearbeiten-Befehle generiert (Kopieren, Einfügen etc), das ohne weiteres Zutun funktioniert (nur ab Windows 2000 getestet). Die Fenster können, wenn sie mehrzeilig sind, mit Scrollbalken ausgestattet werden. Entsprechende Stile erlauben das automatische Scolling, zum Beispiel, wenn der Eingabecursor am visuellen Ende des Controls angekommen ist, aber weiterhin Text eingegeben wird. Bei Windows 95 und 98 ist der Inhalt von Edit-Fenstern auf ca. 30000 Zeichen begrenzt, bei Windows NT und seinen Nachfolgern nur durch den Hauptspeicher.
Für dwStyle können die mit ES_ beginnenden Konstanten verwendet werden. ES_LEFT, ES_RIGHT und ES_CENTER für die Textausrichtung, ES_MULTILINE für mehrzeilige Eingabefenster, ES_AUTOHSCROLL zum automatischen horizontalen Scrolling in einzeiligen, ES_AUTOVSCROLL zum automatischen vertikalen Scrolling in mehrzeiligen Controls, WS_HSCROLL und WS_SCROLL für Scrollbalken (wie bei normalen Fenstern) und ES_NOHIDESEL, um bei markiertem Text die Markierung auch anzuzeigen, wenn das Elternfenster nicht mehr den Fokus hat. ES_LOWERCASE und ES_UPPERCASE wirken wie CBS_LOWERCASE/CBS_UPPERCASE; ES_NUMBER erlaubt nur die Eingabe von Ziffern. ES_PASSWORD ersetzt in der Standardeinstellung die Darstellung jedes eingegebenen Zeichens durch einen Asterisk (*). ES_READONLY verhindert, dass der Nutzer Text in das Control eingeben oder ändern kann.
LISTBOX Erzeugt ein Auflistungfenster. Diese Fenster enthält eine Liste von Zeichenketten, aus denen ausgewählt werden kann. Beim Hinzufügen eines neuen Listenelements wird das Control neu gezeichnet.
Sobald ein Eintrag selektiert wurde, wird er markiert.
LBS_SORT wirkt wie CBS_SORT; eine Mehrfachauswahl wird durch LBS_EXTENDEDSEL ermöglicht. Mit WS_VSCROLL und WS_BORDER verpassen sie der Listbox vertikale Scrollbalken und einen Rahmen. Scrollbalken werden automatisch verwendet, sobald die Zeichenketten nicht mehr in die Listbox passen. Mit LBS_NOTIFY erwirken sie, dass das Control auf eine Selektion mit Ausgabe von Nachrichten des Typs WM_COMMAND an das Elternfenster reagiert. Das Neuzeichnen beim Hinzugügen eines neuen Elements kann mit LBS_NOREDRAW verhindert werden. Dies ist sinnvoll, wenn in ein bereits sichtbares Control viele Elemente eingefügt werden sollen. Die Konstante LBS_STANDARD fasst die üblichsten Stile zusammen.
MDICLIENT Ein Fenster dieses Typs empfängt Nachrichten, die die Fenster einer MDI-Anwendung (Multi Document Interface) steuern. Ein solches Fenster ist notwendig, wenn sie eine MDI-Anwendung entwickeln. Empfohlener Stil ist WS_CLIPCHILDREN.
RICHEDIT Diese Fensterklasse bezeichnet ein Steuerelement der Rich Edit-Version 1.0. Mit einem solchen Control kann Text mit verschiedenen Schriftarten, Stilen und Farben bearbeitet werden. Ein EDIT-Control kann diese Einstellungen immer nur für den gesamten Inhalt bieten.
RICHEDIT_CLASS Wie RICHEDIT, aber Version 2.0 oder 3.0. Bei Windows 2000 wird die Version 3.0 verwendet. Die Einbettung von OLE-Objekten ist möglich.
SCROLLBAR Erzeugt einen rechteckigen Bereich, der Nachrichten an das Parent-Window sendet, wenn es vom Nutzer verändert wird. Das Parent-Window ist dann für die Anpassung der Position des Scrollbalkens verantwortlich. Controls dieser Art werden z. B. für Lautstärkeregler, Zoomregler und vergleichbares verwendet.
STATIC Stellt statische Objekte dar, die weder Einnahmen entgegennehmen noch Ausgaben bieten. Beispiele sind statischer Text und Rahmen.

Beispiele

Das folgende Beispielprogramm bringt die Fensterklassen BUTTON, COMBOBOX, EDIT, LISTBOX, SCROLLBAR und STATIC zur Anzeige. Dabei werden je Fensterklasse immer mehrere Objekte angezeigt, um die Wirkung verschiedener Eigenschaften im Parameter dwStyle der API-Funktion CreateWindowEx() aufzuzeigen.

;winclass.asm - Fensterklassen
.386
.MODEL flat,stdcall
OPTION casemap:none

include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\gdi32.inc
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\gdi32.lib

WndProc PROTO :dword, :dword, :dword, :dword
initControls PROTO :dword

.CONST
ID_EDIT    EQU 39001
IDM_EXIT   EQU 40005

.DATA
szCaption db "Fensterklassen",0
szClassName db "My_Class",0
cFilter db "*.*",0
cEditClass db "edit",0
cButtonClass db "button",0
cStaticClass db "static",0
cScrollClass db "scrollbar",0
cListClass db "listbox",0
cComboClass db "combobox",0
iButtonStyles dd BS_PUSHBUTTON,BS_PUSHBUTTON + BS_FLAT,BS_DEFPUSHBUTTON,BS_CHECKBOX,
           BS_CHECKBOX + BS_LEFTTEXT,
           BS_AUTOCHECKBOX,BS_RADIOBUTTON,BS_AUTORADIOBUTTON,
           BS_3STATE,BS_AUTO3STATE,BS_GROUPBOX,BS_OWNERDRAW
iStaticStyles dd SS_BLACKRECT,SS_GRAYRECT,SS_WHITERECT,SS_BLACKFRAME,SS_GRAYFRAME,SS_WHITEFRAME,
                 SS_CENTER,SS_LEFT,SS_RIGHT,SS_SIMPLE,
                 SS_ETCHEDFRAME,SS_ETCHEDHORZ,
                 SS_ETCHEDVERT,SS_CENTER + SS_SUNKEN
iEditStyles dd WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_CENTER OR ES_AUTOHSCROLL,
               WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_LOWERCASE OR ES_AUTOHSCROLL,
               WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_RIGHT OR ES_AUTOHSCROLL,
               WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_UPPERCASE OR ES_AUTOHSCROLL,
               WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_PASSWORD OR ES_AUTOHSCROLL,
               WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_NUMBER OR ES_AUTOHSCROLL
cStylePB  db "PushButton",0
cStylePBF db "PushButtonFlat",0
cStyleDPB db "DefPushButton",0
cStyleCB  db "Checkbox",0
cStyleCBL db "CheckboxLeft",0
cStyleACB db "AutoCheckbox",0
cStyleRB  db "RadioButton",0
cStyleARB db "AutoRadioButton",0
cStyle3S  db "3State",0
cStyleA3S db "Auto3State",0
cStyleGB  db "GroupBox",0
cStyleOD  db "OwnerDraw",0
cListContent db "ABC0D4EFG7HIJ2KLMN1OP39QR5STU8VWX6YZ",0

.DATA?			;uninitialisierte Daten
hInstance HINSTANCE ?
hIcon HANDLE ?
hCursor HANDLE ?
hWnd HWND ?
cCmdline LPSTR ?
hEdit HANDLE ?
cStyles dd 12 dup (?)           
logfont LOGFONT <?>

.CODE
start:
  call mymain
  invoke ExitProcess,0


mymain PROC
  LOCAL wwd:dword,wht:dword,wtx:dword,wty:dword,wc:WNDCLASSEX
  
  invoke GetModuleHandle,NULL
  mov hInstance,eax
  invoke GetCommandLine
  mov cCmdline,eax
  
  ;call initControls
  mov wtx,CW_USEDEFAULT ;oder konkrete Angaben: 0
  mov wty,CW_USEDEFAULT ;0
  mov wwd,CW_USEDEFAULT ;400
  mov wht,CW_USEDEFAULT ;400
  
  mov wc.cbSize,SIZEOF WNDCLASSEX
  mov wc.style,CS_HREDRAW OR CS_VREDRAW ;OR CS_BYTEALIGNCLIENT OR CS_BYTEALIGNWINDOW
  mov wc.lpfnWndProc,OFFSET WndProc
  mov wc.cbClsExtra,NULL
  mov wc.cbWndExtra,NULL
  push hInstance
  pop wc.hInstance
  mov wc.hbrBackground,COLOR_BTNFACE+1
  mov wc.lpszMenuName,NULL
  mov wc.lpszClassName,OFFSET szClassName
  invoke LoadIcon,NULL,IDI_APPLICATION
  mov hIcon,eax
  mov wc.hIcon,eax
  mov wc.hIconSm,eax
  invoke LoadCursor,NULL,IDC_ARROW
  mov hCursor,eax
  mov wc.hCursor,eax
  
  invoke RegisterClassEx,ADDR wc
  
  invoke CreateWindowEx,WS_EX_LEFT,ADDR szClassName,ADDR szCaption,
                        WS_OVERLAPPEDWINDOW,wtx,wty,wwd,wht,NULL,NULL,hInstance,NULL
  mov hWnd,eax

  invoke ShowWindow,hWnd,SW_SHOWNORMAL
  invoke UpdateWindow,hWnd
  
  call MsgLoop
  ret
mymain ENDP
  

MsgLoop PROC
  LOCAL msg:MSG
  
  Startloop:
    invoke GetMessage,ADDR msg,NULL,0,0
    or eax,eax
    je Exitloop
    invoke TranslateMessage, ADDR msg
    invoke DispatchMessage,ADDR msg
    jmp Startloop
  Exitloop:
  mov eax,msg.wParam
  ret
MsgLoop ENDP

WndProc PROC hWin:dword,uMsg:dword,wParam:dword,lParam:dword
  LOCAL point:POINT                         ;neu
  .IF uMsg == WM_DESTROY
    invoke PostQuitMessage,NULL
  .ELSEIF uMsg == WM_CREATE
    invoke initControls,hWin
  .ELSEIF uMsg == WM_SIZE
    invoke SetFocus,hEdit
  .ELSEIF uMsg == WM_COMMAND
    mov eax,wParam
    .IF ax==IDM_EXIT
      invoke DestroyWindow,hWnd
    .ENDIF
  .ELSE
    invoke DefWindowProc,hWin,uMsg,wParam,lParam
    ret
  .ENDIF
  xor eax,eax
  ret
WndProc ENDP

initControls PROC USES eax ecx edx esi, hWin:dword
  LOCAL iControl:dword, hwnd1:HANDLE, hwnd2:HANDLE, iCount:dword, hFont: HFONT
  mov iControl,10
  
  invoke GetStockObject,ANSI_VAR_FONT                  ;Font aus dem Systemvorrat holen
  invoke GetObject,eax,SIZEOF LOGFONT,ADDR logfont     ;Font-Infos nach logfont schreiben
  invoke CreateFontIndirect,ADDR logfont               ;daraus eine log. Schrift erzeugen
  mov hFont,eax
  
  ;edit controls
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cEditClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR WS_HSCROLL OR WS_VSCROLL OR WS_BORDER \
         OR ES_LEFT OR ES_MULTILINE OR ES_AUTOHSCROLL OR ES_AUTOVSCROLL,
         0,0,120,100,hWin,iControl,hInstance,NULL
  inc iControl       
  mov hEdit,eax
  invoke SendMessage,eax,WM_SETFONT,hFont,0
  
  xor ecx,ecx
  mov hwnd1,-30
  editLoop:
    add hwnd1,30
    mov edx,[iEditStyles + ecx*4]
    push ecx
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cEditClass,NULL,\
           edx,125,hwnd1,120,25,hWin,iControl,hInstance,NULL
    pop ecx
    inc ecx
    inc iControl
    mov edx,[iEditStyles + ecx*4]
    push ecx
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cEditClass,NULL,\
           edx,250,hwnd1,120,25,hWin,iControl,hInstance,NULL
    pop ecx
    inc ecx
    inc iControl
    cmp ecx,6
    jne editLoop
    
  ;button controls
  mov eax,OFFSET cStyles
  mov [eax],OFFSET cStylePB
  mov [eax+4],OFFSET cStylePBF
  mov [eax+8],OFFSET cStyleDPB
  mov [eax+12],OFFSET cStyleCB
  mov [eax+16],OFFSET cStyleCBL
  mov [eax+20],OFFSET cStyleACB
  mov [eax+24],OFFSET cStyleRB
  mov [eax+28],OFFSET cStyleARB
  mov [eax+32],OFFSET cStyle3S
  mov [eax+36],OFFSET cStyleA3S
  mov [eax+40],OFFSET cStyleGB
  mov [eax+44],OFFSET cStyleOD

  xor ecx,ecx
  btnLoop:
    mov eax,25
    mul cl
    add eax,105
    mov esi,[cStyles + ecx*4]
    mov edx,[iButtonStyles + ecx*4]
    or edx,WS_CHILD OR WS_VISIBLE
    push ecx
    ;invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cButtonClass,esi,\
    invoke CreateWindowEx,0,ADDR cButtonClass,esi,\
           edx,5,eax,140,24,hWin,iControl,hInstance,NULL
    invoke SendMessage,eax,WM_SETFONT,hFont,0
    pop ecx       
    inc ecx
    inc iControl
    cmp ecx,12
    jne btnLoop
  
  ;static controls
  xor ecx,ecx
  staticLoop:
    mov eax,25
    mul cl
    add eax,105
    mov edx,[iStaticStyles + ecx*4]
    or edx,WS_CHILD OR WS_VISIBLE
    push ecx
    invoke CreateWindowEx,0,ADDR cStaticClass,ADDR cStaticClass,\
           edx,150,eax,140,24,hWin,iControl,hInstance,NULL
    invoke SendMessage,eax,WM_SETFONT,hFont,0
    pop ecx
    inc ecx
    inc iControl
    cmp ecx,14
    jne staticLoop
    
  ;scroll controls
  mov iCount,2
  mov hwnd1,105
  scrollLoop1:
    push 300
    invoke CreateWindowEx,0,ADDR cScrollClass,NULL,\
           WS_CHILD OR WS_VISIBLE OR SBS_HORZ,295,hwnd1,140,34,hWin,iControl,hInstance,NULL
    inc iControl
    pop hwnd1
    dec iCount
    jnz scrollLoop1
    
  mov iCount,2
  mov hwnd1,295
  scrollLoop2:
    push 401
    invoke CreateWindowEx,0,ADDR cScrollClass,NULL,\
           WS_CHILD OR WS_VISIBLE OR SBS_VERT,hwnd1,150,34,140,hWin,iControl,hInstance,NULL
    inc iControl
    pop hwnd1
    dec iCount
    jnz scrollLoop2

  ;list controls
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cListClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR LBS_STANDARD OR LBS_EXTENDEDSEL OR LBS_NOINTEGRALHEIGHT,\
         440,105,120,127,hWin,iControl,hInstance,NULL
  inc iControl
  mov hwnd1,eax
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cListClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR LBS_NOTIFY OR WS_VSCROLL OR WS_BORDER OR LBS_MULTIPLESEL,\
         440,250,120,127,hWin,iControl,hInstance,NULL
  inc iControl
  mov hwnd2,eax
  mov iCount,36
  mov esi,OFFSET cListContent
  listfillLoop1:
    invoke SendMessage,hwnd1,LB_ADDSTRING,0,esi
    invoke SendMessage,hwnd2,LB_ADDSTRING,0,esi
    inc esi
    dec iCount
    jnz listfillLoop1

  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cListClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR LBS_STANDARD OR LBS_MULTIPLESEL,\
         440,390,120,127,hWin,iControl,hInstance,NULL
  inc iControl
  invoke SendMessage,eax,LB_DIR,DDL_READWRITE OR DDL_HIDDEN OR DDL_DIRECTORY OR 4000h,\
         ADDR cFilter

  ;combobox controls
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cComboClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR WS_VSCROLL OR CBS_DROPDOWN,\
         580,105,120,127,hWin,iControl,hInstance,NULL
  inc iControl
  mov hwnd1,eax
  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cComboClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR WS_VSCROLL OR CBS_SIMPLE OR CBS_SORT OR CBS_AUTOHSCROLL,\
         580,250,120,127,hWin,iControl,hInstance,NULL
  inc iControl
  mov hwnd2,eax
  mov iCount,36
  mov esi,OFFSET cListContent
  combofillLoop1:
    invoke SendMessage,hwnd1,CB_ADDSTRING,0,esi
    invoke SendMessage,hwnd2,CB_ADDSTRING,0,esi
    inc esi
    dec iCount
    jnz combofillLoop1

  invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR cComboClass,NULL,\
         WS_CHILD OR WS_VISIBLE OR WS_VSCROLL OR CBS_DROPDOWN OR CBS_UPPERCASE OR CBS_SORT,\
         580,390,120,127,hWin,iControl,hInstance,NULL
  inc iControl
  invoke SendMessage,eax,CB_DIR,DDL_READWRITE OR DDL_HIDDEN OR DDL_DIRECTORY OR 4000h,\
         ADDR cFilter
  ret
initControls ENDP

END start

Erklärungen

Die Fensterprozedur WndProc ist hier recht kurz ausgefallen. Die Aufgabe, die Steuerelemente zu erzeugen, wird von der Prozedur initControls erfüllt. Diese Prozedur wird in der Behandlung des Ereignissen WM_CREATE aufgerufen, also noch bevor das Fenster auf dem Bildschirm angezeigt wird. Da die zu erzeugenden Steuerelemente Kindelemente des Hauptfensters sind, muss das Handle des Hauptfensters als Parameter mitgegeben werden.

Die Prozedur initControls überlässt die Codeerzeugung für die Sicherung der in der Prozedur benutzen Register MASM (USES eax ecx edx esi). Zusätzlich werden ein paar lokale Variablen definiert, wobei hwnd1 und hwnd2 trotz ihres Namens und ihres Datentyps in der Prozedur teilweise als normale Doubleword-Variablen verwendet werden.

Für in ein anderes Fenster eingebettete sichtbare Steuerelemente werden die Konstanten WS_CHILD und WS_VISIBLE verwendet.
Jede Fensterklasse hat für sich gültige Fensterstile. Die allgemein gültigen Fensterstilkonstanten beginnen mit WS_ (window style), die speziellen Konstanten beginnen mit Zeichen, die die Fensterklasse widerspiegeln (ES_ - edit style, BS_ - button style etc). Die Konstanten werden jeweils mit OR verknüpft. Die Beschreibung aller Stile können sie in der entsprechenden Dokumentation nachlesen, z. B. bei/im MSDN. Die Win32-API- Hilfedatei ist leider nicht mehr ganz taufrisch - deswegen fehlen dort einige Stile.

Im 9. Parameter (hWndParent) von CreateWindowEx() wird jeweils das Handle des Elternfensters angegeben (hWin), bei Hauptfenstern steht hier NULL oder 0. Im 10. Parameter (hMenu) wird kein Menühandle hinterlegt wie der Parametername weismachen will, sondern die ID des Steuerelements. In der Prozedur initControls wird dazu die Variable iControl geführt, die einen Startwert von 10 hat und bei jedem Aufruf von CreateWindowEx() um eins erhöht wird.

EDIT

Zu Beginn wird ein mehrzeiliges Editorfeld erzeugt. Dazu wird die Fensterklasse EDIT verwendet (steht in der Variablen cEditClass; die Schreibweise spielt bei diesen Fensterklassen keine Rolle, im Programm sind alle in Kleinbuchstaben definiert).

Das Editorfenster erhält neben den Standardstilen noch horizontale und vertikale Bildlaufleisten (WS_HSCROLL und WS_VSCROLL) sowie einen Rahmen (WS_BORDER). Durch spezielle Fensterstile wird angegeben, dass die Textausrichtung linksbündig (ES_LEFT) und mehrzeilig (ES_MULTILINE) erfolgen soll. Die Stile ES_AUTOHSCROLL und ES_AUTOVSCROLL bewirken ein automatischen Scrollen des Textes, wenn über den rechten oder unteren Rand hinaus Eingaben erfolgen.

Im Anschluss werden sechs einzeilige Eingabefelder erzeugt. Deren Erzeugung läuft in einer Schleife, die bei jedem Durchlauf zwei Felder anlegt. Dazu wurden die verschiedenen Stilkombinationen in der Variablen iEditStyles hinterlegt. Der Variablen hwnd1 wird in jedem Schleifendurchlauf die Y-Position der Eingabefelder zugewiesen, Startwert ist 0. In das Register ECX wird in jedem Durchlauf die aktuelle Stilkombination geschrieben. Diese wird von der Adresse gelesen, die sich aus dem Offset der Variable iEditStyles und dem Produkt des Zählregisters ECX x 4 errechnet. Je Schleifendurchlauf wird demzufolge von OFFSET iEditStyles + 0 und + 4, + 8 und + 12 sowie + 16 und + 20 gelesen. Im Aufruf von CreateWindowEx() werden die jeweiligen Parameter mit den Werten aus EDX und hwnd1 befüllt.

Die sechs Eingabefelder werden mit den Textausrichtungen zentriert (ES_CENTER) und rechtsbündig (ES_RIGHT) definiert. ES_LOWERCASE und ES_UPPERCASE sorgen für eine automatische Konvertierung der eingegebenen Zeichen. Mit ES_PASSWORD wird jedes eingegebene Zeichen mit einem Sternchen dargestellt. Durch eine Nachricht des Typs EM_SETPASSWORDCHAR kann dieses Zeichen umdefiniert werden. ES_NUMBER gestattet nur die Eingabe von Ziffern. Damit wird allerdings auch die Eingabe von Punkt, Komma und Vorzeichen abgelehnt.

Das Zählregister ECX wird vor jedem Aufruf von CreateWindowEx() gesichert, da der Inhalt durch die Funktion verändert wird. Eine Variable kommt hier nicht in Frage, da sonst das Adressierungsschema nicht mehr verwendet werden kann.

BUTTON

Ein vergleichbares Verfahren wird bei der Erzeugung der verschiedenen Objekte aus der Klasse BUTTON angewendet. Hier kommt allerdings noch die Tabelle cStyles hinzu, deren Elemente im Vorfeld die Adressen einer Reihe von Zeichenketten erhalten. Diese Zeichenketten haben nichts mit dem Fensterstil zu tun, vielmehr handelt es sich um die Beschriftung der Schaltflächen, deren Adresse im Parameter lpWindowName übergeben wird. Bei normalen Fenstern wird die an dieser Adresse liegende Zeichenkette in der Titelleiste ausgegeben, bei den Fensterklassen BUTTON und STATIC handelt es sich um Beschriftungen.

BS_PUSHBUTTON erzeugt eine normale Schaltfläche, durch BS_FLAT wird sie flach dargestellt. BS_DEFPUSHBUTTON erzeugt ebenfalls eine normale Schaltfläche, allerdings wird sie in Dialogen als Standardschaltfläche (def - default) verwendet. In einem Fenster verhalten sich beide Schaltflächen identisch, im Vergleich zu BS_PUSHBUTTON hat BS_DEFPUSHBUTTON einen etwas dickeren Rahmen.

BS_CHECKBOX erzeugt eine Optionsschaltfläche. Diese kann die Zustände An und Aus annehmen, die Beschriftung steht rechts vom Ankreuzfeld; mit BS_LEFTTEXT kann die Beschriftung auf die linke Seite gesetzt werden. Wie sie sehen tut sich bei Betätigen dieser Schaltflächen nicht viel, zumindest wird kein Haken in das Feld gesetzt. Dieses Verhalten zeigt sich allerdings bei BS_AUTOCHECKBOX. Wenn Sie BS_CHECKBOX umschalten möchten, dann müssen sie dem Steuerelement eine explizite Nachricht schicken: invoke SendMessage,hBtn,BM_SETCHECK,0,0 zum Ausschalten und invoke SendMessage,hBtn,BM_SETCHECK,1,0 zum Anschalten. Den aktuellen Zustand können sie mit invoke SendMessage,hBtn,BM_GETCHECK,0,0 abfragen.

Ein einzelnes Element des Typs BS_RADIOBUTTON ergibt eigentlich keinen Sinn, weil mit diesen Steuerelemente eine von mehreren sich gegenseitig ausschließenden Optionen gewählt werden kann. Es gibt mit BS_AUTORADIOBUTTON wieder ein Gegenstück, bei dem der Status nicht manuell geändert werden muss. Ansonsten werden hier die gleichen Nachrichten wie bei BS_CHECKBOX verwendet.

BS_3STATE und BS_AUTO3STATE sind im Grunde das gleiche wie BS_CHECKBOX und BS_AUTOCHECKBOX. Wie der Name aber bereits andeutet, können diese Steuerelemente noch einen dritten Zustand anzeigen, bei dem das Kästchen mit grauer Farbe gef¨llt wird. Bei der Nachricht BM_SETCHECK muss in wParam (3. Parameter) eine 2 stehen, um diesen Zustand einzustellen.

BS_GROUPBOX passt nicht so ganz in das Schema. Steuerelemente mit diesem Stil können nicht angeklickt werden und reagieren nicht auf Tastaturereignisse. Das einzige was man mit ihnen machen kann ist, bestimmte Steuerelemente zu umrahmen sowie die Bezeichnung dieses Rahmens ändern oder auslesen.

BS_OWNERDRAW wird für Schaltflächen verwendet, deren Aussehen selbst programmiert wird. Windows beschränkt sich hier auf die Prüfung, ob das Steuerelement angeklickt wurde sowie auf die Nachrichtenweiterleitung.

STATIC

Statische Elemente sind einfach nur da. Sie verarbeiten keine Nachrichten und sie senden keine Nachrichten.
Die Stile SS_BLACKRECT, SS_GRAYRECT und SS_WHITERECT erzeugen ein mit der entsprechenden Farbe ausgefülltes Rechteck, SS_BLACKFRAME, SS_GRAYFRAME und SS_WHITEFRAME zeichnen Rahmen in der entsprechenden Farbe.
SS_CENTER, SS_LEFT, SS_RIGHT zeichnen die als lpWindowName übergebene Zeichenkette mit der jeweiligen Ausrichtung. SS_SIMPLE entspricht SS_LEFT.
SS_ETCHEDFRAME stellt einen eingesunkenen Rahmen dar, bei SS_ETCHEDHORZ und SS_ETCHEDVERT wird nur die horizontale oder vertikale Seite dargestellt.
Mit SS_SUNKEN wird das gesamte Steuerelement eingesunken dargestellt.

SCROLLBAR

Die Fensterklasse SCROLLBAR wird hauptsächlich angewendet, wenn grafische Entsprechungen von (Schiebe)Reglern (Farbtiefe, Lautstärke, Zoom) angezeigt werden sollen. Eine Verschiebung wird mit Nachrichten des Typs WM_HSCROLL oder WM_VSCROLL an die Fensterprozedur gemeldet. Da dies die gleichen Nachrichten sind, die auch von Bildlaufleisten gesendet werden, muss über den Parameter lParam die Quelle ermittelt werden. Steht hier 0, dann ist es eine Bildlaufleiste, bei einem Steuerelement enthält lParam das Handle des Elements.
Die Steuerung erfolgt über die Funktionen SetScrollInfo() und GetScrollInfo(), die jeweils eine Struktur des Typs SCROLLINFO erwarten bzw. füllen.
Ansonsten gibt es noch die aus Kompatibilitätsgründen vorhandenen Funktionen GetScrollRange(), SetScrollRange(), GetScrollPos() und SetScrollPos(), die allesamt ohne SCROLLINFO auskommen.

LISTBOX

Wie der Name schon sagt, werden mit diesem Steuerelement Zeichenketten in einer Liste dargestellt. Diese Liste ist im Normalfall mit einer vertikalen Bildlaufleiste (WS_VSCROLL) ausgestattet. Der Nutzer kann ein Element der Liste auswählen, mit dem Stil LSB_MULTIPLESEL können mehrere Elemente ausgewählt werden. Die Listenelemente werden durch einfaches Klicken aktiviert oder deaktiviert. Mit LBS_EXTENDEDSEL können mit Hilfe der Tasten STRG oder SHIFT mehrere Listenelemente selektiert werden.

Eine Listbox wird von Windows so dargestellt, dass ein Element immer in seiner kompletten Höhe zu sehen ist. Mit LBS_NOINTEGRALHEIGHT kann das ausgeschaltet werden. Damit nimmt das Steuerlelement genau die bei CreateWindowEx() angegebene Höhe an.

Der Stil LBS_SORT sorgt für eine automatische alphabetische Sortierung in aufsteigender Reihenfolge. Mit LBS_NOTIFY sendet das Steuerelement bei der Wahl von Listenelementen Nachrichten des Typs WM_COMMAND. Diese beiden Stile sowie WS_VSCROLL und WS_BORDER sind im Stil LB_STANDARD zusammengefasst.

Listen werden durch Nachrichten des Typs LB_ADDSTRING gefüllt. Durch jede dieser Nachrichten wird das Feld dazu gebracht, sich selbst neu zu zeichnen. Um dies für die Dauer des Füllens zu verhindern, kann LB_ADDSTRING durch invoke SendMessage,hList,WM_SETREDRAW,FALSE,0 und invoke SendMessage,hList,BM_SETREDRAW,TRUE,0 eingerahmt werden. Das lohnt aber nur, wenn das Steuerelement bereits auf dem Bildschirm angezeigt wird und die Anzahl neuer Elemente ausreichend hoch ist. Hat die Listbox den Stil LBS_SORT, dann werden die neuen Elemente auch gleich einsortiert.

Eine Besonderheit stellt die Nachricht LB_DIR dar, die die Liste mit dem Inhalt des aktuellen Verzeichnisses füllt. Die entsprechende Dateimaske wird durch lParam angegeben, die Attribute der anzuzeigenden Verzeichniseinträge werden mit wParam angegeben. Dabei steht DDL_READWRITE für normale Dateien, DDL_READONLY, DDL_HIDDEN,DDL_SYSTEM, DDL_DIRECTORY und DDL_ARCHIVE sollten klar sein. Dazu gibt es noch die Konstanten 4000h (Laufwerksbuchstaben aufnehmen) und 8000h (nur Dateien mit den angegebenen Attributen aufnehmen). Um also alle Dateien und Unterverzeichnisse des aktuellen Verzeichnisses sowie die verfügbaren Laufwerke aufzunehmen, wird invoke SendMessage,hList,LB_DIR,DDL_READWRITE OR DDL_HIDDEN OR DDL_DIRECTORY OR 4000h,ADDR cFilter reichen.

COMBOBOX

Eine Combobox ist vergleichbar mit einer Listbox, allerdings kommt hier noch ein Eingabefeld hinzu. Bei einer Combobox kann das Listenfeld eingeklappt sein (CBS_DROPDOWN) oder immer sichtbar (CBS_SIMPLE). Mit WS_VSCROLL hat die Liste eine vertikale Bildlaufleiste. Diese ist normalerweise nicht sichtbar, wenn die Liste weniger Elemente enthält als in ihr darstellbar sind. Mit CBS_DISABLENOSCROLL wird die Bildlaufleiste immer dargestellt, sie wird aber bei zu wenigen Listenelementen deaktiviert. Mit CBS_AUTOHSCROLL ist ein horizontales Scrollen im Eingabefeld möglich. CBS_SORT wirkt wie LBS_SORT, CBS_UPPERCASE und CBS_LOWERCASE konvertieren die eingegebenen oder selektierten Daten in Klein- oder Großbuchstaben.

CB_ADDSTRING und CB_DIR wirken wie LB_ADDSTRING und LB_DIR bei einer Listbox.

Zusammenfassung

Das hier gezeigte ist nur ein Teil dessen was möglich ist. Mit jeder neuen Windows-Version kommen neue Stile hinzu. Bei einigen Steuerelementen kann dwExtraStyle in CreateWindowEx verwendet werden, bei anderen passt es nicht so richtig. Ebenso wurden die Grenzen der Kombinierbarkeit der Stile nicht ausgelotet. Hier ist ihre Experimentierfreude gefragt.

Was im ganzen Programm nicht die geringste Rolle spielte waren Reaktionen auf die Ereignisse in den Steuerelementen. Die Darstellung erfolgt mit Schriften, die mittels GetStockObject aus dem Systemvorrat von Windows entnommen werden. Für das erste Edit-Control sowie alle Button- und Static-Controls wurde mit ANSI_VAR_FONT eine Schriftart mit proportionalem Zeichenabstand verwendet. Alle anderen Controls werden mit der im System eingestellten Standardschriftart gezeichnet, i. A. die Schriftart System Wenn diese Schriftarten in ihrem Windows-Systemvorrat größer eingestellt sind als manche Steuerelemente hoch sind, dann leidet darunter natürlich die Darstellung. Ganz davon abgesehen, dass die Schriftart System i. d. R. nichts ist, das man einem Anwender zumuten will.

Auf die Ereignisbehandlung wurde bewusst verzichtet. Für einzelne Steuerelemente wird auf dieses Thema später detaillierter eingegangen, wenn es um Dialoge geht. Die Fensterklassen MDICLIENT, RICHEDIT und RICHEDIT_CLASS wurden wegen der mit ihnen verbundenen Komplexität ebenfalls nicht behandelt.