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

Ana page > Programlama > Windows API Programlama > WinAPI örnek kodlar > winapi_ornek00005

Windows API örnek kodlar

Owner Draw ListView (Subclassing işlemi ile)

Bir Windows API programında kullanılan ListView kontrolünün başlığını ve item satırlarını kendi belirlediğimiz görünümlere göre çizmek için Owner Draw yöntemini kullanabiliriz.

ListView kontrolündeki başlık ve öğelerle ilgili tüm çizimleri Owner Draw yöntemi ile yapmak istediğinizde, ListView kontrolünü, LVS_OWNERDRAWFIXED değeri ile oluşturmamız gerekir.

Ancak, bu durumda WM_NOTIFY mesajı NM_CUSTOMDRAW bildirim kodu altındaki tüm işlemler, satır ve tüm satır seçimi tamamen devre dışı kalır.

Bu durumda;

1. ListView kontrolünün başlık kısmını oluşturmak için, Subclassing işlemi ile ListView için oluşturulan fonksiyon içinde WM_DRAWITEM mesajına işlem yapılır. Ancak, bu mesajlara işlem yapılabilmesi için ListView sütunları oluşturulduktan sonra, sütun başlıkları Header_SetItem() fonksiyonu ile HDF_OWNERDRAW değerine ayarlanmalıdır.

2. ListView kontrolünün item (satır) kısımlarını çizmek için ise, ListView kontrolünün içinde bulunduğu pencerenin fonksiyonu içinde WM_DRAWITEM mesajına işlem yapılır.

Programda yer alacak main.c dosyasının içeriği aşağıdaki şekilde olacaktır:

main.c


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

// commctrl.h içindeki bazı verilerin kullanımı için gerekli
#define _WIN32_WINNT 0x0601
#define _WIN32_IE 0x0501

#define IDC_LISTVIEWOWNER 1001

#define RENKSUTUN01 RGB(240,230,140)
#define RENKSUTUN02 RGB(229,223,107)
#define SELECTBG RGB(190,240,60)
#define SELECTFONT RGB(255,255,255)
#define RENKFONT RGB(50,50,50)

#include <tchar.h>
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>

