Projektowanie i programowanie aplikacji biznesowych Wykład 4 1
Kontrolka ListView ListView to jedna z przydatniejszych kontrolek, pozwalająca wyświetlać informacje w postaci tabeli. Przed utworzeniem kontrolki należy wywołać funkcje InitCommonControls (załaduje ona DLL) oraz dołączyć bibliotekę commctrl.h. Do utworzenia kontrolki stosuje się funkcje CreateWindowEx. 2
HWND hlv=createwindowex(null, WC_LISTVIEW, "ListView", LVS_REPORT WS_CHILD WS_VISIBLE, 10, 10, 300, 200, hwndowner, (HMENU)ID_LV, hinstance, NULL); Lista styli: LVS_REPORT - elementy pokazane s w osobnych liniach. Informacje o elemencie możemy pogrupować w kolumny, o dowolnej nazwie. Pierwsza kolumna od lewej zawiera mała ikon. LVS_SMALLICON - elementy wyświetlane jako małe ikony z etykietami po prawej stronie. Użytkownik może zmieniać położenie elementów. LVS_ICON - tak jak LVS_SMALLICON tylko duże ikony i etykiety pod nimi LVS_LIST - tak jak LVS_SMALLICON, ale elementy są pogrupowane w kolumny LVS_ALIGNLEFT - elementy wyrównane do lewej, wymaga LVS_ICON lub LVS_SMALLICON LVS_ALIGNTOP - elementy wyrównane do góry, dotyczy styli LVS_SMALLICON i LVS_ICON LVS_AUTORANGE - automatyczne rozmieszczenie elementów (LVS_ICON lub LVS_SMALLICON) LVS_BUTTON - elementy wyglądają jak przyciski LVS_EDITLABELS - można edytować etykiety LVS_NOCOLUMNHEADER - nagłówki kolumn są niewidoczne (LVS_REPORT) LVS_NOLABELWRAP - opis elementu w pojedynczej linii (LVS_ICON) LVS_NOSCROLL - elementy nie są przewijane gdy nie mieszczą się w oknie LVS_NOSORTHEADER - nagłówki są nie posortowane LVS_SHOWSELALWAYS - zaznaczenie jest zawsze widoczne LVS_SINGLESEL - można zaznaczyć tylko jeden element LVS_SORTASCENDING - sortowanie rosnąco LVS_SORTDESCENDING - sortowanie malejąco 3
Ponadto mamy do dyspozycji długą listę styli rozszerzonych, które stosujemy podczas tworzenia kontrolki lub za pośrednictwem makra ListView_SetExtendedListViewStyle. ListView_SetExtendedListViewStyle(hLV, LVS_EX_FLATSB); Lista dodatkowych styli: LVS_EX_FLATSB - płaskie paski przewijania, LVS_EX_FULLROWSELECT - zaznaczenie całego wiersza (LVS_REPORT), LVS_EX_GRIDLINES - widoczne linie siatki (LVS_REPORT), LVS_EX_HEADERDRAGDROP - przenoszenie kolumn za pomocą myszy (z LVS_REPORT), LVS_EX_ONECLICKACTIVATE - wysyła komunikat LVN_ITEMACTIVATE podczas zaznaczenia elementu. Podświetla element po najechaniu na niego myszą, LVS_EX_SUBITEMIMAGES - pozwala dodać ikony do podelementów, LVS_EX_TRACKSELECT - zaznaczenie elementu po zatrzymaniu na nim kursora, LVS_EX_TWOCLICKACTIVATE - wysyła komunikat LVN_ITEMACTIVATE po dwukrotnym kliknięciu myszą na elemencie, LVS_EX_UNDERLINECOLD - zaznaczony element wyświetlany z podkreśleniem, LVS_EX_UNDERLINEHOT - element nad którym zatrzymał się tekst jest wyświetlany z podkreślonym tekstem, LVS_EX_CHECKBOXES - włącza CHECKBOX's dla wszystkich pozycji. 4
Przed utworzeniem kontrolki wywołuje się funkcje InitCommonControlsEx(), jako że List-View należy do grupy ''Common Controls. Tworzenie wierszy i kolumn Dodawanie kolumn polega na wypełnieniu odpowiedniej struktury (LVCOLUMN). Pole mask określa, które z pozostałych pól zawierają prawidłowe wartości. Poszczególne parametry to: ustawienie tekstu (LVCF_TEXT), szerokości kolumny (LVCF_WIDTH), oraz jej numeru (LVCF_SUBITEM). Za pośrednictwem makra ListView_InsertColumn następuje wysłanie komunikatu do struktury. 5
Reasumując aby dodać kolumnę musimy skorzystać ze struktury LVCOLUMN. Jej deklaracja wygląda następująco: typedef struct _LV_COLUMN { UINT mask; int fmt; int cx; LPTSTR psztext; int cchtextmax; int isubitem; LV_COLUMN; Poszczególne pola oznaczają: mask - określa które z pól jest "ważne" i brane pod uwagę podczas wysyłania struktury. Możliwe wartości to: LVCF_FMT - pole.fmt LVCF_SUBITEM - pole.isubitem LVCF_TEXT - pole.psztext LVCF_WIDTH - pole.cx fmt - wyrównanie w kolumnie LVCFMT_BITMAP_ON_RIGHT - bitmapa z prawej strony tekstu LVCFMT_CENTER - wysrodkowane LVCFMT_COL_HAS_IMAGES - element "nagłówkowy" zawiera obrazek LVCFMT_IMAGE - element posiada obrazek LVCFMT_LEFT - tekst wyrownany do lewej LVCFMT_RIGHT - tekst wyrównany do prawej cx - szerokość kolumny w pikselach psztext - wskaźnik na tekst będący nagłówkiem kolumny cchtextmax - rozmiar pola 'psztext isubitem - index elementu skojarzonego z kolumna 6
Dodawanie elementów do listy wygląda bardzo podobnie do dodawania kolumn. Tym razem pole isubitem oznacza, że struktura, z której korzystamy (LVITEM) odnosi się do elementu (''item''), a nie kolumny (''subitem''), dlatego też ustawiamy to pole na 0: LVi1.mask = LVIF_TEXT; for(int i=0; i<20; i++) { LVi1.pszText = "test"; LVi1.iItem = i; // numer wiersza LVi1.iSubItem = 0; ListView_InsertItem( hlv1, & LVi1 ); W efekcie uzyskamy 20-cia wierszy o zawartości "test. Po utworzeniu oczekiwanej liczby wierszy możemy uzupełnić dane w całej strukturze kontrolki czyli wprowadzić dane do pozostałych kolum. W tym celu można posłużyć się makrem ListView_SetItemText lub wysłać LVM_SETITEMTEXT. ListView_SetItemText( hlv, 0, 1, element (0,1)" ); // 0 wiersz 1-kolumna ListView_SetItemText( hlv, 0, 2, "element (0,2)" ); ListView_SetItemText( hlv, 1, 1, "element (1,1)" ); ListView_SetItemText( hlv, 1, 2, "element (1,2)" ); ListView_SetItemText( hlv, 2, 1, "element (2,1)" ); ListView_SetItemText( hlv, 2, 2, "element (2,2)" ); 7
Czyszczenie zawartości kontrolki ListView hlv1 SendMessage( hlv1, LVM_DELETEALLITEMS, 0, 0); Reakcja na zdarzenie podwójnego naciśnięcia pola kontrolki LRESULT CALLBACK Panel( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch( msg ) { case WM_NOTIFY: switch((( LPNMHDR ) lparam )->code ) { case NM_DBLCLK: MessageBox( NULL, Klik na ListView, Info", MB_ICONEXCLAMATION MB_OK ); break; Pobieranie danych z pola kontrolki ListView_GetItemText(hLV1, nr_wiersza, nr_kolumny, wartosc_odczyt, rozmiar_odczyt); Zmiana koloru tekstu i tła SendMessage(hLV1,LVM_SETBKCOLOR,0,(LPARAM)RGB( 255, 255, 0 ) ); SendMessage(hLV1,LVM_SETTEXTBKCOLOR,0,(LPARAM)RGB( 155, 155, 110 )); 8
ListView w praktyce kontynuacja programu z wykładu 3 Założenie. Naciśnięcie danego skrótu klawiszowego powinno spowodować wyświetlenie danych z tabeli Not_Zakres w kontrolce ListView. Ponadto podwójne kliknięcie na wybrany element kontrolki (kolumna ID) powinno spowodować wyświetlenie w kontrolce ListBox (Wynik SQL) danych wygenerowanych na podstawie zapytania SQL skonstruowanego na podstawie stanów kontrolek typu RadioButton i CheckBox. 9
int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow ) { InitCommonControls(); hlv1 = CreateWindowEx( 0, WC_LISTVIEW, NULL, WS_CHILD WS_VISIBLE LVS_REPORT LVS_EDITLABELS LVS_SHOWSELALWAYS LVS_EDITLABELS, 10, 490, 860, 180, hwnd,null, hinstance, NULL ); kolumny_hlv1(); void kolumny_hlv1() { LVc1.mask = LVCF_WIDTH LVCF_TEXT LVCF_SUBITEM; LVc1.iSubItem = 0; LVc1.cx = 60; LVc1.pszText = "ID"; ListView_InsertColumn( hlv1, 0, & LVc1 ); LVc1.iSubItem = 1; LVc1.cx = 70; LVc1.pszText = "Data"; ListView_InsertColumn( hlv1, 1, & LVc1); LVc1.iSubItem = 9; LVc1.cx = 100; LVc1.pszText = "Obrot"; ListView_InsertColumn( hlv1, 9, & LVc1); 10
case WM_COMMAND: char **sql_results; int nrow, ncolumn, ret; if( LOWORD( wparam ) == 2300 ) // dotyczy skrótu klawiszowego { zapytanie="select * from Not_Zakres"; SendMessage( hlv1, LVM_DELETEALLITEMS, 0, 0); sqlite3_open("baza_lab3", &pdb); ret=sqlite3_get_table(pdb, zapytanie, &sql_results, &nrow, &ncolumn, &obsluga_bledu); if( ret!= SQLITE_OK ) { MessageBox( NULL, "Blad zapytania!", "Error.", MB_ICONEXCLAMATION MB_OK ); else { wiersze_hlv1(nrow); // tworzy odpowiednią liczbę wierszy w kontrolce for(int w=1; w<=nrow; w++) { for(int k=w*ncolumn; k<(w+1)*ncolumn; k++) { ListView_SetItemText( hlv1, w-1, k%ncolumn, sql_results[k] ); sqlite3_free_table(sql_results); sqlite3_close(pdb); 11
void wiersze_hlv1(int k) { LVi1.mask = LVIF_TEXT; for(int i=0; i<=k; i++) { LVi1.pszText = ""; LVi1.iItem = k; LVi1.iSubItem = 0; ListView_InsertItem( hlv1, & LVi1 ); 12
case WM_NOTIFY: switch((( LPNMHDR ) lparam )->code ) { case NM_DBLCLK: int nr_wiersza = SendMessage( hlv1, LVM_GETNEXTITEM, 0, LVNI_SELECTED ); char wartosc_odczyt[30]; SendMessage(hLB1, LB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0); zsql="select id, data, nazwa"; if(isdlgbuttonchecked(hwnd, ID_CB1 ) == BST_CHECKED) zsql=zsql+", close"; if(isdlgbuttonchecked(hwnd, ID_CB2 ) == BST_CHECKED) zsql=zsql+", volumen"; if(isdlgbuttonchecked(hwnd, ID_CB3 ) == BST_CHECKED) zsql=zsql+", liczba_tr"; if(isdlgbuttonchecked(hwnd, ID_RB1 ) == BST_CHECKED) { ListView_GetItemText(hLV1, nr_wiersza, 1, wartosc_odczyt, 30 ); zsql=zsql+" from notowania where data='"+wartosc_odczyt+"'"; if(isdlgbuttonchecked(hwnd, ID_RB2 ) == BST_CHECKED) { ListView_GetItemText(hLV1, nr_wiersza, 2, wartosc_odczyt, 30 ); zsql=zsql+" from notowania where nazwa = '"+wartosc_odczyt+"'"; if(isdlgbuttonchecked(hwnd, ID_RB1 ) == BST_UNCHECKED && IsDlgButtonChecked(hwnd, ID_RB2 ) == BST_UNCHECKED) zsql=zsql+" from notowania"; sqlite3_open("baza_lab3", &pdb); ret=sqlite3_get_table(pdb, zsql.c_str(), &sql_results, &nrow, &ncolumn, &obsluga_bledu); if( ret!= SQLITE_OK ) { MessageBox( NULL, zsql.c_str(), "Error.", MB_ICONEXCLAMATION MB_OK ); else { for(int r=0; r<=nrow; r++) { rekord=""; for(int k=r*ncolumn; k<(r+1)*ncolumn; k++) { rekord=rekord+" "+sql_results[k]; SendMessage(hLB1, LB_ADDSTRING, (WPARAM) r, (LPARAM) rekord.c_str()); sqlite3_free_table(sql_results); sqlite3_close(pdb); 13
14
15