Доброго дня. Сьогодні ми розглянемо створення і використання табличного віджета в МС Віндовс.

Функції

І найперше, що потрібно розглянути — це основні функції і структури, які необхідно знати при використанні таблиці у вікні. Для створення примірника табличного елементу необхідно скористатися функцією CreateWindow. Її виклик може виглядати наступним чином.
/* створюємо примірник табличного елементу */
    listview = CreateWindow (WC_LISTVIEW,  
                             L"listview",
                             WS_TABSTOP | WS_VISIBLE | WS_CHILD | 
                             LVS_REPORT | LVS_EDITLABELS, /* прапорці властивостей */
                             0, /* відступ від лівого краю вікна */
                             0, /* відступ від верхнього краю вікна */
                             100, /* відступ від правого краю */
                             100, /* відступ від нижнього краю */
                             window, /* батьківське вікно */
                             0, /* меню */
                             hThisInstance,
                             NULL) ;
Наступним кроком стане створення колонок для елементу за допомогою функції ListView_InsertColumn, яка вставляє колонку в табличний елемент, і структури LVCOLUMN, яка описує дану колонку. Оголошення функції ListView_InsertColumn виглядає наступним чином. int ListView_InsertColumn(HWND hwnd, int iCol, const LPLVCOLUMN pcol) ; hwnd — це примірник, створеного раніше функцією CreateWindow, табличного елементу. iCol — це порядковий номер колонки. pcol — це вказівник на заповнену структуру LPLVCOLUMN. Оголошення структури LPLVCOLUMN виглядає наступним чином:
typedef struct _LVCOLUMN {
  UINT   mask;
  int    fmt;
  int    cx;
  LPTSTR pszText;
  int    cchTextMax;
  int    iSubItem;
#if (_WIN32_IE >= 0x0300)
  int    iImage;
  int    iOrder;
#endif 
#if (_WIN32_WINNT >= 0x0600)
  int    cxMin;
  int    cxDefault;
  int    cxIdeal;
#endif 
} LVCOLUMN, *LPLVCOLUMN;
Нам знадобляться наступні її елементи: cx — ширина колонки в пікселях; iSubItem — індекс дочірнього елементу (встановлюємо в 0); mask — ця змінна містить інформацію про те, яка інформація є правильно заповненою і доступною в структурі; fmt — вирівнювання заголовку колонки і її елементів (LVCFMT_LEFT, LVCFMT_RIGHT, LVCFMT_CENTER і інші); pszText — заголовок колонки. Для того, щоб додавати елементи (значення) в таблицю, необхідно скористатися функціями-макросами ListView_InsertItem і ListView_SetItem, а вказувати дані необхідно в структурі LVITEM. Оголошення функцій виглядає наступним чином.
int ListView_InsertItem (HWND hwnd, const LPLVITEM pitem) ;
BOOL ListView_SetItem (HWND hwnd, const LPLVITEM pitem) ;
hwnd — це вказівник на табличний елемент; pitem — це вказівник на заповнену структуру LVITEM. Для заповнення таблиці даними, необхідно спочатку використати функцію ListView_InsertItem, яка створить новий рядок і встановить першу комірку для нього, всі інші комірки даного рядка необхідно вставляти функцією ListView_SetItem. Без використання функції ListView_InsertItem ваша програма буде завершуватись з помилкою. Оголошення структури LVITEM виглядає наступним чином:
typedef struct {
  UINT   mask;
  int    iItem;
  int    iSubItem;
  UINT   state;
  UINT   stateMask;
  LPTSTR pszText;
  int    cchTextMax;
  int    iImage;
  LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
  int    iIndent;
#endif 
#if (_WIN32_WINNT >= 0x0501)
  int    iGroupId;
  UINT   cColumns;
  PUINT  puColumns;
#endif 
#if (_WIN32_WINNT >= 0x0600)
  int    *piColFmt;
  int    iGroup;
#endif 
} LVITEM, *LPLVITEM ;
Основні її елементи, які ми будемо використовувати: mask — це є бітна маска, котра вказує, які дані є доступними (заповненими) для використання (LVIF_TEXT); stateMask — встановлюємо в 0; state — також являється бітовою маскою, її встановимо в 0. pszText — текст комірки. ISubItem — номер колонки в таблиці. іItem — номер рядка в таблиці.

Програма

Розглянемо приклад програми, яка використовує табличний віджет.
#include <windows.h>
#include <commctrl.h>
#include <Commdlg.h>
#include <Wingdi.h>
#include <commctrl.h>
#include <string>
using namespace std ;

/* об'єкти вікна і табличного елементу */
HWND window ;
HWND listview ;
 
/* головна функція програми (аналог main) */
int WinMain (HINSTANCE hThisInstance,
             HINSTANCE hPrevInstance,
             LPSTR lpszArgument,
             int nFunsterStil) ;
 
