BG MVC Model View Controller eğitim serisi yayında...

Ana page > Programlama > Windows API Programlama > Splitter

Splitter

► Kontroller

Windows API ile kullanılmak üzere sistem tarafından önceden tanımlanmış bir Splitter kontrolü yoktur. Yeni bir Windows sınıfı tanımlayarak bir splitter kontrolü oluşturabiliriz.

Windows API ile bir Splitter kontrolü oluşturmak için CreateWindowEx() fonksiyonu ile 3 adet pencere oluşturulur. Her bir pencere için yeni bir sınıf tanımlandıktan sonra, her üç pencere için ortak bir fonksiyon atanır.

1. Öncelikle Burada gösterildiği gibi bir Windows API projesi oluşturalım. Projeyle birlikte otomatik olarak oluşturulan main.c dosyasının başlangıç kısmını aşağıdaki şekilde düzenleyelim:


#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#define IDC_PANELLEFT 101
#define IDC_PANELRIGHT 102
#define IDC_PANELSPLITTER 103

#include <tchar.h>
#include <windows.h>
#include <windowsx.h> /* For GET_X_LPARAM() function */

HWND hwndLeftPanel, hwndRightPanel; /* Handles for left and right panels */
HWND hwndSplitterPanel; /* Handle for splitter panel */

/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

HWND CreatePanel (HWND hwnd, int panel); /* Declaration of panel creating function */
/* Procedure for all panels */
LRESULT CALLBACK PanelProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

/* Make the class name into a global variable */
TCHAR szClassName[ ] = _T("SplitterApp");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
					 

Aşağıdaki satırlar ile iki adet ana panel ve bir adet splitter panel pencere değeri programa eklenir.


HWND hwndLeftPanel, hwndRightPanel;
HWND hwndSplitterPanel;

Programa eklenen aşağıdaki satır ile panelleri oluşturmak için kullanacağımız fonksiyonun bildirimi yapılır.


HWND CreatePanel (HWND hwnd, int panel);

Aşağıdaki satır ile yeni bir Windows sınıfı tanımlayarak oluşturacağımız Panel kontrollerine atayacağımız PanelProc() fonksiyonunun tanımlaması programa eklenir.


LRESULT CALLBACK PanelProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

2. Şimdi, üç adet panel oluşturmak için;

WindowProcedure içinde oluşturacağımız WM_CREATE seçeneğine aşağıdaki satırları ekleyelim:


LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
             /* Creating left panel */
             hwndLeftPanel = CreatePanel(hwnd, 1);
             /* Creating right panel */
             hwndRightPanel = CreatePanel(hwnd, 2);
             /* Creating splitter panel */
             hwndSplitterPanel = CreatePanel(hwnd, 3);
             break;

3. Panelleri oluşturan fonksiyonu programa eklemek için;

main.c dosyasının sonuna aşağıdaki satırları ekleyelim:


HWND CreatePanel (HWND hwnd, int panel)
{
  WNDCLASSEX winpan = {0};
  HWND hwndPanel;

  winpan.cbSize = sizeof (WNDCLASSEX);

  winpan.lpfnWndProc = PanelProc;
  winpan.hCursor = LoadCursor (NULL, IDC_ARROW);
  winpan.cbClsExtra = 0;
  winpan.cbWndExtra = 0;
  winpan.style = CS_HREDRAW | CS_VREDRAW; /* For drawing panels properly */

  switch(panel) {
     case 1: /* Left panel */
        winpan.lpszClassName = TEXT("PanelLeft");
        winpan.hCursor = LoadCursor (NULL, IDC_ARROW);
        winpan.hbrBackground = (HBRUSH) CreateSolidBrush (RGB(200, 230, 255));
        break;
     case 2: /* Right panel */
        winpan.lpszClassName = TEXT("PanelRight");
        winpan.hCursor = LoadCursor (NULL, IDC_ARROW);
        winpan.hbrBackground = (HBRUSH) CreateSolidBrush (RGB(250, 200, 240));
        break;
     case 3: /* Splitter panel */
        winpan.lpszClassName = TEXT("PanelSplitter");
        winpan.hCursor = LoadCursor(NULL, IDC_SIZEWE);
        winpan.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
        break;
  }

  if (!RegisterClassEx (&winpan)) return 0;

  switch(panel) {
     case 1: /* Creating left panel */
        hwndPanel = CreateWindowEx (0, winpan.lpszClassName, NULL,
                            WS_CHILD | WS_VISIBLE, 0, 0, 300, 400,
                            hwnd, (HMENU) IDC_PANELLEFT, 0, NULL);
        break;
     case 2: /* Creating right panel */
        hwndPanel = CreateWindowEx (0, winpan.lpszClassName, NULL,
                            WS_CHILD | WS_VISIBLE, 305, 0, 300, 400,
                            hwnd, (HMENU) IDC_PANELRIGHT, 0, NULL);
        break;
     case 3: /* Creating splitter panel */
        hwndPanel = CreateWindowEx (0, winpan.lpszClassName, NULL,
                            WS_CHILD | WS_VISIBLE, 300, 0, 5, 400,
                            hwnd, (HMENU) IDC_PANELSPLITTER, 0, NULL);
        break;
  }

  return hwndPanel;
}