HWND ListViewOwner;

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void FillListView(HWND hwnd);
LRESULT CALLBACK ListViewProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

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

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_DBLCLKS;                 /* Catch double-clicks */
    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("Owner Draw Listview "),       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           440,                 /* The programs width */
           260,                 /* 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:
        {
             ListViewOwner = CreateWindowEx(WS_EX_CLIENTEDGE , WC_LISTVIEW, "",
                                  WS_CHILD | LVS_REPORT | WS_VISIBLE | LVS_OWNERDRAWFIXED,
                                  10, 10, 400, 200, hwnd,
                                  (HMENU)IDC_LISTVIEWOWNER, NULL, NULL);
             ListView_SetExtendedListViewStyle(ListViewOwner, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
             SetWindowSubclass(ListViewOwner, ListViewProc, 0, 0);
             FillListView(ListViewOwner);

             break;
        }

        case WM_DRAWITEM:
        {
             // ListView Item satır çizimi burada (Üst pencere WM_DRAWITEM)
             if (wParam == IDC_LISTVIEWOWNER) {
                 LPDRAWITEMSTRUCT lDraw = (LPDRAWITEMSTRUCT)lParam;
                 char cdizi[20];
                 int id1, id2;

                 // Eğer satır seçilmiş ise tüm satır seçim çizimi yapar.
                 if(lDraw->itemState && ODS_SELECTED) {
                    FillRect(lDraw->hDC, &lDraw->rcItem, CreateSolidBrush((COLORREF)SELECTBG));
                    SetTextColor (lDraw->hDC, SELECTFONT);
                 }
                 else {
                    FillRect(lDraw->hDC, &lDraw->rcItem, CreateSolidBrush((COLORREF)RGB(255,255,255)));
                    SetTextColor (lDraw->hDC, RENKFONT);
                 }
                 // Bir satırda yer alan öğe ve alt öğeleri sırayla çizme
                 for (id1=0, id2=5; id1<4; id1++, id2+=98) {
                      ListView_GetItemText(ListViewOwner, lDraw->itemID, id1, cdizi, sizeof(cdizi));
                      lDraw->rcItem.left=id2;
                      DrawText(lDraw->hDC, cdizi, strlen(cdizi), &lDraw->rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
                 }
           }

           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;
}

void FillListView(HWND hwnd)
{
  LVCOLUMN lvc;
  LVITEM lvI;
  int idCol=4, idItem=10;
  char cdizi[15];
  int id1, id2;
  HDITEM hdi = { 0 };

  // LVCOLUMN structure için ilk değer atama işlemlerini yapar.
  lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  lvc.cx = 98;           // Sütun genişliği değeri
  lvc.pszText = cdizi;
  lvc.cchTextMax = sizeof(cdizi);
  lvc.fmt = LVCFMT_LEFT; // Sütunları sol tarafa ayarlar

  // Sütun ekleme işlemleri
  for (id1=0; id1<idCol; id1++) {
       lvc.iSubItem = id1;
       sprintf(cdizi, "%s%d", "Column", id1+1);
       lvc.pszText = cdizi;
       // Sütun ekleme işlemi
       ListView_InsertColumn(hwnd, id1, &lvc);
  }

  // Bu işlem yapılmazsa, Subclassing fonksiyonu (ListViewProc) içinde başlık değerlerine işlem yapılamaz.
  if (GetWindowLongPtr(hwnd, GWL_STYLE)& LVS_OWNERDRAWFIXED) {
      for (id1=0; id1<idCol; id1++) {
           hdi.mask = HDI_FORMAT;
           hdi.fmt = HDF_OWNERDRAW;
           Header_SetItem(ListView_GetHeader(hwnd), id1, &hdi);
      }
  }

  // LVITEM structure için ilk değer atama işlemlerini yapar.
  lvI.mask      = LVIF_TEXT | LVIF_STATE;
  lvI.stateMask = 0;
  lvI.iSubItem  = 0;
  lvI.state     = 0;

  // Satır ekleme işlemleri
  for (id1=0; id1<idItem; id1++) {
       lvI.iItem  = id1;
       sprintf(cdizi, "%s%d", "Item", id1+1);
       lvI.pszText   = cdizi;
       // İlk sütun için öğe ekleme işlemleri
       ListView_InsertItem(hwnd, &lvI);

       // Diğer sütunlar için öğe ekleme işlemleri
       for (id2=1; id2<idCol; id2++) {
            sprintf(cdizi, "%s%d-%d", "SubItem", id1+1, id2+1);
            ListView_SetItemText(hwnd, id1, id2, cdizi);
       }
  }
}

LRESULT CALLBACK ListViewProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
  switch (message) {
     // LVS_OWNERDRAWFIXED ListView Header bölümünü çizmek için
     // Listview item satır çizimi üst pencere WM_DRAWITEM mesajı içinde
     case WM_DRAWITEM:
     {
          LPDRAWITEMSTRUCT lDraw = (LPDRAWITEMSTRUCT)lParam;
          char cdizi[20];
          HDITEM hdi = { 0 };
          hdi.mask = HDI_TEXT | HDI_FORMAT;
          hdi.pszText = cdizi;
          hdi.cchTextMax = 20;
          HBRUSH hBrush;

          if(lDraw->CtlType==ODT_HEADER) {
             SetBkMode(lDraw->hDC, TRANSPARENT);
             if (lDraw->itemID%2) hBrush = CreateSolidBrush(RENKSUTUN02);
             else hBrush = CreateSolidBrush(RENKSUTUN01);

             SetTextColor(lDraw->hDC, RENKFONT);
             SelectObject(lDraw->hDC, hBrush);

             FillRect(lDraw->hDC, &lDraw->rcItem, NULL);

             Header_GetItem(lDraw->hwndItem, lDraw->itemID, &hdi);
             DrawText(lDraw->hDC, cdizi, strlen(cdizi), &lDraw->rcItem, DT_CENTER|DT_VCENTER);
          }
          DeleteObject(hBrush);

          break;
     }
  }

  return DefSubclassProc(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ı