/* функція обробки повідомлень */
LRESULT CALLBACK WindowProcedure (HWND, 
                                  UINT, 
                                  WPARAM, 
                                  LPARAM) ;

/* функція заповнення даними таблиці */                                  
void fill_table_with_data () ;
 
/* ім'я класу вікна */
wchar_t window_class_name [] = L"WindowInWindowsClass" ;
 
/* реалізація головної функції програми */
int WinMain (HINSTANCE hThisInstance,
             HINSTANCE hPrevInstance,
             LPSTR lpszArgument,
             int nFunsterStil)
{
    /* ініціація бібліотеки */
    InitCommonControls () ;
    
    /* Змінна, в якій зберігаються повідомлення до програми */
    MSG messages ;
    /* структура даних для класу вікна */
    WNDCLASSEX wincl ;
 
    /* заповнюємо структуру класу вікна */
    wincl.hInstance = hThisInstance ;
    wincl.lpszClassName = window_class_name ;
    wincl.lpfnWndProc = WindowProcedure ;
    wincl.style = CS_DBLCLKS ;
    wincl.cbSize = sizeof (WNDCLASSEX) ;
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW) ;
    wincl.lpszMenuName = NULL ;
    wincl.cbClsExtra = 0 ;
    wincl.cbWndExtra = 0 ;
    /* Створюємо об'єкт, який буде заповняти кольором полотно вікна */
    wincl.hbrBackground = (HBRUSH) CreateSolidBrush (RGB (232, 246, 255)) ;
    
    /* реєструємо клас і перевіряємо повернене */
    /* значення на предмет помилки */
    if (!RegisterClassEx (&wincl))
    {        
        MessageBox (GetDesktopWindow (), 
                    L"Не можу зареєструвати клас вікна", 
                    L"Невиправна помилка!", 
                    MB_OK | MB_ICONERROR) ;
        
        return 0 ; 
    }
 
    /* створюємо примірник вікна */
    window = CreateWindowEx (0,                         /* Додаткові можливості */
                             window_class_name,         /* ім'я класу вікна */
                             L"Вікно таблиці",          /* заголовок */
                             WS_OVERLAPPEDWINDOW,       /* звичайне вікно */
                             1,                         /* координата лівого верхнього кута по осі x */
                             1,                         /* координата лівого верхнього кута по осі у */
                             1000,                      /* ширина програми в пікселях */
                             600,                       /* висота програми в пікселях */
                             GetDesktopWindow (),       /* вікно буде дочірнім до робочого столу */
                             NULL,                      /* немає меню */
                             hThisInstance,             /* примірник обробника програми */
                             NULL) ;                    /* дані створення вікна (сигнал WM_CREATE) */
 
    /* перевіряємо повернене значення на предмет помилки */
    if (window==NULL)
    {
        MessageBox (GetDesktopWindow (),
                    L"Помилка при створенні примірника вікна.",
                    L"Невиправна помилка!",
                    MB_OK | MB_ICONERROR) ;
                    
        return 0 ;
    }
    
    /* змінна, яка буде зберігати розміри вікна */
    RECT rcClient ;

    /* дізнаємося розміри вікна */
    GetClientRect (window, &rcClient) ;
    
    /* створюємо примірник табличного елементу */
    listview = CreateWindow (WC_LISTVIEW,  
                             L"listview",
                             WS_TABSTOP | WS_VISIBLE | WS_CHILD | 
                             LVS_REPORT | LVS_EDITLABELS, /* прапорці властивостей */
                             2, /* відступ від лівого краю вікна */
                             2, /* відступ від верхнього краю вікна */
                             rcClient.right - rcClient.left - 2, /* відступ від правого краю */
                             rcClient.bottom - rcClient.top - 2, /* відступ від нижнього краю */
                             window, /* батьківське вікно */
                             0, /* меню */
                             hThisInstance,
                             NULL) ;
                             
    /* перевіряємо повернене значення на предмет помилки */
    if (listview==NULL)
    {
        MessageBox (GetDesktopWindow (),
                    L"Помилка при створенні примірника табличного елементу.",
                    L"Невиправна помилка!",
                    MB_OK | MB_ICONERROR) ;
                    
        return 0 ;
    }
 
    /* змінні для створення колонок табличного елементу*/
    wstring col_name ;       
    LVCOLUMN lvc ; /* об'єкт ініціалізації колонки */
    
    /* частково заповнюємо структуру */
    lvc.cx = 50 ; /* ширина колонки в пікселях */
    lvc.iSubItem = 0 ; /* дочірні елементи */
    /* Дана бітова маска вказує, що формат, ширина, текст і дочірні елементи 
    ** дозволені для даної структури */
    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM ;
    lvc.fmt = LVCFMT_LEFT ;
    
    col_name = L"Номер" ;
    
    /* встановлюємо назву першої колонки */
    lvc.pszText = (LPWSTR) col_name.c_str() ;
    
    /* вставляємо першу колонку в табличний елемент */
    if (ListView_InsertColumn (listview, /* табличний елемент */
                               0, /* порядковий номер колонки */
                               &lvc) /* структура ініціалізації колонки */
                                    ==(-1))
    {
        MessageBox(window,
                   L"Не можу створити колонку для об'єкта представлення табличних даних",
                   L"Невиправна помилка!",
                   MB_ICONERROR | MB_OK) ;
            
        return 0 ;
    }
    
    col_name = L"Дані" ;
    
    /* встановлюємо назву другої колонки */
    lvc.pszText = (LPWSTR) col_name.c_str() ;
    
    /* вставляємо другу колонку в табличний елемент */
    if (ListView_InsertColumn (listview, /* табличний елемент */
                               1, /* порядковий номер колонки */
                               &lvc) /* структура ініціалізації колонки */
                                    ==(-1))
    {
        MessageBox(window,
                   L"Не можу створити колонку для об'єкта представлення табличних даних",
                   L"Невиправна помилка!",
                   MB_ICONERROR | MB_OK) ;
            
        return 0 ;
    }
 
    /* Показуємо вікно на весь екран */
    ShowWindow (window, SW_SHOW) ;
    
    /* заповняємо таблицю даними */
    fill_table_with_data () ;
    
    /* Приймаємо повідомлення, поки не зустрінемо 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Перетворюємо віртуальні клавіші до символьних */
        TranslateMessage (&messages) ;
        
        /* Посилаємо повідомлення до WindowProcedure */
        DispatchMessage (&messages) ;
    }
 
    /* Повертаємо значення, яке нам дала функція PostQuitMessage() */
    return messages.wParam ;
}
 