4. Panel için atadığımız fonksiyonu oluşturmak için;

Aşağıdaki satırları programa ekleyelim:


LRESULT CALLBACK PanelProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  int xpos_active;
  int xpos_down = 0;
  static BOOL bResizing;

  switch (message) {
     case WM_LBUTTONDOWN:
     {
          /* When left mouse button pressed down on splitter panel */
          if (hwnd==hwndSplitterPanel) {
              bResizing = TRUE; /* Shows that resizing operation is on */
              SetCapture(hwndLeftPanel); /* Captures the mouse for left panel */
              xpos_down = GET_X_LPARAM(lParam); /* Get mouse x coordinate when left mouse button pressed down */
              return 0;
          }
     }
     break;

     case WM_LBUTTONUP:
     {
          ReleaseCapture();
          bResizing = FALSE; /* Shows that resizing operation is off */
          return 0;
     }
     break;

     case WM_MOUSEMOVE:
     {
          /* Get mouse x coordinate while mouse is moving with left mouse button pressed down */
          xpos_active = GET_X_LPARAM(lParam);

          /* If resizing operation is on and mouse active x coordinate is between 100-500 */
          if (bResizing && (xpos_active>100) && (xpos_active<500)) {
              MoveWindow(hwndLeftPanel, 0, 0, xpos_active-xpos_down, 400, TRUE); /* Move left panel */
              MoveWindow(hwndSplitterPanel, xpos_active, 0, 5, 400, TRUE); /* Move splitter panel */
              /* Move right panel according to other panels positions */
              MoveWindow(hwndRightPanel, xpos_active + (5 - xpos_down), 0, 605 - (xpos_active + (5 - xpos_down)), 400, TRUE);
          }
          return 0;
     }
     break;
  }

  return DefWindowProc (hwnd, message, wParam, lParam);
}

Yukarıdaki kodları eklediğimizde, main.c dosyasının en son hali aşağıdaki şekilde olacaktır.

main.c


#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#define IDC_PANELLEFT 101
#define IDC_PANELRIGHT 102
#define IDC_PANELSPLITTER 103

#include <tchar.h>
#include <windows.h>
#include <windowsx.h> /* For GET_X_LPARAM() function */

HWND hwndLeftPanel, hwndRightPanel; /* Handles for left and right panels */
HWND hwndSplitterPanel; /* Handle for splitter panel */

/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

HWND CreatePanel (HWND hwnd, int panel); /* Declaration of panel creating function */
/* Procedure for all panels */
LRESULT CALLBACK PanelProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

/* Make the class name into a global variable */
TCHAR szClassName[ ] = _T("SplitterApp");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_HREDRAW | CS_VREDRAW;    /* For drawing panels properly */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program */
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           _T("Splitter uygulaması"), /* Title Text */
           WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* Prevent flickering while resizing panels */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           605,                 /* The programs width */
           400,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}

/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
             /* Creating left panel */
             hwndLeftPanel = CreatePanel(hwnd, 1);
             /* Creating right panel */
             hwndRightPanel = CreatePanel(hwnd, 2);
             /* Creating splitter panel */
             hwndSplitterPanel = CreatePanel(hwnd, 3);
             break;

        case WM_DESTROY:
             PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
             break;
        default:                        /* for messages that we don't deal with */
             return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

HWND CreatePanel (HWND hwnd, int panel)
{
  WNDCLASSEX winpan = {0};
  HWND hwndPanel;

  winpan.cbSize = sizeof (WNDCLASSEX);

  winpan.lpfnWndProc = PanelProc;
  winpan.hCursor = LoadCursor (NULL, IDC_ARROW);
  winpan.cbClsExtra = 0;
  winpan.cbWndExtra = 0;
  winpan.style = CS_HREDRAW | CS_VREDRAW; /* For drawing panels properly */

  switch(panel) {
     case 1: /* Left panel */
        winpan.lpszClassName = TEXT("PanelLeft");
        winpan.hCursor = LoadCursor (NULL, IDC_ARROW);
        winpan.hbrBackground = (HBRUSH) CreateSolidBrush (RGB(200, 230, 255));
        break;
     case 2: /* Right panel */
        winpan.lpszClassName = TEXT("PanelRight");
        winpan.hCursor = LoadCursor (NULL, IDC_ARROW);
        winpan.hbrBackground = (HBRUSH) CreateSolidBrush (RGB(250, 200, 240));
        break;
     case 3: /* Splitter panel */
        winpan.lpszClassName = TEXT("PanelSplitter");
        winpan.hCursor = LoadCursor(NULL, IDC_SIZEWE);
        winpan.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
        break;
  }

  if (!RegisterClassEx (&winpan)) return 0;

  switch(panel) {
     case 1: /* Creating left panel */
        hwndPanel = CreateWindowEx (0, winpan.lpszClassName, NULL,
                            WS_CHILD | WS_VISIBLE, 0, 0, 300, 400,
                            hwnd, (HMENU) IDC_PANELLEFT, 0, NULL);
        break;
     case 2: /* Creating right panel */
        hwndPanel = CreateWindowEx (0, winpan.lpszClassName, NULL,
                            WS_CHILD | WS_VISIBLE, 305, 0, 300, 400,
                            hwnd, (HMENU) IDC_PANELRIGHT, 0, NULL);
        break;
     case 3: /* Creating splitter panel */
        hwndPanel = CreateWindowEx (0, winpan.lpszClassName, NULL,
                            WS_CHILD | WS_VISIBLE, 300, 0, 5, 400,
                            hwnd, (HMENU) IDC_PANELSPLITTER, 0, NULL);
        break;
  }

  return hwndPanel;
}

LRESULT CALLBACK PanelProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  int xpos_active;
  int xpos_down = 0;
  static BOOL bResizing;

  switch (message) {
     case WM_LBUTTONDOWN:
     {
          /* When left mouse button pressed down on splitter panel */
          if (hwnd==hwndSplitterPanel) {
              bResizing = TRUE; /* Shows that resizing operation is on */
              SetCapture(hwndLeftPanel); /* Captures the mouse for left panel */
              xpos_down = GET_X_LPARAM(lParam); /* Get mouse x coordinate when left mouse button pressed down */
              return 0;
          }
     }
     break;

     case WM_LBUTTONUP:
     {
          ReleaseCapture();
          bResizing = FALSE; /* Shows that resizing operation is off */
          return 0;
     }
     break;

     case WM_MOUSEMOVE:
     {
          /* Get mouse x coordinate while mouse is moving with left mouse button pressed down */
          xpos_active = GET_X_LPARAM(lParam);

          /* If resizing operation is on and mouse active x coordinate is between 100-500 */
          if (bResizing && (xpos_active>100) && (xpos_active<500)) {
              MoveWindow(hwndLeftPanel, 0, 0, xpos_active-xpos_down, 400, TRUE); /* Move left panel */
              MoveWindow(hwndSplitterPanel, xpos_active, 0, 5, 400, TRUE); /* Move splitter panel */
              /* Move right panel according to other panels positions */
              MoveWindow(hwndRightPanel, xpos_active + (5 - xpos_down), 0, 605 - (xpos_active + (5 - xpos_down)), 400, TRUE);
          }
          return 0;
     }
     break;
  }

  return DefWindowProc (hwnd, message, wParam, lParam);
}

Program derleyip çalıştırdığımızda aşağıdakine benzer bir ekran görüntüsü karşımıza gelecektir:

Programın kaynak kodları

Programın exe dosyası