Um zu verstehen, warum man in C einen Standard eingeführt hat bedarf es ein wenig mehr der Geschichte zu dieser Sprache.C C++ C/C++ Programmieren C Kurs Programmierung Systemprogrammierung Win32 api Win-Api Windows Systemprogrammierung C Programmierung Win32 api Win-Api Windows Systemprogrammierung Kapitel 5: Dialogfelder

Wenn der Benutzer mehrere Informationen eingeben muss, reicht ein Menü häufig nicht mehr aus. Dann werden so genannte Dialogfelder verwendet. Dialogfelder werden mithilfe von Schablonen erstellt, welche die Steuerelemente im Dialogfeld definieren. Ein solches Dialogfeld wird mit dem Resourcen-Typ DIALOGEX in einer Resourcen-Skriptdatei erstellt. Die Anzahl der Schablonen dazu sind gewaltig. Natürlich ist es auch möglich Dialogfelder während der Laufzeit dynamisch zu erzeugen. Aber darauf wird hier nicht eingegangen.

In der Regel wird meistens ein moderaler Dialogfeldtyp verwendet. Bekanntes Beispiel: Sie wollen eine Datei in Ihrem Texteditor öffnen. Kurz darauf erscheint eine Box, womit Sie die Datei zum Öffnen aus dem Verzeichnis suchen können. Solange Sie jetzt keine Datei zum Öffnen ausgewählt haben, wird der Zugriff auf anderen Funktionen derselben Anwendung blockiert. Zwischen anderen Anwendungen können Sie aber weiterhin hin- und herschalten.

Nichtmoderale Dialogfeldtypen müssen Sie im Programm mit der Funktion CreateDialog() erst erzeugen. Damit nichtmoderale Dialogfeldtypen auch alle auf dem Bildschirm bleiben, müssen Sie die Nachrichten in der Nachrichtenschleife mit der Funktion IsDialogMessage() auswerten. Solche Dialogfeldtypen sind Ihnen vielleicht aus Grafikprogrammen bekannt, worin sich in mehreren Dialogfeldern so genannte Werkzeugsammlungen befinden. In diesem Tutorial werden die nichtmoderalen Dialogfeldtypen nicht behandelt.

5.1. Die Ressourcen-Skriptedatei und die Dialogfeldschablonen            zurück  zum Inhaltsverzeichnis

Damit Sie eine Vorstellung für die Schablonen der Dialogfelder bekommen, folgt hierzu die Resourcen-Skriptedatei mit entsprechenden Erklärung im Anschluss daran.

#include <windows.h>
#include "resource.h"

/////////////////////////////////////////////////////////////////
//
// Menü
//

IDR_MENU MENU
BEGIN
    POPUP "Dialogfelder"
    BEGIN
        MENUITEM "Radio && Checkbox",             ID_MENU_RADIO_CHECK
        MENUITEM "Editfeld",                      ID_EDITFELD
        MENUITEM "Listbox",                       ID_LISTBOX
        MENUITEM "Beenden",                       ID_EXIT
    END
    MENUITEM "?",                                 ID_HELP
END

/////////////////////////////////////////////////////////////////
//
// Dialogfeld mit Radio- und Checkbutton
//

IDR_DIALOG DIALOGEX 20, 20, 170, 100
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Dialogfeld (Check- und Radiobutton)"
FONT 8, "MS Sans Serif"
BEGIN
    CHECKBOX        "Checkbox 1",IDC_CHECKBOX1,9,7,70,10
    CHECKBOX        "Checkbox 2",IDC_CHECKBOX2,9,17,70,10
    GROUPBOX        "Radiobuttons",-1,5,30,86,50
    RADIOBUTTON     "Radio 1", IDC_RADIO1,20,43,37,10,WS_GROUP |
                                                     WS_TABSTOP
    RADIOBUTTON     "Radio 2",IDC_RADIO2,20,53,39,10
    RADIOBUTTON     "Radio 3",IDC_RADIO3,20,63,41,10
    PUSHBUTTON      "&Fertig",IDCANCEL,116,8,50,14,WS_GROUP
END

/////////////////////////////////////////////////////////////////
//
// Dialogfeld mit EDITTEXT
//

IDR_TEXTDIALOG DIALOGEX 20, 20, 180, 70
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
                                              WS_SYSMENU
CAPTION "Dialogfeld (Textfeld)"
FONT 8, "MS Sans Serif"
BEGIN
   LTEXT "Passwort     : ", -1, 36, 8, 45, 8
   EDITTEXT IDC_EDIT1, 83,6,61,13, ES_AUTOHSCROLL | WS_BORDER
   LTEXT "Geheimnummer : ", -1, 36, 24, 45, 8
   EDITTEXT IDC_EDIT2, 83,22,61,13, ES_AUTOHSCROLL | WS_BORDER
   PUSHBUTTON "&Bestätigen", IDOK, 33, 50, 50, 14
   PUSHBUTTON "&Abbrechen", IDCANCEL, 95, 50, 50 ,14,WS_GROUP
END

/////////////////////////////////////////////////////////////////
//
// Dialogfeld mit EDITTEXT
//

IDR_LISTBOX DIALOGEX  20, 20, 150, 110
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Listbox"
FONT 8, "MS Sans Serif"
BEGIN
    EDITTEXT        IDC_DIRECTORY,6,5,136,13,ES_AUTOHSCROLL |
                                             ES_READONLY |
                                             NOT WS_TABSTOP
    LISTBOX         IDC_LIST,6,20,136,59,LBS_SORT |
                                         LBS_NOINTEGRALHEIGHT |
                                         LBS_DISABLENOSCROLL |
                                         WS_VSCROLL |
                                         WS_TABSTOP
    PUSHBUTTON      "&Abbrechen",IDCANCEL,50,87,50,14,WS_GROUP
END

/////////////////////////////////////////////////////////////////
//
//Icon
//
ID_ICON              ICON        "goofy.ico"

Das Dialogfeld MENU und ICON ist Ihnen noch aus dem Kapitel zuvor geläufig und deshalb soll darauf nicht mehr allzu sehr eingegangen werden. Mit diesen Angaben sieht das Menü mit seinen Elementen wie folgt aus:

Menü zur Demonstration der Dialogfelder

Menü zur Demonstration der Dialogfelder

Weiter mit der Resourcen-Skriptedatei:

IDR_DIALOG DIALOGEX 20, 20, 170, 100
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Dialogfeld (Check- und Radiobutton)"
FONT 8, "MS Sans Serif"
BEGIN
    CHECKBOX        "Checkbox 1",IDC_CHECKBOX1,9,7,70,10
    CHECKBOX        "Checkbox 2",IDC_CHECKBOX2,9,17,70,10
    GROUPBOX        "Radiobuttons",-1,5,30,86,50
    RADIOBUTTON     "Radio 1", IDC_RADIO1,20,43,37,10,WS_GROUP |
                                                      WS_TABSTOP
    RADIOBUTTON     "Radio 2",IDC_RADIO2,20,53,39,10
    RADIOBUTTON     "Radio 3",IDC_RADIO3,20,63,41,10
    PUSHBUTTON      "&Fertig",IDCANCEL,116,8,50,14,WS_GROUP
END

Mit diesen Zeilen wird ein Dialogfeld mit Check- und Radiobuttons erstellt. Eingeleitet wird ein Resourcen-Typus für ein Dialogfeld immer mit DIALOGEX. Die einzelnen Parameter der Schablone DIALOGEX im Überblick:

Angabe Bedeutung
IDR_DIALOG Die Idenfikation des Dialogfeldes, welche benötigt wird um diese Resource zu laden. IDR_DIALOG muss eine 16-Bit-Zahl sein. Der Wert dieser Ressource wurde im Beispiel hier, in der Headerdatei resource.h definiert.
DIALOGEX Anfang eines Dialogfeldes, Name der Ressource.
20,20,170,100(x,y,width,height) Postion und Größe des Dialogfeldes
STYLE DS_MODALFRAME|WS_POPUP| WS_VISIBLE|WS_CAPTION|WS_SYSMENUCAPTION "Dialogfeld"FONT 8, "MS Sans Serif" Optionen für das Dialogfeld. Mit STYLE geben Sie den Stil des Dialogfeldes an. Mit CAPTION den Titel und mit FONT die Schriftart- und Größe.

Auf den nun folgenden Zeilen zwischen BEGIN und END werden jetzt die Steuerelemente des Dialogfeldes eingebaut. Mit

CHECKBOX        "Checkbox 1",IDC_CHECKBOX1,9,7,70,10 

packen Sie in das Dialogfeld eine Checkbox mit der Beschriftung "Checkbox 1", die Identifikation IDC_CHECKBOX1 und den Angaben der Position und Größe.

Mit GROUPBOX erstellen Sie einen Rahmen um die gleich folgenden Radiobuttons. Die Angaben der Radiobuttons sind Äquivalent mit den Checkbuttons. Mit PUSHBUTTON definieren Sie eine einfache Schaltfläche für das Dialogfeld. Fix und fertig sieht dieses Dialogfeld später bei der Ausführung folgendermaßen aus:

Dialogfelder: Radiobuttons  und Checkboxen

Dialogfelder: Radiobuttons und Checkboxen

Anhand dieser vielen Möglichkeiten, die Sie hier bereits gesehen haben und der vielen Möglichkeiten, die Sie noch nicht gesehen haben, kommen Sie in der Praxis kaum um einen Dialogeditor herum. Wie und welchen Sie dabei verwenden, bleibt Ihnen überlassen. Es muss allerdings erwähnt werden, dass jeder dieser Dialogeditoren so seine Eigenheiten besitzt. Gerade bei der Angabe der Position und Größe der einzelnen Resourcen kann es ohne einen solchen Editor recht frustrieren werden.

Weiter mit dem nächsten Dialogfeld.

IDR_TEXTDIALOG DIALOGEX 20, 20, 180, 70
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
                                              WS_SYSMENU
CAPTION "Dialogfeld (Textfeld)"
FONT 8, "MS Sans Serif"
BEGIN
   LTEXT "Passwort     : ", -1, 36, 8, 45, 8
   EDITTEXT IDC_EDIT1, 83,6,61,13, ES_AUTOHSCROLL | WS_BORDER
   LTEXT "Nummer       : ", -1, 36, 24, 45, 8
   EDITTEXT IDC_EDIT2, 83,22,61,13, ES_AUTOHSCROLL | WS_BORDER
   PUSHBUTTON "&Bestätigen", IDOK, 33, 50, 50, 14
   PUSHBUTTON "&Abbrechen", IDCANCEL, 95, 50, 50 ,14,WS_GROUP
END

Auch hier geben Sie zuerst wieder mit DIALOGEX, die Position und Größe, den Stil, die Überschrift und die Schrift des Dialogfeldes an. Zwischen BEGIN und END steht wieder der Inhalt des Dialogfeldes. LTEXT steht für einen links bündig ausgerichteten Text. Mit EDITTEXT definieren Sie ein Bearbeitungsfeld im Dialogfeld. Dies stellt die Standardmethode da zur Eingabe von getippten Text oder Zahlen. Am Ende definieren Sie wieder zwei einfache Schaltflächen (PUSHBUTTON). Bei der Ausführung im Programm sieht dieses Dialogfeld so aus:

Einzeiliges Editfeld

Einzeiliges Editfeld

Zum Schluss noch ein Dialogfeld mit einer Listbox.

IDR_LISTBOX DIALOGEX  20, 20, 150, 110
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Listbox"
FONT 8, "MS Sans Serif"
BEGIN
    EDITTEXT        IDC_DIRECTORY,6,5,136,13,ES_AUTOHSCROLL |
                                             ES_READONLY |
                                             NOT WS_TABSTOP
    LISTBOX         IDC_LIST,6,20,136,59,LBS_SORT |
                                         LBS_NOINTEGRALHEIGHT |
                                         LBS_DISABLENOSCROLL |
                                         WS_VSCROLL |
                                         WS_TABSTOP
    PUSHBUTTON      "&Abbrechen",IDCANCEL,50,87,50,14,WS_GROUP
END

Außer der LISTBOX womit Sie ein Listenfeld definieren, finden Sie hier nichts Neues vor. Hier das Ergebnis eines solchen Dialogfeldes:

Eine Listbox

Eine Listbox

5.2 Die Headerdatei für die Ressourcen            zurück  zum Inhaltsverzeichnis

Die ID der einzelnen Ressourcen der Ressourcen-Skriptedatei wurden wieder alle in eine Headerdatei resource.h gepackt.

#define ID_MENU_RADIO_CHECK            1
#define ID_EDITFELD                    2
#define ID_LISTBOX                     3
#define ID_HELP                        4
#define ID_EXIT                        5


#define IDR_MENU                       100
#define ID_ICON                        111


#define IDR_DIALOG                     1000
#define IDR_TEXTDIALOG                 1001
#define IDR_LISTBOX                    1002

#define IDC_CHECKBOX1                  10001
#define IDC_CHECKBOX2                  10002
#define IDC_RADIO1                     10003
#define IDC_RADIO2                     10004
#define IDC_RADIO3                     10005


#define IDC_EDIT1                      10006
#define IDC_EDIT2                      10007

#define IDC_DIRECTORY                  10008
#define IDC_LIST                       10009

#define PASSWORT "pinguin"
#define NUMMER    666999

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMsg,
                         WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK CheckRadioProc(HWND hDlg, UINT uMsg,
                                WPARAM wParam, LPARAM lParam );

LRESULT CALLBACK CheckEditProc(HWND hDlg, UINT uMsg,
                               WPARAM wParam, LPARAM lParam );

LRESULT CALLBACK CheckListboxProc(HWND hDlg, UINT uMsg,
                                  WPARAM wParam, LPARAM lParam );

Außer den Konstanten finden Sie in dieser Headerdatei auch gleich die Vorwärtsdeklarationen der Prozeduren vor. Dabei werden vier Prozeduren benötigt. Die Prozedur WndProc() verarbeitet wieder die eingehenden Nachrichten der Nachrichten-Schleife aus der WinMain()-Funktion. Die anderen drei Prozeduren benötigen Sie für die Dialogfelder. Für jedes Dialogfeld wird dabei eine extra Funktion benötigt, womit die Aktionen der Steuerelemente des Dialogfeldes ausgewertet werden.

5.3. Das komplette WIN32-Listing zu den Dialogfeldern            zurück  zum Inhaltsverzeichnis

Jetzt folgt das Listing, womit alle Dialogfelder verwendet werden können. Das Listing ist ein wenig umfangreicher und wird im Anschluss analysiert.

#include <windows.h>
#include <string.h>
#include "resource.h"

LPCSTR MainClassName = "Dialogfelder";

HINSTANCE hInst;

//Für Auswertung von Check- und Radiobuttons
BOOL bChecked1 = FALSE;
BOOL bChecked2 = FALSE;
BOOL bRadio1   = FALSE;
BOOL bRadio2   = FALSE;
BOOL bRadio3   = FALSE;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
   WNDCLASSEX wc;
   MSG wmsg;
   HWND hWnd;

   wc.cbSize                 = sizeof(WNDCLASSEX);
   wc.style          = 0;
   wc.lpfnWndProc         = WndProc;
   wc.cbClsExtra         = 0;
   wc.cbWndExtra         = 0;
   wc.hInstance         = hInstance;
   wc.hIcon                 = LoadIcon(GetModuleHandle(NULL),
                            MAKEINTRESOURCE(ID_ICON));
   wc.hCursor                 = LoadCursor(NULL, IDC_CROSS);
   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
   wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU);
   wc.lpszClassName = MainClassName;
   wc.hIconSm                 = (HICON)LoadImage(GetModuleHandle(NULL),
                                        MAKEINTRESOURCE(ID_ICON),
                                        IMAGE_ICON, 16, 16, 0);

   if(!RegisterClassEx(&wc))
      {
       MessageBox(NULL, "Windows Registrations Fehler", "Error!",
                  MB_ICONEXCLAMATION | MB_OK)
       return 0;
      }

    hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, MainClassName,
                          "Menü Beispiel",
                          WS_OVERLAPPEDWINDOW|WS_VISIBLE,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          400, 300,NULL,NULL,hInstance, NULL);

    hInst=hInstance;

    if(hWnd == NULL)
    {
       if(MessageBox(NULL, "Fehler beim Erstellen des Fensters!",
          "Error!",        MB_ICONEXCLAMATION | MB_OK) == IDOK);
          return 0;
    }

while(GetMessage(&wmsg,NULL,0,0))
   {
      TranslateMessage(&wmsg);
      DispatchMessage(&wmsg);
   }
   return wmsg.wParam;
}


LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg,
                          WPARAM wParam, LPARAM lParam )
{
   switch( uMsg )
   {
      case WM_COMMAND :
              switch( LOWORD( wParam ) )
              {
                 //Wurde Menüelement "Radio & Checkbox" gewählt
                 case ID_MENU_RADIO_CHECK  :
                        DialogBox( hInst,
                                   MAKEINTRESOURCE(IDR_DIALOG),
                                   hWnd,
                                   (DLGPROC)CheckRadioProc );
                        break;
                 //Menüelement "Editfeld" wurde ausgewählt
                 case ID_EDITFELD:
                        DialogBox( hInst,
                                 MAKEINTRESOURCE(IDR_TEXTDIALOG),
                                   hWnd,
                                   (DLGPROC)CheckEditProc );
                        break;
                 //Menüelement "Listbox" wurde ausgewählt
                 case ID_LISTBOX :
                        DialogBox( hInst,
                                   MAKEINTRESOURCE(IDR_LISTBOX),
                                   hWnd,
                                   (DLGPROC)CheckListboxProc );
                        break;
                 //Menüelement "?" wurde ausgewählt
                 case ID_HELP:
                        MessageBox(hWnd,"Hier können Sie einige "
                                        "Dialogfelder testen",
                                        "Hinweis", MB_OK);
                        break;
                 //Menüelement "Beenden" wurde betätigt
                 case ID_EXIT :
                        DestroyWindow( hWnd );
                        break;
              }
              break;

      case WM_DESTROY :
              PostQuitMessage(0);
              break;

      default :
            return( DefWindowProc( hWnd, uMsg, wParam, lParam ));
   }

   return( 0L );
}

// Nachrichtenverarbeitung für das Dialogfeld
// "Radio & Checkbutton"
LRESULT CALLBACK CheckRadioProc( HWND hDlg, UINT uMsg,
                              WPARAM wParam, LPARAM lParam )
{
   char str[255];

   switch( uMsg )
   {
      //Beim Initialisieren mit bestimmten Werten besehen
      case WM_INITDIALOG :
            CheckDlgButton( hDlg, IDC_CHECKBOX1, BST_UNCHECKED );
            CheckDlgButton( hDlg, IDC_CHECKBOX2, BST_UNCHECKED );
            CheckRadioButton( hDlg, IDC_RADIO1, IDC_RADIO3,
                                                IDC_RADIO1 );
            break;
      //Check- und Radiobutton auswerten
      case WM_COMMAND :
            switch( LOWORD( wParam ) )
            {
               case IDC_CHECKBOX1 : //Checkbox 1
                      bChecked1 = !(IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX1 ) == BST_CHECKED);
                      CheckDlgButton( hDlg, IDC_CHECKBOX1,
                                      bChecked1 ? BST_CHECKED :
                                      BST_UNCHECKED );
                      break;
               case IDC_CHECKBOX2 : //Checkbox 2
                      bChecked2 = !(IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX2 ) == BST_CHECKED);
                      CheckDlgButton( hDlg, IDC_CHECKBOX2,
                                      bChecked2 ? BST_CHECKED :
                                      BST_UNCHECKED );
                      break;
               case IDC_RADIO1 : //Radiobutton 1
                      bRadio1 = TRUE;
                      CheckRadioButton( hDlg, IDC_RADIO1,
                                        IDC_RADIO3, IDC_RADIO1 );
                      break;
               case IDC_RADIO2 : //Radiobutton 2
                      bRadio2 = TRUE;
                      CheckRadioButton( hDlg, IDC_RADIO1,
                                        IDC_RADIO3,IDC_RADIO2 );
                      break;
               case IDC_RADIO3 : //Radiobutton 3
                      bRadio3 = TRUE;
                      CheckRadioButton( hDlg, IDC_RADIO1,
                                        IDC_RADIO3,IDC_RADIO3 );
                      break;
               // Stand der Check- und Radiobuttons auswerten
               // und mithilfe einer MessageBox ausgeben
               case IDCANCEL :
                      bChecked1 = (IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX1 ) == BST_CHECKED);
                      bChecked2 = (IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX2 ) == BST_CHECKED);
                      bRadio1 = (IsDlgButtonChecked
                      ( hDlg, IDC_RADIO1 ) == BST_CHECKED);
                      bRadio2 = (IsDlgButtonChecked
                      ( hDlg, IDC_RADIO2 ) == BST_CHECKED);
                      bRadio3 = (IsDlgButtonChecked
                      ( hDlg, IDC_RADIO3 ) == BST_CHECKED);
                      wsprintf(str, "Checkbox     1: %s\n"
                                   "Checkbox     2: %s\n"
                                   "Radiobutton 1: %s\n"
                                   "Radiobutton 2: %s\n"
                                   "Radiobutton 2: %s\n",
                                   bChecked1?"EIN":"AUS",
                                   bChecked2?"EIN":"AUS",
                                   bRadio1?"EIN":"AUS",
                                   bRadio2?"EIN":"AUS",
                                   bRadio3?"EIN":"AUS");
                      MessageBox(hDlg, str, "Status", MB_OK);
                      //Wichtig!!! Dialog zu Ende
                      EndDialog( hDlg, IDCANCEL );
                      break;
            }
            break;

      default :
            return( FALSE );
   }
   return( TRUE );
}

// Nachrichtenverarbeitung für das Dialogfeld
// "Editfeld"
LRESULT CALLBACK CheckEditProc( HWND hDlg, UINT uMsg,
                              WPARAM wParam, LPARAM lParam )
{
   char chk_pswd[9];
   int  chk_numb=0;

   switch( uMsg )
   {
      //Beim Initialisieren mit bestimmten Werten besehen
      case WM_INITDIALOG :
         SetDlgItemText( hDlg, IDC_EDIT1, "passwort");
         SetDlgItemInt ( hDlg, IDC_EDIT2, 12345, TRUE);
         break;
      //die Eingabefelder auswerten
      case WM_COMMAND :
         switch( LOWORD (wParam) )
            {
               BOOL btran;
               case IDOK : //OK-Button wurde gedrückt
                  //Zeichenketten im ersten Eingabefeld einlesen
                  GetDlgItemText( hDlg, IDC_EDIT1,
                                  chk_pswd, sizeof(chk_pswd)-1);
                  //Integer im zweiten Eingabefeld einlesen
                  chk_numb=GetDlgItemInt( hDlg, IDC_EDIT2,
                                          &btran, TRUE);
                  //Passwort und Geheimnummer überprüfen
                  if( (strcmp(chk_pswd, PASSWORT) == 0) &&
                       (chk_numb == NUMMER ) )
                     MessageBox( hDlg, "Login erfolgreich",
                                 "Passwort OK", MB_OK);
                  else
                      MessageBox( hDlg, "Zugriff verweigert",
                                  "Passwort falsch", MB_OK);
                  //Dialog beenden
                  EndDialog( hDlg, IDOK);
                  break;
               case IDCANCEL : //Abbrechen-Button gedrückt
                  //Dialog beenden
                  EndDialog( hDlg, IDCANCEL);
                  break;
            }
         break;
      default: return FALSE;
   }
 return TRUE;
}

//Nachrichtenverarbeitung für die "Listbox
LRESULT CALLBACK CheckListboxProc( HWND hDlg, UINT uMsg,
                               WPARAM wParam, LPARAM lParam )
{
  char szTmp[255] = "*.*";

   switch( uMsg )
   {
      //Beim Initialisieren mit bestimmten Werten besehen
      case WM_INITDIALOG :
           DlgDirList( hDlg, szTmp , IDC_LIST, IDC_DIRECTORY,
                                  DDL_DIRECTORY  );
            break;
      //Listbox auswerten
      case WM_COMMAND :
            switch( LOWORD( wParam ) )
            {
               //Ein Element in der Liste wurde ausgewählt
               case IDC_LIST :
                      //Wurde doppelt geklickt
                      if ( HIWORD( wParam ) == LBN_DBLCLK )
                      {
                        //Element in der Listbox auslesen
                         if ( DlgDirSelectEx( hDlg, szTmp,
                               sizeof( szTmp ), IDC_LIST ) )
                         {
                            strcat( szTmp, "*.*" );
                            DlgDirList( hDlg, szTmp, IDC_LIST,
                                    IDC_DIRECTORY,
                                    DDL_DIRECTORY | DDL_DRIVES );
                         }
                         else //Ausgewähltes Element ausgeben
                            MessageBox( hDlg, szTmp,
                                   "Ausgewählte Datei",
                                   MB_OK | MB_ICONINFORMATION );
                      }
                      break;
               case IDCANCEL :
                      //Dialog mit Abbrechen beenden
                      EndDialog( hDlg, IDCANCEL );
                      break;
            }
            break;
      default :
            return( FALSE );
   }
   return( TRUE );
}

Sie haben jetzt die Resourcen-Skritpedatei, das Icon, die Headerdatei und das Listing. Somit können Sie jetzt schon gerne das Programm übersetzten. Wenn alles glatt verlaufen ist, sollte sich folgendes Fenster bei ihnen öffnen:

Fenster beim Ausführen des Programms

Fenster beim Ausführen des Programms

5.4. Analyse des Listings            zurück  zum Inhaltsverzeichnis

Jetzt die Erklärung zum Programm. In der WinMain()-Funktion bleibt alles beim Alten. Also dabei nichts Neues. Es kann also gleich in WndProc() eingestiegen werden.

LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg,
                          WPARAM wParam, LPARAM lParam )
{
   switch( uMsg )
   {
      case WM_COMMAND :
              switch( LOWORD( wParam ) )
              {
                 //Wurde Menüelement "Radio & Checkbox" gewählt
                 case ID_MENU_RADIO_CHECK  :
                        DialogBox( hInst,
                                   MAKEINTRESOURCE(IDR_DIALOG),
                                   hWnd,
                                   (DLGPROC)CheckRadioProc );
                        break;

Es sei gegeben, dass ein Anwender das Menüelement "Radio & Checkbox" ausgewählt hat. Beim Betätigen eines Menüelements wird also die Nachricht WM_COMMAND gesendet. Welches Element es denn nun wahr, befindet sich in den niedrigeren zwei Bytes in wParam. Entspricht der Wert von LOWORD(wParam) dem von der Konstante ID_MENU_RADIO_CHECK (was in diesem Fall das Szenario sein soll), wird die Funktion DialogBox() aufgerufen.

Die Funktion DialogBox() erzeugt ein modales Dialogfeld aus einer Dialogfeld-Schablone, welche Sie ja in der Resourcen-Skriptedatei definiert haben. Der erste Parameter ist der Instanz-Handle. Der zweite Parameter ist der Name der Dialogfeld-Schablone, in der Resourcen-Skriptedatei. Die Ressource-ID ist ein nullterminierter String, welchen Sie sich mit dem bekannten Makro MAKEINTRESOURCE() ermitteln. Der dritte Parameter ist ein Handle auf das Hauptfenster und der vierte Parameter ein Zeiger auf eine Dialogfeld-Prozedur, welche die Nachrichten für das Dialogfeld auswertet. Ein solche Dialogfeld-Funktion muss definiert werden, um die Nachrichten des Dialogfeldes überhaupt verarbeiten zu können.

Der Prozedur CheckRadioProc() wird gleich als erste Nachricht WM_INITDIALOG gesendet. Diese Nachricht entspricht der Nachricht WM_CREATE für das Hauptfenster. Für Dialogfelder wird immer die Nachricht WM_INITDIALOG gesendet.

LRESULT CALLBACK CheckRadioProc( HWND hDlg, UINT uMsg,
                              WPARAM wParam, LPARAM lParam )
{
   char str[255];

   switch( uMsg )
   {
      //Beim Initialisieren mit bestimmten Werten besehen
      case WM_INITDIALOG :
            CheckDlgButton( hDlg, IDC_CHECKBOX1, BST_UNCHECKED );
            CheckDlgButton( hDlg, IDC_CHECKBOX2, BST_UNCHECKED );
            CheckRadioButton( hDlg, IDC_RADIO1, IDC_RADIO3,
                                                IDC_RADIO1 );
            break;

In der Prozedur CheckRadioProc() wird die Nachricht WM_INITDIALOG gleich für weitere Maßnahmen verwendet. Zuerst wird mit der Funktion CheckDlgButton() dafür gesorgt, dass die beiden Checkboxen erst mal nicht gesetzt sind (BST_UNCHECKED). Der erste Parameter ist das Handle für die Dialogbox, der zweite Parameter ist die ID der zu modifizierenden Schaltfläche und mit dem letzten Parameter geben Sie den Markierungsstatus für die Schaltfläche an. Außer BST_UNCHECKED können Sie dafür auch BST_CHECKED (für gesetzt) und BST_INDETERMINATE (Element ist weder markiert noch unmarkiert) verwenden.

Ähnlich verläuft dies bei den Radiobuttons mit der Funktion CheckRadioButton() ab. Der erste Parameter ist das Handle für die Dialogbox, der zweite Parameter steht für die ID des ersten Optionsfelds und der dritte Parameter für die ID des letzten Optionsfelds in der Gruppe. Mit dem vierten Parameter geben Sie die ID des auszuwählenden Optionsfelds an.

Würden Sie jetzt z.B. die "Checkbox 1" markieren, würde die Nachricht WM_COMMAND an die Prozedur CheckRadioProc() gesendet.

      case WM_COMMAND :
            switch( LOWORD( wParam ) )
            {
               case IDC_CHECKBOX1 : //Checkbox 1
                      bChecked1 = !(IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX1 ) == BST_CHECKED);
                      CheckDlgButton( hDlg, IDC_CHECKBOX1,
                                      bChecked1 ? BST_CHECKED :
                                      BST_UNCHECKED );
                      break;

Dass die Nachricht WM_COMMAND gesendet wurde, heißt noch lange nicht, dass das Häckchen der Checkbox gesetzt oder nicht gesetzt wird. Dafür müssen Sie wieder selbst sorgen. Entspricht also die eingegangene Nachricht dem der Konstante von IDC_CHECKBOX1, übergeben Sie der Variablen bChecked1 den Rückgabewert der Bedingung IsDlgButtonChecked() == BST_CHECKED. Als Parameter wird dieser Funktion der Handle für das Dialogfeld und die ID-Kennung der zu überprüfenden Checkbox übergeben. Damit in der Funktion CheckDlgButton() im Anschluss daran nicht bei wahrheitsgemäßer Rückgabe der Bedingung BST_CHECKED ein bereits gesetztes Häckchen nochmals gesetzt wird, wurde der Rückgabewert der Funktion IsDlgButtonChecked() negiert ( = !()). Da also zu Beginn die Checkbox noch nicht gesetzt war und Sie diese setzen, wird der Rückgabewert negiert, da ungleich BST_CHECKED. Somit wird aus 0 der Wert 1. Was eben zutrifft, überlassen wir in der Funktion CheckDlgButton() dem tenären Bedingungsoperator ?:.

Genauso verläuft dies bei der "Checkbox 2" und anschließend auch bei den Radiobuttons. Nur wird bei den Radiobuttons die Funktion CheckRadioButton() zum setzen verwendet.

               case IDC_CHECKBOX2 : //Checkbox 2
                      bChecked2 = !(IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX2 ) == BST_CHECKED);
                      CheckDlgButton( hDlg, IDC_CHECKBOX2,
                                      bChecked2 ? BST_CHECKED :
                                      BST_UNCHECKED );
                      break;
               case IDC_RADIO1 : //Radiobutton 1
                      bRadio1 = TRUE;
                      CheckRadioButton( hDlg, IDC_RADIO1,
                                        IDC_RADIO3, IDC_RADIO1 );
                      break;
               case IDC_RADIO2 : //Radiobutton 2
                      bRadio2 = TRUE;
                      CheckRadioButton( hDlg, IDC_RADIO1,
                                        IDC_RADIO3,IDC_RADIO2 );
                      break;
               case IDC_RADIO3 : //Radiobutton 3
                      bRadio3 = TRUE;
                      CheckRadioButton( hDlg, IDC_RADIO1,
                                        IDC_RADIO3,IDC_RADIO3 );
                      break;
               // Stand der Check- und Radiobuttons auswerten
               // und mithilfe einer MessageBox ausgeben
               case IDCANCEL :
                      bChecked1 = (IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX1 ) == BST_CHECKED);
                      bChecked2 = (IsDlgButtonChecked
                      ( hDlg, IDC_CHECKBOX2 ) == BST_CHECKED);
                      bRadio1 = (IsDlgButtonChecked
                      ( hDlg, IDC_RADIO1 ) == BST_CHECKED);
                      bRadio2 = (IsDlgButtonChecked
                      ( hDlg, IDC_RADIO2 ) == BST_CHECKED);
                      bRadio3 = (IsDlgButtonChecked
                      ( hDlg, IDC_RADIO3 ) == BST_CHECKED);
                      wsprintf(str, "Checkbox     1: %s\n"
                                   "Checkbox     2: %s\n"
                                   "Radiobutton 1: %s\n"
                                   "Radiobutton 2: %s\n"
                                   "Radiobutton 2: %s\n",
                                   bChecked1?"EIN":"AUS",
                                   bChecked2?"EIN":"AUS",
                                   bRadio1?"EIN":"AUS",
                                   bRadio2?"EIN":"AUS",
                                   bRadio3?"EIN":"AUS");
                      MessageBox(hDlg, str, "Status", MB_OK);

Wird jetzt der Button "Fertig" betätigt, erscheint eine MesssageBox() mit einer Zusammenfassung der Zustände von den Check- und Radiobutton.

Überprüfen der Radiobuttons und Checkboxen

Überprüfen der Radiobuttons und Checkboxen

Den Zustand können Sie wieder bequem mit der Funktion IsDlgButtonChecked() auswerten. Jetzt eine sehr wichtige Zeile:

                      EndDialog( hDlg, IDCANCEL );   

Mit dieser Funktion wird das Dialogfeld wieder entfernt. Der erste Parameter ist der Handle des Dialogfeld-Fensters und der zweite Parameter wird an die Funktion DialogBox() zurückgegeben.

Auf zum zweiten Menüelement in der Prozedur WndProc():

                 case ID_EDITFELD:
                        DialogBox( hInst,
                                MAKEINTRESOURCE(IDR_TEXTDIALOG),
                                   hWnd,
                                   (DLGPROC)CheckEditProc );
                        break;

Hierbei wird davon ausgegangen, dass der Anwender das Menüelement "Editfeld" ausgewählt hat. Die Funktion DialogBox() wurde bereits erklärt. Daher gleich zur Prozedur CheckEditProc():

LRESULT CALLBACK CheckEditProc( HWND hDlg, UINT uMsg,
                              WPARAM wParam, LPARAM lParam )
{
   char chk_pswd[9];
   int  chk_numb=0;

   switch( uMsg )
   {
      //Beim Initialisieren mit bestimmten Werten besehen
      case WM_INITDIALOG :
         SetDlgItemText( hDlg, IDC_EDIT1, "passwort");
         SetDlgItemInt ( hDlg, IDC_EDIT2, 12345, TRUE);
         break;

Auch hierbei wird als erstes beim Erstellen des Dialogfeldes die Nachricht WM_INITDIALOG gesendet. Hierbei wird die Funktion SetDlgItemText() zum Vorbelegen eines Strings und die Funktion SetDlgItemInt() zum Vorbelegen einer Ganzzahl verwendet. Dadurch ergibt sich beim erzeugen des Dialogfeldes folgende Grundstellung:

Passwortabfrage mit einzeiligem Editfeld

Passwortabfrage mit einzeiligem Editfeld

Jetzt können Sie das Passwort und die Geheimnummer eingeben:

Passworteingabe

Passworteingabe

Bei Betätigung des Buttons "Bestätigen" wird die Eingabe eingelesen.

      case WM_COMMAND :
         switch( LOWORD (wParam) )
            {
               BOOL btran;
               case IDOK : //Bestätigen-Button wurde gedrückt
                  //Zeichenketten im ersten Eingabefeld einlesen
                  GetDlgItemText( hDlg, IDC_EDIT1,
                                  chk_pswd, sizeof(chk_pswd)-1);
                  //Integer im zweiten Eingabefeld einlesen
                  chk_numb=GetDlgItemInt( hDlg, IDC_EDIT2,
                                          &btran, TRUE);
                  //Passwort und Geheimnummer überprüfen
                  if( (strcmp(chk_pswd, PASSWORT) == 0) &&
                       (chk_numb == NUMMER ) )
                     MessageBox( hDlg, "Login erfolgreich",
                                 "Passwort OK", MB_OK);
                  else
                      MessageBox( hDlg, "Zugriff verweigert",
                                  "Passwort falsch", MB_OK);
                  //Dialog beenden
                  EndDialog( hDlg, IDOK);
                  break;

Der Text zur Eingabe eines Strings wird mit der Funktion GetDlgItemText() ausgelesen. Der erste Parameter ist das Handle zum Dialogfeld-Fenster. Der zweite Parameter die ID-des Steuerelements und der dritte Parameter ist der Puffer, welcher den Text aufnimmt gefolgt vom vierten Parameter, der die max. Länge des Puffers angibt, der kopiert werden soll.

Ähnlich verläuft dies mit der Funktion GetDlgItemInt() ab. Nur ist hierbei der Rückgabewert ein Integerwert des Textfeldes. Der erste Parameter ist das Handle zum Dialogfeld-Fenster, der zweite Parameter die ID des Bearbeitungsfelds. Der dritte Parameter ist ein Zeiger auf eine BOOL-Variable. Ist dieser Wert auf TRUE gesetzt ist der eingelesene Wert ein korrekter int-Wert und bei FALSE wurde eine falsche Eingabe gemacht. Geben Sie beim vierten Parameter TRUE an, handelt es sich um einen vorzeichenlosen Integerwert. Bei FALSE handelt es sich um unsigned int (UINT).

Anschließend wird die Eingabe C-typisch überprüft und mit einer MessageBox ausgegeben:

Passwortüberprüfung erfolgreich

Passwortüberprüfung erfolgreich

Auch hier darf die wichtige Zeile EndDialog() nicht fehlen. EndDialog() wird ebenso aufgerufen, wenn der Anwender die Taste "Abbrechen" betätigt. Zurück zu WndProc(). Zum Schluss hätten Sie noch im Menü das Element "Listbox".

                 case ID_LISTBOX :
                        DialogBox( hInst,
                                   MAKEINTRESOURCE(IDR_LISTBOX),
                                   hWnd,
                                   (DLGPROC)CheckListboxProc );
                        break;

Auch hierbei wird wieder die Funktion DialogBox() mit entsprechenden Parametern aufgerufen. Da auch hier nichts Unbekanntes stattfindet, soll gleich zur Prozedur CheckListboxProc() gesprungen werden.

LRESULT CALLBACK CheckListboxProc( HWND hDlg, UINT uMsg,
                               WPARAM wParam, LPARAM lParam )
{
  char szTmp[255] = "*.*";

   switch( uMsg )
   {
      //Beim Initialisieren mit bestimmten Werten besehen
      case WM_INITDIALOG :
           DlgDirList( hDlg, szTmp , IDC_LIST, IDC_DIRECTORY,
                                  DDL_DIRECTORY  );
            break;

Auch hier wird beim Erhalt der Nachricht WM_INITDIALOG das Listenfeld mit der Funktion DlgDirList() mit Dateinamen gefüllt.

Listenfeld

Listenfeld

Die Bedeutung der einzelnen Parameter der Funktion DlgDirList(): Der erste Parameter ist der Handle des Dialogfeldes, welches das Listenfeld enthält. Der zweite Parameter ist ein Zeiger auf einen Suchstring. In diesem Beispiel wurde der Suchstring "*.*" verwendet, womit alle Dateien im Verzeichnis aufgelistet werden. Würden Sie bspw. den Suchstring "*.exe" angegeben, würden alle Dateien aufgelistet, welche mit der Extension exe im Verzeichnis sind. Natürlich können Sie auch hierbei einen ganzen Pfad mit angeben. Bspw. mit "C:\\WINNT\\system32\\*.dll" würden im Listenfeld alle DLL-Dateien aus dem Laufwerksverzeichnis C:\WINNT\system32 aufgelistet werden. Der dritte Parameter entspricht der ID des Listenfeldes (LISTBOX). Mit dem dritten Parameter geben Sie die ID des statischen Textes an, der das aktuelle Verzeichnis mit Laufwerksangabe anzeigt. Da dieses EDITFELD in der Resourcen-Skriptedatei mit dem Attribut ES_READONLY versehen wurde, ist dieses Feld grau und kann nicht editiert werden. Mit dem letzten Parameter können Sie Attribute des Dateinamens vergeben, die angezeigt werden sollen. Mit DDL_DIRECTORY geben Sie an, dass im Listenfeld auch Unterverzeichnisse berücksichtigt werden, welchen zwischen eckigen ([]) Klammern eingeschlossen sind. Wollen bspw. auch, dass Laufwerke mit angezeigt werden, können Sie diese Option mit dem bitweisen ODER-Operator mit DDL_DRIVES verknüpfen. Versteckte Dateien lassen sich mit DDL_HIDDEN und Systemdateien mit DDL_SYSTEM anzeigen. Für weitere Attribute verwenden Sie am besten die MSDN-Dokumentation und suchen nach DDL_…

Weiter geht es mit

      case WM_COMMAND :
            switch( LOWORD( wParam ) )
            {
               //Ein Element in der Liste wurde ausgewählt
               case IDC_LIST :

Es wurde hier die Nachricht WM_COMMAND gesendet, also hat sich etwas in dem Dialogfeld der Listenfelder getan. Dazu werten Sie wieder die niedrigeren zwei Bytes von wParam aus. Im Falle von IDC_LIST hat sich etwas im Listenfeld getan. Was genau werten Sie mit folgenden Zeilen aus:

                      if ( HIWORD( wParam ) == LBN_DBLCLK )
                      {
                        //Element in der Listbox auslesen
                         if ( DlgDirSelectEx( hDlg, szTmp,
                               sizeof( szTmp ), IDC_LIST ) )
                         {
                            strcat( szTmp, "*.*" );
                            DlgDirList( hDlg, szTmp, IDC_LIST,
                                    IDC_DIRECTORY,
                                    DDL_DIRECTORY);
                         }
                         else //Ausgewähltes Element ausgeben
                            MessageBox( hDlg, szTmp,
                                   "Ausgewählte Datei",
                                   MB_OK | MB_ICONINFORMATION );
                      }
                      break;

Hier überprüfen Sie die höheren zwei Bytes (HIWORD) der Variablen wParam auf die Konstante LBN_DBLCLK. LBN_DBLCLK ist gegeben, wenn im Listenfeld ein String mit der linken Maustaste doppelt geklickt wurde.

Ist dies der Fall, ermitteln Sie mit der Funktion DlgDirSelectEx() die aktuelle Auswahl in einem Listenfeld. Diese Auswahl wird anschließend im zweiten Parameter (szTmp) dieser Funktion abgelegt. Der erste Parameter ist wieder der Handle des Dialogfeldes, welches das Listenfeld enthält. Im dritten Parameter geben Sie die Anzahl der Zeichen an, welche in den zweiten Parameter kopiert werden sollen. Der vierte Parameter ist ID des Listenfeldes. Die Funktion liefert als Rückgabewert ungleich 0 zurück, wenn es sich bei der Auswahl um ein Verzeichnis handelt. Bspw. Sie wählen wie im Bild dargestellt das Verzeichnis "include" aus.

Verzeichnis auswählen

Verzeichnis auswählen

Dann wird in der nächsten Zeile mittels strcat() "*.*" hinten angehängt. Somit befände sich im String szTmp der Inhalt "c:\dev-cpp\include\*.*". Durch das Anhängen von "*.*" am Ende bewirken Sie, dass mit der nächsten Zeile mit der Funktion DlgDirList() der komplette Inhalt des Verzeichnis "include" aufgelistet wird.

Ist der String, den Sie mit der Funktion DlgDirSelectEx() ausgewählt haben, kein Verzeichnisname, dann handelt es sich um eine Datei und es wird 0 zurückgegeben. Diese ausgewählte Datei geben Sie in der else-Verzweigung mit einer MessageBox() aus.

Datei ausgewählt

Datei ausgewählt

Betätigen Sie hingegeben im Dialogfeld die "Abbrechen" Schaltfläche, wird die Nachricht IDCANCEL gesendet und das Dialogfeld wird wieder sauber mit EndDialog() beendet.

Weiter mit Kapitel 6: GDI, Textausgabe und Malen und Zeichnen            zum Inhaltsverzeichnis