Nastavení
Nastavení obou verzí aplikace bude standardně uloženo v registru. Funkce pro manipulaci s nastavením v registru RegCreateKeyEx, RegQueryValueEx jsou podporovány ve všech verzích Windows. Nastavení aplikace bude v kapesním i stolním počítači uloženo v klíči HKEY_CURRENT_USER\\Software\\Petr Lesny\\List1.0.
Pro přenositelnost kódu nesmíme zapomenout i zde použít pro manipulaci s textem datový typ TCHAR a odpovídající funkce pro práci s ním. Práci s registrem je možné zapouzdřit do jednoduchého objektu. I tento objekt budeme využívat na obou platformách beze změny.
Hlavní okno aplikace
Hlavní okno aplikace bude obsahovat jediný prvek uživatelského rozhraní: seznam s ikonami (ListView). Prvek ListView může zobrazovat informace v jednom ze čtyř režimů: velké ikony s popisem, malé ikony, seznam a seznam s hlavičkami. Pro náš účel bude stačit zobrazení s malými ikonami.
ListView vytvoříme při obsluze zprávy WM_CREATE; po vytvoření k němu musíme přidat seznam ikon a naplnit jej obsahem. Abychom ušetřili paměť, jsou všechny položky uloženy v objektu Storage a ListView je vytvořen s příznakem LVS_OWNERDATA; stačí nastavit počet prvků seznamu a prvek ListView se bude pomocí upozornění LVN_GETDISPINFO dotazovat naší aplikace na texty jednotlivých položek.
HWND CreateListView(const HWND hwnd) { RECT rect; GetClientRect(hwnd, &rect); HWND hwndList = CreateWindowEx(0L, WC_LISTVIEW, TEXT(""), WS_CHILD|WS_VISIBLE|LVS_LIST|LVS_SINGLESEL| LVS_EDITLABELS|LVS_AUTOARRANGE|LVS_OWNERDATA, rect.left, rect.top, rect.right, rect.bottom, hwnd, NULL, g_hInstance, NULL); HIMAGELIST himl = ImageList_Create(16, 16, ILC_COLOR, 3, 1); ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ITEMBLANK))); ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ITEMRED))); ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ITEMGREEN))); ListView_SetImageList(hwndList, himl, LVSIL_SMALL); ListView_DeleteAllItems(hwndList); ListView_SetItemCount(hwndList, g_STORAGE->getN()); ListView_SetColumnWidth(hwndList, 0, 240); // Šířka podobně jako na PPC return hwndList; } |
Prvek ListView ovládáme pomocí funkcí ListView_XXX, které jsou popsány v dokumentaci Windows SDK. Všechny zprávy od prvku ListView jsou naší aplikaci zaslány prostřednictvím upozornění (WM_NOTIFY). Šipky, funkční klávesy apod. obsluhuje prvek ListView sám.
Nesmíme také zapomenout změnit velikost prvku ListView při každé změně velikosti okna (při obsluze zprávy WM_SIZE).
Změna některé položky našeho seznamu ListView probíhá následujícím způsobem:
- Uživatel se rozhodne změnit text u položky ListView tak, že na ní klikne 2x myší nebo programátor zavolá funkci ListView_EditLabel.
- Prvek ListView se "zeptá" naší aplikace, zda může povolit změnu prvku (zasláním upozornění LVN_BEGINLABELEDIT). Vrátíme hodnotu FALSE, proto bude změna položky povolena.
- Až uživatel dokončí změnu položky, zašle ListView naší aplikaci upozornění LVN_ENDLABELEDIT a je na programátorovi, aby se postaral o uložení změněného textu.
Pro všechny funkce prvku ListView, které budeme potřebovat si vytvoříme obalující funkce (wrappers):
Co budeme chtít udělat | Jméno naší obalující funkce | Kdy bude funkce volána |
---|---|---|
Vytvoření | CreateListView | Obsluha zprávy WM_CREATE |
Zrušení | DestroyListView | Obsluha zprávy WM_DESTROY |
Změna velikosti prvku ListView | ResizeListViewToWindow | Obsluha zprávy WM_SIZE |
Přidání nové položky na konec seznamu | AddNewItemToListView | Položka menu "New", stisk klávesy Insert, stisk kláves Shift+Enter |
Vymazání všech položek seznamu | DeleteAllItemsInListView | Položka menu "Clear". |
Editace vybrané položky seznamu | EditListViewItem | Stisk klávesy F2, dvojklik na položce seznamu; editaci mohou Windows zahájit i samostatně. |
Smazání vybrané položky seznamu | DeleteListViewItem | Stisk klávesy Delete. |
Aktualizace textu položky seznamu, která byla editována | UpdateListViewItem | Obsluha upozornění LVN_ENDLABELEDIT. |
Vyzvednutí textu a čísla ikony z prvku Storage a jejich předání prvku ListView | GetListViewItemInfo | Obsluha upozornění LVN_GETDISPINFO. |
Změna ikony u vybrané položky seznamu | ListViewChangeIcon | Stisk mezerníku na vybrané položce. |
Posun vybrané položky seznamu nahoru nebo dolů | MoveListBoxItem | Shift + klávesa se šipkou nahoru nebo dolů |
Vybrání první položky seznamu. | SelectFirstListViewItem | Stisk klávesy Enter v situaci, kdy zatím není zvýrazněna žádná položka seznamu. |
Tyto obalující funkce (wrappers) zjednodušují ovládání prvku ListView a jeho propojení s obsluhou zpráv v hlavním okně aplikace. Příklad dvou obalujících funkcí:
void DeleteListViewItem(const HWND hwnd, const HWND hwndList) { // Zjistíme základní informace o vybrané položce a počtu prvků int item = ListView_GetNextItem(hwndList, -1, LVNI_ALL|LVNI_SELECTED); int last = ListView_GetItemCount(hwndList); if(item != -1) { // Vymažeme prvek v paměti g_STORAGE->deleteItem(item); // Překreslíme všechny prvky seznamu ListView_SetItemCount(hwndList, g_STORAGE->getN()); ListView_RedrawItems(hwndList, 0, last - 1); UpdateWindow(hwnd); } } |
a
void AddNewItemToListView(const HWND hwnd, const HWND hwndList) { // Vytvoříme nový prvek v paměti int item = g_STORAGE->createItem(S_NONE, g_szNewItemText); // Přidáme informaci o něm prvku ListView LV_ITEM lvitem; lvitem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_STATE; lvitem.iSubItem = 0; lvitem.state = LVIS_FOCUSED|LVIS_SELECTED; lvitem.stateMask = LVIS_FOCUSED|LVIS_SELECTED; lvitem.iImage = S_NONE; lvitem.pszText = LPSTR_TEXTCALLBACK; lvitem.iItem = item; ListView_InsertItem(hwndList, &lvitem); // Zahájíme editaci SetFocus(hwndList); ListView_EditLabel(hwndList, item); } |
V další části našeho pravidelného seriálu si blíže popíšeme návrh uživatelského rozhraní.