Die WinAPI Plattform

Tutorials

Tutorial Nummer 14

(14.) Windows Buttons

In diesem Tutorial werde ich endlich die 'richtigen' Windows Buttons vorstellen, die natürlich viel einfacher zu benutzen sind, als selbst gebaute.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                   PSTR szCmdLine, int iCmdShow)
{
   MSG        msg;
   HWND       hWnd;
   WNDCLASS   wc;
   
   const char szAppName[]  = "Windows Buttons";
   
   wc.cbClsExtra           = 0;
   wc.cbWndExtra           = 0;
   wc.hbrBackground        = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
   wc.hCursor              = LoadCursor(NULL, IDC_ARROW);
   wc.hIcon                = LoadIcon(NULL, IDI_APPLICATION);
   wc.hInstance            = hInstance;
   wc.lpfnWndProc          = WndProc;
   wc.lpszClassName        = szAppName;
   wc.lpszMenuName         = NULL;
   wc.style                = CS_HREDRAW | CS_VREDRAW;
   
   RegisterClass(&wc);
   
   hWnd = CreateWindow(    szAppName,
                           szAppName,
                           WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT,
                           CW_USEDEFAULT,
                           CW_USEDEFAULT,
                           CW_USEDEFAULT,
                           NULL,
                           NULL,
                           hInstance,
                           NULL);
   
   ShowWindow(hWnd, iCmdShow);
   UpdateWindow(hWnd);
   
   while (GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
   
   return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

Da ein Windows Button auch ein Childfenster ist, das man aber nicht mehr registrieren muss, da dies von Windows schon gemacht wurde, brauchen wir auch wieder einen Handle, mit dem wir das Buttonchildfenster identifizieren können.

   static HWND hButton;
   
   switch (message)
   {
   case WM_CREATE:
      {

In der WM_CREATE Nachricht erstellen wir mit CreateWindow unser Buttonchildfenster, wie wir das auch für eigene Childfenster machen würden. Als Klassennamen muss man hier nur 'button' angeben.

         hButton = CreateWindow(  "button",
                                  "Beenden",
                                  WS_CHILD | WS_VISIBLE,
                                  0, 0, 0, 0,
                                  hWnd,
                                  NULL,
                                  ((LPCREATESTRUCT) lParam) -> hInstance,
                                  NULL);
         return 0;
      }
   case WM_SIZE:
      {

Die Buttonchildfenster kann man auch ganz normal, wie andere Fenster auch, verschieben. Da sie ganz normale Childfenster sind, kann man mit Buttons eigentlich alles machen, was man auch mit anderen Childfenstern machen kann.

         MoveWindow(hButton, LOWORD(lParam) / 2 - 80, HIWORD(lParam) - 30, 
                                                           160, 22, TRUE);
         return 0;
      }

Die vordefinierten Windows Controlls kommunizieren mit dem Hauptprogramm über Nachrichten. Da es ein ganz schönes Chaos geben würde, wenn es für jedes Controll und jede Nachricht eine eigene Windows Nachricht (WM_*) gäbe, hat man alle diese Nachrichten in der Nachricht WM_COMMAND zusammengefasst. HIWORD(wParam) liefert den 'Actioncode'. Bei einem Buttonklick ist das z. B. BN_CLICKED. LOWORD(wParam) ergibt die ID des Childfensters. Bei uns wird das immer Null sein, da wir in CreateWindow bei hMenu NULL angegeben haben. Hätte man dort (mit Hilfe eines casts) etwas anderes angegeben, hätte LOWORD(wParam) diesen Wert geliefert. lParam ist der Handle zu dem entsprechenden Childfenster. Diesen kann man auch mit dem eigenen Handle vergleichen, weshalb man nicht unbedingt die ID braucht.

Wenn nun der Button geklickt wurde, beenden wir das Programm. Denn auf dem Button steht 'Beenden'.

   case WM_COMMAND:
      {
         if (lParam == (LPARAM)hButton)
         {
            if (HIWORD(wParam) == BN_CLICKED)
               SendMessage(hWnd, WM_CLOSE, 0, 0);
         }
         return 0;
      }
   case WM_DESTROY:
      {
         PostQuitMessage(0);
         return 0;
      }
   }
   return DefWindowProc(hWnd, message, wParam, lParam);
}

Wie du sehen konntest sind die vordefinierten Windows Controlls ziemlich einfach zu benutzen. Man sollte sie natürlich immer den selbst programmierten Controlls vorziehen. Da man sich so erstens Arbeit spart und zweitens der Anwender bei gleicher Funktionalität auch das gleiche Aussehen haben will. So fühlt er sich 'zu Hause'.

Wenn du meinst, dass irgend eine Stelle in diesem Tutorial ungenau ist oder etwas nicht erklärt wird, dann schreibe mir einfach eine E-Mail.

webmaster@win-api.de