/*  Дана функція викликається системною функцією DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND phwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    /* обробляємо повідомлення */
    switch (message)
    {
        case WM_DESTROY:
        
            /* посилаємо повідомлення WM_QUIT */
            PostQuitMessage (0) ;
 
            break;
            
        case WM_SIZE:
        
            /* дана подія вказує на зміни розміру вікна */
            
            /* визначаємо розміри вікна */    
            RECT rcClient ;
            GetClientRect (window, &rcClient) ;
            
            /* у відповідності до нових розмірів переміщаємо 
            ** табличний елемент і змінюємо його розміри відносно вікна */
            MoveWindow (listview,
                        2, /* двохпіксельні відступи від країв рамки вікна */
                        2,
                        rcClient.right - rcClient.left - 2,
                        rcClient.bottom - rcClient.top - 2,
                        true) ;
 
        case WM_COMMAND:
            
            /* обробляємо події вікна (натискання кнопок і т.д.) */
            
        default:
            
            /* запускаємо обробник за умовчанням (якщо
            ** не враховано повідомлення) */
            return DefWindowProc (phwnd, message, wParam, lParam) ;
    }
 
    return 0 ;
}

void fill_table_with_data ()
{
    /* структура, яка містить інформацію про рядок/комірку */
    LVITEM        lvI ;
    
    /* заповняємо структуру */
    lvI.mask     = LVIF_TEXT ;
    lvI.stateMask= 0 ;
    lvI.state    = 0 ;
    
    /* заповняємо структуру для першого рядка першої комірки */
    lvI.pszText  = L"1" ;
    lvI.iSubItem = 0 ;
    lvI.iItem    = 0 ;
    
    /* створюємо перший рядок і першу комірку */
    ListView_InsertItem(listview, &lvI) ;
    
    /* заповняємо структуру для другої комірки першого рядка */
    lvI.pszText  = L"Data1" ;
    lvI.iSubItem = 1 ;
    ListView_SetItem(listview, &lvI) ;
    
    /* заповняємо структуру для другого рядка першої комірки */
    lvI.pszText  = L"2" ;
    lvI.iSubItem = 0 ;
    lvI.iItem    = 1 ;
    
    /* створюємо другий рядок і першу комірку */
    ListView_InsertItem(listview, &lvI) ;
    
    /* заповняємо структуру для другої комірки другого рядка */
    lvI.pszText  = L"Data2" ;
    lvI.iSubItem = 1 ;
    ListView_SetItem(listview, &lvI) ;
}
Для “збирання” даної програми використаємо наступний файл Makefile (для порту компілятора GCC і Makefile):
main: main.cxx
	g++ -c main.cxx -o main.obj -D UNICODE -D _UNICODE
	g++ -mwindows main.obj -o main.exe -luuid -lComctl32 -lodbc32 -lComdlg32 -lgdi32

clean:
	rm *.exe
	rm *.obj
	rm *.res
Після компілювання програми командою: compile_command Ми можемо отримати результат: main
Категорії: