06 Używanie list


Rozdział 6
Używanie list
Wyświetlanie list w oknach dialogowych Organizowanie
danych w strukturze drzewiastej
Obsługa wyboru jednej lub kilku pozycji
Implementacja zależności pomiędzy listami w oknie dialogowym
Sposób prezentacji informacji ma ogromny wpływ na sposób odbioru aplikacji jako mniej
lub bardziej przyjaznej. Aplikacje bardziej przyjazne użytkownikowi mają większe szansę na
sukces. Wiele spośród tych informacji podawanych jest w formie list: katalogów i plików,
nazw czcionek i ich stylów a nawet wykazu samolotów podchodzących do lądowania na
lotnisku w Los Angeles.
Tworzenie list
Listy mogą występować w czterech różnych odmianach: listy kombinowane (rozwijane),
pola listy, drzewa oraz listy szczegółowe. Każda z tych list spełnia określone zadania
programistyczne. Wraz z umieszczeniem obiektu listy w oknie dialogowym należy również
określić właściwy styl, ponieważ może on wpływać w sposób radykalny na wygląd oraz
działanie całego obiektu. Przykładowo, dokonywanie wyboru wielopozycyj-nego może być
dozwolone w przypadku pól listy oraz list szczegółowych, podczas gdy w przypadku listy
kombinowanej styl Drop List uaktywnia funkcjonalność pola edycji, natomiast styl
Dropdown tego nie czyni.
W niniejszym rozdziale poznamy zagadnienia związane ze stosowaniem różnego ro-
dzajów list. Zaczniemy jak zwykle, od utworzenia nowego projektu o budowie okna dia-
logowego, o nazwie Lists. Projekt będzie obejmował wszystkie cztery rodzaje list, co ma na
celu wyświetlenie struktury katalogów oraz zawartych w nich plików.
PATRZ TAKŻE
Informacje na temat tworzenia aplikacji wykorzystujących jako podstawę okno dialogowe,
znajdują się w rozdziale 3.


124_____________________________________Poznaj Visual C++ 6
Dodawanie list kombinowanych (rozwijanych)
Lista kombinowana zawdzięcza nazwę swojej budowie. Składa się bowiem z trzech kontrolek: pola
edycji, pola listy oraz przycisku. Lista tego typu umożliwia dokonanie wyboru tylko jednej pozycji. Od
pozostałych rodzajów list odróżnia ją to, iż wybrana pozycja jest zawsze widoczna u góry listy.
Tabela 6.1 wymienia trzy rodzaje, na jakie podzielić można listy kombinowane. O tym, który spośród
tych typów ma zostać zastosowany, decydujemy przy użyciu karty Styles, dostępnej w oknie dialogowym
Combo Box Properties. Okno to możemy wywołać po umieszczeniu listy na szablonie okna
dialogowego.
W nowej przykładowej aplikacji lista kombinowana użyta zostanie do dokonywania wyboru
głównego katalogu, a następnie umieszczeniu w innych obiektach okna dialogowego informacji o
podkatalogach oraz plikach.
Tabela 6. l. Rodzaje list kombinowanych Opis
Rodzaj Opis
Simple ' Łączy pole edycji z polem listy. Lista jest zawsze widoczna, wybrana pozycja natomiast
zostaje wyświetlona w polu edycji
Dropdown Łączy pole edycji wyposażone w przycisk oraz pole listy. Lista zostaje wyświetlona
dopiero po kliknięciu przycisku
Drop List Zawiera statyczne okno tekstowe, posiadające przycisk rozwijania listy oraz pole listy. Jest
to typ podobny do Dropdown z tą różnicą, że użytkownik nie może dokonywać
wpisów z klawiatury
Umieszczenie listy kombinowanej w oknie dialogowym Lists
1. Otwórz w edytorze zasobów szablon okna dialogowego, klikając dwukrotnie pozycję
IDD_LIST_DIALOG, widoczną w panelu ResoureesYiew, a następnie usuń znajdujący się
pośrodku okna napis TODO.
2. Usuń z szablonu przycisk Cancel, a OK przesuń w prawy dolny róg. Ponieważ w nowym oknie
umieścimy kilka innych obiektów, prawdopodobnie konieczne będzie powiększenie jego
rozmiarów. Na obecnym etapie okno powinno mieć proporcje jak okno pokazane na rysunku 6. l.
3. Z paska narzędziowego Controls wybierz statyczne pole tekstowe i umieść je w lewym górnym rogu
okna dialogowego.
4. Nadaj mu nagłówek: Main Directory.
5. Z paska Controls wybierz symbol listy kombinowanej i umieść taką listę po prawej stronie Main
Directory.
6. Zwiększ szerokość listy, rozciągając ją do po prawego marginesu okna dialogowego.


Używanie list 125

Rysunek 6.1. Lista kombinowana umieszczona w oknie dialogowym Lists
7. Nadaj liście identyfikator IDC_MAIN_DIR.
8. Na znajdującej się w oknie właściwości karcie Styles, z listy Type wybierz pozycję Drop List.
Umieszczona w oknie dialogowym lista kombinowana posiada domyślnie zaznaczoną opcję Sort.
Oznacza to, że wszystkie elementy występujące na liście, uporządkowane będą alfabetycznie. Aby
zrezygnować z tej opcji, należy na karcie Styles usunąć znacznik widniejący w polu wyboru Sort. Cechą
listy kombinowanej jest możliwość oglądania listy w rozwiniętym oknie. Owo okno rozwijamy klikając
przycisk widoczny w obrębie pola edycji. Wokół rozwiniętego pola listy widoczna jest ramka
formatująca, umożliwiająca zwiększenie wysokości pola za pomocą uchwytów wymiarowania.
Skoro dodaliśmy do naszego okna dialogowego listę kombinowaną, za pomocą Ciass-Wizard
przypiszemy jej teraz zmienną, wykonując poniższą procedurę.
Przypisanie zmiennej CcomboBox do listy kombinowanej
1. Wywołaj CIassWizard, naciskając kombinację klawiszy CtrI+W lub wybierając właściwą pozycję z
menu View.
2. Kliknij kartę Member Yariables.
3. Z listy Ciass Name wybierz pozycję ClistDIg.
4. W polu listy Control IDs zaznacz pozycję IDC_MAIN_DIR.
5. Kliknij przycisk Add Yariable, po czym otwarte zostanie okno Add Member Yariable.
6. Upewnij się, że z listy Category wybrana jest pozycja Control, a z listy Variable Type pozycja
CcomboBox.
7. Wpisz w polu Member Variable Name nazwę nowej zmiennej: m_ncbMainDir,
a następnie kliknij OK.
8. W oknie CIassWizard również kliknij przycisk OK, co zakończy działanie narzędzia.


O nowym rodzaju list, listach rozszerzonych, mówimy w rozdziale 11.
Rozszerzona funkcjonalność list kombinowanych
Visual C++ w swojej szóstej wersji pozwala na umieszczanie elementów graficznych jako pozycji listy
rozwijanej. Jest to tzw. rozszerzona lista rozwijana.
Dodawanie list drzewiastych
Lista drzewiasta jest unikalną listą, jedyną, która może wyświetlać informacje hierar-
chiczne. Wynika z tego sposób przedstawienia elementów listy. Element wysunięty najdalej w
lewą stronę nazywany jest root node (odsł. węzeł korzenia) węzłem początkowym. Po
przeciwnej stronie grafu występują elementy nie posiadające następujących po nich
podelementów, zwane leafnode (dosł. węzeł liścia) - węzłami końcowymi. Pomiędzy węzłami
krańcowymi występują węzły pośrednie branch node (dosł. węzeł gałęzi) - węzły
wewnętrzne.'Na wykresie węzły połączone są liniami, reprezentującymi zachodzące pomiędzy
nimi relacje. Domyślnie, lista drzewiasta zezwala na wyselekcjonowanie tylko jednego
elementu. Celem umożliwienia dokonywania wyboru kilku elementów jednocześnie trzeba
wpisać pewną porcję kodu.
W naszym przykładzie lista drzewiasta użyta zostanie do wyświetlania zawartości kata-
logów, którą stanowią pliki uporządkowane alfabetycznie. Utworzymy zatem węzły począt-
kowe dla każdej litery alfabetu, a następnie przydzielimy pliki do właściwych węzłów.
Używając po raz kolejny narzędzia CIassWizard, umieścimy w oknie dialogowym listę
drzewiastą, wykonując podane poniżej instrukcje, a następnie przydzielimy jej zmienną, co
opisuje punkt "Przydzielenie zmiennej CTreeCtrl liście drzewiastej".
Dodanie listy drzewiastej do szablonu okna dialogowego Lists
1. Otwórz w edytorze zasobów szablon okna dialogowego IDC_LISTS_DIALOG kli-kając
dwukrotnie właściwą pozycję w panelu ResourcesView.
2. Umieść na szablonie statyczne pole tekstowe, nazywając je Files. Będzie ono pełniło rolę
nagłówka listy drzewiastej, co widać na rysunku 6.2.
3. Z paska narzędziowego Controls wybierz pozycję symbolizującą listę drzewiastą, a później
umieść ją po lewej stronie okna dialogowego.
4. Wprowadź identyfikator IDC_FILES_TREE dla nowej listy.
5. Po przejściu na kartę Styles zaznacz opcje: Has Buttons, Has Lines, Lines at Root. Okno
dialogowe powinno wyglądać obecnie dokładnie jak na rysunku 6.2.


Używanie list 127

Rysunek 6.2. Okno dialogowe Lists z umieszczoną w nim listą drzewiastą
Przydzielenie zmiennej CTreeCtri liście drzewiastej
1. Wywołaj narzędzie CIassWizard, naciskając CtrI+W lub aktywując właściwą pozycję menu View.
2. Kliknij kartę Member Variables.
3. Z listy CIass Name wybierz pozycję CListsDIg.
4. Wybierz IDC_FILES_TREE z listy Control IDs.
5. Kliknij przycisk Add Variable, co spowoduje otwarcie okna dialogowego Add Member Variable.
6. Z listy Category musi być wybrana pozycja Control, natomiast jako typ zmiennej, czyli Variable
Type, musisz wybrać CTreeCtri.
7. Jako nazwę zmiennej wpisz w polu Member Variable Name: m_treeFiles, po czym kliknij OK.
8. Zamknij okno CIassWizard, klikając obecny w nim przycisk OK.
PATRZ TAKŻE
Więcej informacji na temat stylów i używania list drzewiastych w widokach dokumentów
znajduje się w rozdziale 19.
Listy drzewiaste a wybór wielopozycyjny
Klasa CTreeCtri nie pozwala wprawdzie na wybór więcej niż jednej pozycji z listy, lecz można
wyprowadzić z niej podklasę i wyposażyć ją w tę funkcję.


128_____________________________________Poznaj Visual C++ 6
Wykorzystanie pól listy
Pole listy jest najprostszą jej formą, przedstawiającą w sposób bezpośredni zawarte na liście
elementy, lecz w przeciwieństwie do list kombinowanych i drzewiastych, umożliwia jednoczesny wybór
więcej niż jednego elementu. Lista tego rodzaju występuje w czterech wariantach dotyczących
możliwości dokonywania wyboru pozycji. Warianty te opisane są w tabeli 6.2.
Tabela 6.2. Typy selekcji w polach listy
Typ Opis
Single Można wybrać tylko jeden element listy. Wybranie któregoś z nich unieważnia ostatnio
dokonaną selekcję
Multiple Można dokonać selekcji kilku elementów listy, klikając je myszą, w połączeniu z klawiszem
Shift lub Ctrl
Extended Spełnia funkcje typu Multiple, pozwalając dodatkowo na dokonywanie wyboru poprzez
przeciągnięcie myszą z wciśniętym jej lewym klawiszem, ponad wybranymi elementami
None Nie zezwala na wybór żadnego elementu
Podobnie jak w przypadku listy kombinowanej, porządkowanie alfabetyczne jest przyjęte
jako domyślne. Aby zmienić ten stan rzeczy, musimy usunąć znacznik opcji Sort, na karcie
Styles. W naszym projekcie Lists użyjemy pola listy do wyświetlenia podkata-logów.
Będziemy mogli wybrać kilka spośród nich, a z listy szczegółowej odczytać dodatkowe
szczegóły. Zaczniemy od umieszczenia pola listy typu Multiple w oknie dialogowym, co
uczynimy według przedstawionej poniżej procedury. Odnosi się ona do opcji stylu No
Integral Height, która niezaznaczona powoduje obliczenie wysokości pola listy w celu
pomieszczenia konkretnej liczby elementów. Jeśli pozostawimy tę opcję aktywną, pole będzie
wyświetlało listę partiami.
Umieszczenie pola listy w oknie dialogowym Lists
1. Otwórz szablon okna dialogowego IDD_LISTS_DIALOG w edytorze zasobów.
2. Dodaj statyczne pole tekstowe o nagłówku Sub Directories, które będzie opisywało
zawartość pola listy.
3. Z paska narzędziowego Controls wybierz pole listy i umieść je wzorując się na rysunku 6.3.
4. Jako identyfikator pola listy wpisz: IDC_SUB_DIRS.
5. Otwórz kartę Styles, a w niej z listy Selection wybierz pozycję Extended.


Używanie list 129
6. Na tej samej karcie usuń znacznik z pola wyboru No Integral Height. Okno dialogowe
powinno obecnie wyglądać jak na rysunku 6.3.
Teraz, skoro pole listy jest już dodane, należy przydzielić mu zmienną.

Rysunek 6.3. Okno dialogowe Lists z dodanym polem listy
Przydzielenie zmiennej CListBox do pola listy
1. Wywołaj narzędzie CIassWizard, naciskając Ctri+W lub aktywując właściwą pozycję
menu View.
2. Kliknij kartę Member Variables.
3. Z listy Ciass Name wybierz pozycję CListsDIg.
4. Z pola listy Control IDs wybierz identyfikator IDC_SUB_DIRS.
5. Kliknij przycisk Add Variable, co spowoduje otwarcie okna dialogowego Add Member
Variable.
6. Z listy Category musi być wybrana pozycja Control, natomiast jako typ zmiennej, czyli
Variable Type, musisz wybrać CListBox.
7. Jako nazwę zmiennej wpisz w polu Member Variable Name: m_lbSubDirs, po czym
kliknij OK.
8. Zamknij okno CIassWizard, klikając obecny w nim przycisk OK.
Użycie list szczegółowych
Lista tego typu jest najbardziej złożonym obiektem spośród list i stosowana jest raczej
jako samodzielny widok, niż element okna dialogowego. Może ona wyświetlać symbole
graficzne wraz z towarzyszącymi im napisami. Posiada cztery tryby wyświetlania, wymie-
nione w tabeli 6.3.


130 Poznaj Visual C++6
Eksplorator Windows wykorzystuje listę szczegółową
Najbardziej znamiennym przykładem zastosowania listy szczegółowej jest Eksplorator
Windows, Menu View pozwala na wybór jednego z czterech trybów wyświetlania.
Tabela 6.3. Typy widoku listy szczegółowej Tryb
widoku Opis
Icon Wyświetla duże ikony (32 X 32 piksele) z podpisami umieszczonymi pod spodem, ikony
porządkowane są w rzędach
Smali Icon Tryb podobny do poprzedniego z tą różnicą, że wyświetlane są małe ikony (16 x
16pikseli).
List Wyświetla w sposób podobny do trybu Smali Icon, ikony porządkowane są w kolumnach
Report Wyświetla w kolumnach informacje o plikach. Kolumny posiadają swoje nagłówki
W przykładzie Lists lista szczegółowa wykorzystana będzie do wyświetlania szczegółów
katalogów, wyselekcjonowanych w polu listy leżącym powyżej. Informacje na tej liście
umieszczone będą w trzech kolumnach. Zawartością pierwszej z nich będzie nazwa katalogu,
drugiej liczba plików znajdujących się w katalogu, a trzecia kolumna posłuży do podania
rozmiaru katalogu w megabajtach. Po dodaniu listy szczegółowej do okna dialogowego, co
uczynimy kierując się podaną niżej procedurą, przydzielimy jej za pomocą CIassWizard
zmienną CListCtri.
Umieszczenie listy szczegółowej w oknie dialogowym
1. Otwórz szablon okna dialogowego IDD_LISTS_DIALOG w edytorze zasobów.
2. Umieść w nim nowe statyczne pole tekstowe, nazwij je Selected Directory Details, aby
pełniło rolę nagłówka listy i porównaj z rysunkiem 6.4.
3. Wybierz pozycję listy szczegółowej z paska narzędziowego Controls i umieść ją
posługując się rysunkiem 6.4.


Używanie list 131

Rysunek 6.4. Okno dialogowe z dodaną listą szczegółową
4. Nadaj nowej liście identyfikator IDC_SELECTED_DIRS.
5. Po kliknięciu karty Styks z widocznej tam listy View wybierz pozycję Report. Okno
dialogowe powinno wyglądać teraz dokładnie jak na rysunku 6.4.
Przydzielenie liście szczegółowej zmiennej CListCtrl
1. Jednym ze znanych już sposobów otwórz CIassWizard.
2. Kliknij kartę Member Yariables.
3. Wybierz pozycję CListsDlg spośród obecnych na liście Ciass Name.
4. Następnie zaznacz pozycję IDC_SELECTED_DIRS z listy Control IDs.
5. Kliknij Add Variable.
6. Upewnij się, że lista rozwijana Category wyświetla Control, a Variable Type pokazuje
pozycję CListCtri.
7. W polu Member Variable Name wpisz m_lcDirsDetails, a następnie kliknij OK.
8. Kliknij OK, aby zamknąć CIassWizard.
PATRZ TAKŻE
^ Więcej informacji o listach szczegółowych (kontrolkach list), ich stylach i wykorzystaniu
znajduje się w rozdziale 19.
Zapełnianie list
Ponieważ listy szczegółowe służą wyświetlaniu i dokonywaniu selekcji różnych ele-
mentów, należy tę listę nimi wypełnić. Każdy wpis wprowadzony na listę staje się jej


132 Poznaj Visual C++ 6
elementem. Jakkolwiek mechanizm ten jest podobny dla wszystkich typów list, to podczas
dalszej lektury przekonamy się, że każda z list posiada specyficzne właściwości.
Umieszczanie elementów na liście kombinowanej
Lista kombinowana jest jedyną spośród list, które można wypełniać za pośrednictwem
edytora zasobów. Przeprowadzamy ten proces, wykorzystując kartę Data w oknie dialogowym
właściwości listy. Przykład widoczny jest na rysunku 6.5. Każda pozycja listy może zostać
wprowadzona poprzez wpis w polu Enter Listbox Items. Jeśli zachodzi potrzeba dopisywania
kolejnych pozycji w ten sposób, należy wciskać kombinację CtH+Enter po każdym wpisie,
ponieważ naciśnięcie samego klawisza Enter spowoduje zamknięcie okna. Praktyka taka nie
jest jednakże stosowana. Zwykle listę wypełnia się w trakcie pracy programu, często poprzez
funkcję OninitDialog (). Osnowa MFC wywołuje tę funkcję przed otwarciem okna
dialogowego.
s t
Entet
listboK
iterns:

Generał s Data i Slytes | Exlended Stytes


Disdnction *J ", Meri( ' Credit " :' Pass --Fail ::-
,., , , ,, , ^,tf|

Rysunek 6.5. Karta Data w oknie właściwości listy kombinowanej
Klasą MFC, obsługującą listy kombinowane jest CComboBox. Klasa ta posiada kilka
zaimplementowanych funkcji odpowiedzialnych za umieszczanie na liście nowych elementów i
usuwanie obecnych. Każdy nowo dodany element opatrzony zostaje numerem, który pozwala później na
odwoływanie się do niego.
Tabela 6.4. Funkcje klasy CComboBox związane z zawartością listy
Nazwa funkcji Opis
AddString Dodaje nowy element na końcu listy lub w miejscu wynikającym z ustalonego
porządku sortowania
DeleteString Usuwa element z listy
InsertString Umieszcza element w wybranym punkcie listy
ResetContent Usuwa całą zawartość listy
Dir Specjalny tryb służący umieszczaniu na liście nazw plików jako elementów listy


Używanie list_______________________________________ 133
W przykładowym programie Lists lista kombinowana zostanie wypełniona za pośrednictwem
funkcji okna dialogowego OninitDialog () wykazem katalogów pobranym za pomocą pewnych funkcji
globalnych systemu Windows. Najpierw musimy jednak zadeklarować nową zmienną
PopulateCombo()o typie zwracanej wartości void. Następnie należy zmodyfikować zawartość funkcji
poprzez wpisanie kodu zawartego na listingu 6. l, od linii 28. Na koniec będziemy musieli jeszcze
wpisać kod zawarty w liniach 34-53 tego samego listingu.
Listing 6. l. LST06_1 .CPP wypełnianie listy kombinowanej
1 BOOL CListsDlg::OninitDialog()
2 (
3 CDialog::OninitDialog();
4
5 // Dodaj pozycję "About..." do menu systemowego.
6 // IDM ABOUTBOX musi pozostawać w zasięgu poleceń systemu. 1
ASSERTf(IDM_ABOUTBOX & OxFFFO) == IDM_ABOUTBOX);
8 ASSERT(IDM_ABOUTBOX < OxFOOO);
9
10 CMenu* pSysMenu = GetSystemMenu(FALSE);
11 if (pSysMenu != NULL)
12 (
13 CString strAboutMenu;
14 strAboutMenu.LoadString(IDS_ABOUTBOX) ;
15 if (!strAboutMenu.IsEmpty() )
16 {
17 pSysMenu->AppendMenu(MF_SEPARATOR) ;
18 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu) ;
19 }
20 }
O
21 // Ustal ikonę dla okna dialogowego II Odbywa się to automatycznie
22 II gdy okno główne aplikacji // nie jest oknem dialogowym
23 Setlcon(m_hlcon, TRUE); // Set big icon
24 Setlcon(m_hlcon, FALSE); // Set smali icon
25
26 // TODO: Tutaj zainicjuj nową funkcję
27 // ** Inicjalizacja listy kombinowanej dla głównego katalogu
28 PopulateCombo();


Używanie list 135
cymi w buforze szBuffer argumenty w postaci określonych ścieżek dyskowych. Definicja MAX_PATH
służy określeniu maksymalnej liczby znaków w nazwie ścieżki. W większości wypadków wynosi ona
260. Po pobraniu nazw ścieżek, zawartość bufora szBuffer przekazywana jest zmiennej m_cbMainDir
funkcji AddString (), która odpowiada za umieszczenie tych nazw w polu listy. Ponieważ lista
kombinowana w naszym przykładzie posiada aktywną opcję Sort, nowe elementy listy zostaną ułożone
w porządku alfabetycznym.
Reakcja programu na komunikaty powiadamiające listy kombinowanej
Zadaniem listy kombinowanej jest umożliwienie użytkownikowi dokonanie wyboru jednego
spośród dostępnych w niej elementów. Gdy przebiega to normalnym trybem, program musi dostać
właściwą wiadomość, natychmiast po dokonaniu wyboru, a następnie zareagować na fakt zmiany
selekcji w określony sposób. Możliwe to jest poprzez prze-chwytywanie komunikatu
powiadamiającego CBN_CHANGE, wysyłanego przez listę do okna dialogowego w momencie zmiany
wybranej pozycji.
Dodamy zatem funkcję obsługi komunikatu CBN_CHANGE dla listy kombinowanej IDC_MAIN_DIR.
Powinna zostać utworzona jednocześnie funkcja składowa OnSelchan-geMainDir (). Będziemy musieli
także powołać nową zmienną składową klasy CString:
m_strMainDir, która będzie przechowywała nazwę ścieżki. Ta sama zmienna posłuży nam w dalszym
toku działań do wypełniania listy drzewiastej oraz pola listy. Teraz jednak wpiszemy kod zawarty na
listingu 6.2.
Sprawdzanie błędów powstałych podczas wypełniania listy kombinowanej
Należy sprawdzać wartości zwracane przez funkcje AddString()oraz insert-StringO. Jeśli podczas
wypełniania listy pojawią się błędy, wartości zwracane przyjmą postać CB__ERR lub CB_ERRSPACE.
Listing 6.2. LST06_2.CPP - pobieranie zapisu pozycji wybranej z listy kombinowanej
1 void CListsDlg::OnSelchangeMainDir()O
2 (
3 // TODO: Tutaj umieść kod funkcji obsługi komunikatu
4 // ** Pobranie numeru porządkowego wybranej pozycji
5 int nlndex = m_cbMainDir.GetCurSel();@
6
7 // ** Sprawdzenie poprawności numeru porządkowego
8 if(nlndex != CB_ERR)
9 {
10 // ** Pobranie zapisu wybranej pozycji oraz przechowanie
11 // ** jej w zmiennej oraz wywołanie funkcji dla
12 // ** wypełnienia pozostałych list


134_____________________________________Poznaj Visual C++ 6 i
29 return TRUE; // Zwraca TRUE dopóki okno listy nie jest ( // aktywne l
30 }
31 ' l
32 void CListsDlg::PopulateCombo() '
33 (
34 TCHAR szBuffer[MAX_PATH];
35 , @
36 // ** Pobierz katalog systemu Windows, zwykle C:\Windows
37 // ** i umieść na liście kombinowanej
38 GetWindowsDirectory(szBuffer, MAX_PATH); '.
39 m_cbMainDir.AddString(szBuffer) ;
40

41 // ** Odrzuć katalog i pozostaw tylko identyfikator dysku C:
42 // ** i umieść go w oknie listy kombinowanej
43 szBuffer[2]=0;
44 m_cbMainDir.AddString(szBuffer) ;
45
46 // ** Pobierz katalog System, t l zwykle C:\Windows\System
47 // ** i umieść w oknie listy
48 GetSystemDirectory(szBuffer, MAX_PATH); 0
49 m_cbMainDir.Add3tring(szBuffer) ;
50 l
51 // ** Pobierz katalog bieżący i umieść w oknie listy
52 GetCurrentDirectory(MAX_PATH, szBuffer);
53 m_cbMainDir.AddString(szBuffer);
54 )__________________,___________________________________ ,
O Wywołanie funkcji PopulateCombo () z funkcji OninitDialog (). Umieszczenie
katalogu Windows w oknie listy.
Odrzucenie katalogu i pozostawienie jedynie identyfikatora dysku oraz umieszczenie go w oknie
listy.
O Umieszczenie katalogu systemowego w oknie listy.
Umieszczenie bieżącego katalogu w oknie listy.
Funkcje GetWindowsDirectoryO, GetSystemDirectory() oraz GetCurrent-DirectoryO wywołane
kolejno w liniach 28, 48 i 52 są globalnymi funkcjami zapisują-


Używanie list 135
cymi w buforze szBuffer argumenty w postaci określonych ścieżek dyskowych. Definicja MAX_PATH
służy określeniu maksymalnej liczby znaków w nazwie ścieżki. W większości wypadków wynosi ona
260. Po pobraniu nazw ścieżek, zawartość bufora szBuffer przekazywana jest zmiennej m_cbMainDir
funkcji AddString (), która odpowiada za umieszczenie tych nazw w polu listy. Ponieważ lista
kombinowana w naszym przykładzie posiada aktywną opcję Sort, nowe elementy listy zostaną ułożone
w porządku alfabetycznym.
Reakcja programu na komunikaty powiadamiające listy kombinowanej
Zadaniem listy kombinowanej jest umożliwienie użytkownikowi dokonanie wyboru jednego
spośród dostępnych w niej elementów. Gdy przebiega to normalnym trybem, program musi dostać
właściwą wiadomość, natychmiast po dokonaniu wyboru, a następnie zareagować na fakt zmiany
selekcji w określony sposób. Możliwe to jest poprzez prze-chwytywanie komunikatu powiadamiającego
CBN_CHANGE, wysyłanego przez listę do okna dialogowego w momencie zmiany wybranej pozycji.
Dodamy zatem funkcję obsługi komunikatu CBN_CHANGE dla listy kombinowanej IDC_MAIN_DIR.
Powinna zostać utworzona jednocześnie funkcja składowa OnSelChan-geMainDir (). Będziemy musieli
także powołać nową zmienną składową klasy CString:
m_strMainDir, która będzie przechowywała nazwę ścieżki. Ta sama zmienna posłuży nam w dalszym
toku działań do wypełniania listy drzewiastej oraz pola listy. Teraz jednak wpiszemy kod zawarty na
listingu 6.2.
Sprawdzanie błędów powstałych podczas wypełniania listy kombinowanej
Należy sprawdzać wartości zwracane przez funkcje AddString () oraz insert-StringO. Jeśli podczas
wypełniania listy pojawią się błędy, wartości zwracane przyjmą postać CB_ERR lub CB_ERRSPACE.
Listing 6.2. LST06_2.CPP - pobieranie zapisu pozycji wybranej z listy kombinowanej
1 void CListsDlg::OnSelchangeMainDir()0
2 {
3 // TODO: Tutaj umieść kod funkcji obsługi komunikatu
4 // ** Pobranie numeru porządkowego wybranej pozycji
5 int nlndex = m_cbMainDir.GetCurSel();@
6
7 // ** Sprawdzenie poprawności numeru porządkowego
8 if(nlndex != CB_ERR)
9 {
10 // ** Pobranie zapisu wybranej pozycji oraz przechowanie
11 // ** jej w zmiennej oraz wywołanie funkcji dla
12 // ** wypełnienia pozostałych list


136_____________________________________Poznaj Visual C++ 6
13 m_cbMainDir.GetLBText(nlndex, m_strMainDir);
14 PopulateTree();O
15 }
16 }
O Wywołanie następuje, gdy użytkownik zmieni dotychczasowy wybór pozycji z listy. Program
pobiera numer porządkowy wybranej pozycji na liście. Następuje pobranie i przechowanie nazwy
katalogu. O Wywołanie funkcji w celu wypełnienia listy drzewiastej.
W momencie otrzymania komunikatu o zmianie wybranej pozycji widoczna w linii 5 funkcja
GetCurSel () i zwraca numer porządkowy wybranej pozycji do zmiennej nlndex. Jeśli nie została wybrana
natomiast żadna z pozycji listy, co sprawdzone zostaje w linii 8, wtedy zwracana jest specjalna wartość
CB_ERR. Jeżeli wartość nlndex zostaje uznana, zostaje przekazana w linii 13 funkcji GetLBText () wraz ze
zmienną m_strMainDir. W linii 14 natomiast widzimy wywołanie nowej funkcji Populatetree (), którą
zajmiemy się w następnym punkcie.
Wypełnianie listy drzewiastej
Podczas tego procesu często zachodzi konieczność przechowania informacji o strukturze drzewa, by móc
określić, które elementy listy są podrzędne, a które nadrzędne w stosunku do nowej, umieszczanej na liście
pozycji, i
Klasą biblioteki MFC odpowiedzialną za funkcjonowanie list drzewiastych jest CTree-Ctri. Funkcja ta
wyposażona jest w wymienione w tabeli 6.5 funkcje, które służą dodawaniu nowych lub usuwania istniejących
elementów listy. Funkcja lnsertltem() występuje w kilku odmianach przeciążonych, których zadaniem jest
zaspokojenie potrzeb programu i w zakresie umieszczania wskaźników do obiektów graficznych innych
obiektów zewnętrznych. Każda pozycja wprowadzana na listę otrzymuje indywidualny wskaźnik HTREEITEM, który
może zostać przekazany funkcji lnsertltem(), co umożliwia tworzenie hierarchii drzewa.
Tabela 6.5. Funkcje klasy CTreeCtrl wypełniające listę Nazwa
funkcji Opis
Insertitem Umieszcza nowe elementy jako nadrzędne lub podrzędne wobec innych, zależnie od
parametrów
Deleteltem Usuwa pozycję listy DeleteAllItems Usuwa
wszystkie pozycje listy


Używanie list 137
By wypełnić listę drzewiastą, musimy powołać do życia nową funkcję składową, o nazwie
PopulateTree (), o typie zwracanej wartości void. Pliki umieszczone na liście jako jej pozycje, pokazane
są w oknie listy w porządku alfabetycznym. Funkcja umieszcza na liście najpierw pozycje organizujące
porządek alfabetyczny, a później dodatkową 27 pozycję dla plików, których nazwy zaczynają się od
znaku innego niż litera. Następnie ta sama funkcja, posługując się innymi obecnymi w systemie
Windows funkcjami, pobiera nazwy plików umieszczonych w danym katalogu i według klucza
alfabetycznego wstawia te nazwy we właściwe miejsca listy. Kiedy mamy gotową funkcję PopulateTree
(), musimy dopisać kod umieszczony na listingu 6.3.
Listing 6.3. LST06_3.CPP - wypełnianie listy drzewiastej
1 void CListsDlg::PopulateTree()
2 {
3 // ** Usuń wszystkie pozycje z listy
4 m treeFiles.DeleteAllItems();
5 // ** Umieść tablicę HTREEITEMS
6 HTREEITEM hLetter[27]; O
7 // ** Umieść węzły początkowe dla liter A-Z S for(int nChar =
'A'; nChar <= 'Z'; nChar++)
9 hLetter[nChar - 'A'] =
m_treeFiles.InsertItem((TCHAR*)SnChar) ;
10
11 // ** Umieść węzeł "Other"
12 hLetter[26] = iri_treeFiles . Insertitem ("Other") ;
13
14 HANDLE hFind;
15 WIN32_FIND_DATA dataFind;
16 BOOL bMoreFiles = TRUE;
17 CString strFile;
18
19 // ** Znajdź pierwszy plik w katalogu
20 hFind = FindFirstFile(m_strMainDir + "\\*.*", &dataFind); @
21
22 // ** Kontynuuj przeszukiwanie katalogu, aż do odnalezienia II **
wszystkich plików
23 while(hFind != INVALID_HANDLE_VALUE && bMoreFiles == TRUE)
24 {
25 // ** Sprawdź, czy znaleziony plik nie jest katalogiem
26 if(dataFind.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE)
27 {
28 // ** Pobierz pierwszą literę nazwy pliku


138 Poznaj Visual C++ 6
29 int nChar = dataFind.cFileName[0];
30 // ** Dokonaj konwersji małych liter na wielkie
31 if(islower(nChar))
32 nChar -= 32;
33 // ** Jeśli nazwa pliku zaczyna się od litery,
34 // ** wyodrębnij 'A' by ustalić jej miejsce w tablicy
35 // ** hLetter
36 if(isalpha(nChar))
37 nChar -= 'A' ;
38 else
39 nChar =26;
40 // ** Umieść nazwę pliku na liście
41 m_treeFiles.Insertitem(dataFind.cFileName, O
hLetter[nChar]) ;
42 }
43 // ** Znajdź kolejny plik w katalogu
44 bMoreFiles = FindNextFile(hFind, SdataFind);
45 }
46 // ** Zakończ poszukiwanie
47 FindClose(hFind);
48 l
O Umieszczenie węzłów początkowych dla wszystkich liter alfabetu.
@ Odszukanie pliku w katalogu zapisanym w m strMainDir.
Iteracja wszystkich plików znalezionych w katalogu.
O Umieszczenie nazwy pliku na liście.
W linii 4 powyższego listingu następuje wywołanie funkcji DeleteAllltems (), usuwającej wszystkie
pozycje listy. Jest to konieczne, ponieważ wypełnianie listy odbywa się za każdym razem, gdy zmienimy
katalog bieżący. Pętla for umieszczona w liniach 8 i 9 wywołuje funkcję lnsertltem() podając jako
parametr kolejne litery alfabetu. Ponieważ nie ma innych zdefiniowanych parametrów, litery te
automatycznie dołączane są do listy. Po każdym wywołaniu funkcji insertitemO zwrócony wskaźnik
HTREEITEM zostaje zapisany w tablicy hLetter. Dlatego pozycja tablicy hLetter [0] przechowuje wskaźnik
litery A, hLetter [l] litery B itd. Węzeł początkowy Others umieszczony w linii 12, przechowywać będzie
nazwy plików nie zaczynające się od liter.
Pobieranie nazw plików rozpoczyna się od wywołania w linii 20 funkcji FindFirst-itemO. Jako
argument podana jest zmienna m_strMainDir + "\\*.*", co służy przeszukaniu wybranego katalogu.
Następnie w linii 44 wywołana zostaje funkcja Find-Nextltem(), której zadaniem jest pobranie nazw
kolejnych plików. Zwraca ona PALSE


Używanie list 139
gdy już pobrane zostaną nazwy wszystkich plików, a to powoduje zatrzymanie działania pętli. Obie
funkcje Find zapisują pobrane nazwy w zmiennej dataFind, która należy do struktury
WIN32_DATA_FIND. Struktura owa przechowuje informacje o wszystkich odnotowanych pozycjach.
Poprzez linię 26 sprawdzone zostają atrybuty wszystkich odnalezionych plików. Ma to na celu
stwierdzenie, że mamy do czynienia z plikiem, a nie podkatalogiem. W linii 29 pobrany zostaje pierwszy
znak nazwy pliku i jeśli to konieczne, w linii 32 zamieniony z litery małej na wielką. Linia 36 kontroluje,
czy nazwa pliku rozpoczyna się od znaku alfabetycznego. Jeżeli tak jest, wartość danego znaku
skonwertowana zostaje na numer indeksu w tablicy hLetter. Wywołana natomiast w linii 41 funkcja
lnsertltem() powoduje przypisanie nazwy pliku do odpowiedniego węzła.
Po skompilowaniu i uruchomieniu aplikacji jej okno dialogowe powinno wyglądać jak na rysunku
6.6. Widać na nim rozwiniętą listę katalogów wraz z zawartością pierwszego z nich.

Rysunek 6.6. Widok okna dialogowego Lists z funkcjonującą listą drzewiastą i listą rozwijaną
Wypełnianie pola listy
Wypełnianie pola listy przebiega praktycznie identycznie z wypełnianiem listy kombinowanej.
Najważniejszymi różnicami pomiędzy tymi dwoma typami obiektów jest sposób wyświetlania listy oraz
to, iż pola listy umożliwiają dokonywanie wyboru kilku pozycji jednocześnie.
Klasą MFC, która odpowiada za obsługę pól listy jest CListBox. Funkcje w niej zawarte, służące
umieszczaniu nowych i usuwaniu istniejących pozycji listy, są identyczne z funkcjami wymienionymi w
tabeli 6.4, znajdującej się nieco wcześniej w tym rozdziale.
W przykładzie Lists ten rodzaj obiektu wykorzystamy do wyświetlania podkatalogów zawartych w
katalogu, który jest podany w polu edycji listy kombinowanej. Zaczniemy od


140_____________________________________Poznaj Visual C++ 6
dodania nowej funkcji składowej, o nazwie PopulateListBox()i typie zwracanej wartości void.
Następnie poddamy edycji zapis funkcji OnSelChangeMainDir (), która wywoływana będzie po
wywołaniu PopulateTree ().
Wpiszemy teraz kod zawarty na listingu 6.4, by spowodować wypełnienie pola listy nazwami
podkatalogów.
Listing 6.4. LST06_4.CPP - wypełnianie pola listy
1 void CListsDlg::PopulateListBox()
2 {
3 // ** Usunięcie wszystkich dotychczasowych elementów listy
4 m_lbSubDirs.ResetContent() ;O
5
6 HANDLE hFind;
7 WIN32_FIND_DATA dataFind;
8 BOOL bMoreFiles = TRUE;
9
10 // ** Odnalezienie pierwszego pliku w głównym katalogu
11 hFind = FindFirstFile(m_strMainDir + "\\*.*", SdataFind); @
12
13 // ** Pętla wyszukująca wszystkie pozostałe pliki
14 while(hFind != INVALID_HANDLE_VALUE && bMoreFiles == TRUE)
15 {
16 // ** Sprawdzenie obecności podkatalogów
17 if(dataFind.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
18 {
19 // ** Umieszczenie w polu listy nazw podkatalogów
20 II ** z pominięciem pozycji "." oraz ".."
21 if(strcmp(dataFind.cFileName, ".")) 0
22 iffstrcmp(dataFind.cFileName, "..")) O
23 m_lbSubDirs.Add3tring(dataFind.cFiieName) ;
24 }
25 // ** Odnalezienie następnego pliku w katalogu głównym
26 bMoreFiles = FindNextFile(hFind, SdataFind);
27 }
28 // ** Zakończenie pobierania nazw plików
29 FindClose(hFind);
30 )
O Umieszczenie węzłów początkowych dla wszystkich liter alfabetu.


Używanie list 141
O Umieszczenie węzłów początkowych dla wszystkich liter alfabetu. Odszukanie
pliku w katalogu zapisanym w m_strMainDir. Iteracja wszystkich plików
znalezionych w katalogu. O Umieszczenie nazwy pliku na liście.
Widoczne w linii 4 wywołanie funkcji ResetContent () powoduje usunięcie dotychczasowej
zawartości listy. Jest to niezbędne, ponieważ pole listy jest wypełniane za każdym razem, gdy dokonamy
zmiany katalogu wybranego za pośrednictwem listy kombinowanej. Aby przypomnieć sobie szczegóły
dotyczące funkcji FindFirstitemO oraz FindNext-ltem(), musimy się nieco cofnąć, do punktu
"Wypełnianie listy drzewiastej", w tym rozdziale.
Atrybuty każdej odnalezionej pozycji są sprawdzane w linii 17 w celu upewnienia się, iż dana
pozycja jest podkatalogiem. Dwa wywołania funkcji strcmpOw liniach 21 i 22 powodują zignorowanie
pozycji . oraz .. . Funkcji AddStringO wywołanej w linii 23 podana zostaje nazwa pozycji (w tym
wypadku jest to nazwa podkatalogu), która jest wyświetlona w polu listy. Jeśli skompilujemy i
uruchomimy aplikację, stwierdzimy, że wybranie katalogu z listy kombinowanej spowoduje jego
rozwinięcie listy drzewiastej oraz pola listy.
Reakcja programu na komunikaty powiadamiające pola listy
Działania, które użytkownik wykonuje w obrębie pola listy, powodują wysyłanie do okna
dialogowego aplikacji komunikatów powiadamiających. Komunikat LBN_SELCHANGE zostaje wysłany,
gdy użytkownik dokona zmiany wyboru pozycji z listy. Sposób traktowania poczynionego przez
użytkownika wyboru zależy od tego, czy lista pozwala wybierać kilka pozycji jednocześnie oraz od
funkcji składowych klasy CListBox.
Pole listy użyte w przykładzie Lists zezwala na wybór wielopozycyjny. Funkcja obsługi komunikatu
tworzy listę wybranych katalogów i zapisuje ją w nowej zmiennej składowej klasy cstringList, m_strList.
Musimy zatem dodać tę zmienną, korzystając z okna dialogowego Add Member Variable.
Dodamy także funkcję obsługi komunikatu LBN_SELCHANGE dla pola listy IDC_SUB_DIRS. W ten
sposób utworzona również zostanie funkcja składowa OnSelChan-geSubDirs (). Funkcja ta określać
będzie, ile pozycji wybrał użytkownik, a także będzie pobierać ich nazwy i zapisywać je w zmiennej
m_strList. Na koniec ta sama funkcja wywoływać będzie inną, populateListControl (), która z kolei użyje
zawartości zmiennej m_strList do wyświetlenia szczegółowego wykazu pozycji na liście szczegółowej.
Dopiszemy teraz kod z listingu 6.5.


Listing 6.5. LST06_5.CPP - reakcja aplikacji na komunikat powiadamiający pola listy
1 void CListsDlg::OnSelchangeSubDirs() O '
2 {
3 // TODO: Tutaj wpisz kod funkcji obsługi komunikatu
4 // ** Sprawdzenie liczby wybranych pozycji
5 int nSelCount = m_lbSubDirs.GetSelCount(); @
6
7 // ** Wyczyszczenie zawartości m_strList
8 m_strList.RemoveAll() ;
9 if(nSelCount)
10 ( >
11 CString str;
12 // ** Utworzenie tablicy typu int przechowującej indeksy
13 // ** oraz jej inicjalizacja z indeksami wybranych pozycji
14 LPINT pitems = new int[nSelCount]; l
15 m_lbSubDirs.GetSelItems(nSelCount, pitems);
16
17 for(int i = 0; i < nSelCount; i++) @
18 (
19 // ** Pobranie nazw wybranych pozycji
20 // ** oraz zapisanie ich w zmiennej
21 m_lbSubDirs.GetText(pitems[i], str); O
22 m_strList.AddTail(str) ; O
23 ) )
24 // ** Uporządkowanie zawartości tablicy
25 delete [] pitems;
26 }
27 // ** Wypełnienie listy szczegółowej
28 PopulateListControl();
29 }
O Funkcja jest wywołana, gdy użytkownik dokona zmiany wyboru.
Pobranie liczby wybranych pozycji.
Wypełnienie tablicy.
O Zapisanie nazwy wybranego katalogu w zmiennej m_strList.
Wywołanie funkcji wypełniającej listę szczegółową.


Używanie list 143
W linii 14 ustanowiona zostaje tablica wartości i n t. Tablica ta zawierać będzie indeksy wybranych
z listy pozycji i z tego powodu jej rozmiar musi być równy nSelCount. Zmienna pitems jest wskaźnikiem
wartości w tej tablicy i zainicjowana zostaje ze wskazaniem jej początku. W linii 25 tablica zostaje
usunięta poprzez użycie delete [ ], kiedy nie jest dłużej potrzebna.
W linii 15 funkcja GetSelltems () pobiera listę wybranych elementów. Lista owa posiada indeks
początkowy 0. Drugim parametrem tej funkcji jest wskaźnik tablicy i n t, którą funkcja wypełnia.
Pętla for rozpoczęta w linii 17 dokonuje iteracji dla wszystkich wybranych elementów. Za każdym
przebiegiem wywoływana jest funkcja GetText (), pobierająca kolejny indeks z tablicy (pitems [l]) i
zapisując nazwę w zmiennej str. Następnie w linii 22 nazwa ta jest dołączana na końcu zawartości
m_strList. Ponieważ za każdym razem, kiedy lista wybranych podkatalogów ulega zmianie, elementy
wykazane na liście szczegółowej są wywoływane w linii 28, na końcu funkcji PopulateListControl ().
Wypełnianie listy szczegółowej
Wypełnianie listy szczegółowej przebiega nieco inaczej niż w przypadku pozostałych typów list,
opisanych w tym rozdziale. Zależy ono od sposobu przedstawienia danych na tej liście. Istnieją cztery
sposoby wypełniania: Icon, Smali Icon, List oraz Report, o czym mówiliśmy wcześniej w tym
rozdziale. Prawdopodobnie najczęściej używanym (i najbardziej użytecznym) trybem jest Report. W
trybie tym lista wyświetla dane dotyczących plików pogrupowane w kolumny. Na przykład, w
Eksploratorze Windows tryb Report powoduje użycie czterech kolumn reprezentujących nazwę pliku,
jego rozmiar oraz typ, a także datę ostatniej modyfikacji. Kategorie danych określone są w nagłówkach
kolumn.
Klasą MFC zawierającą mechanizmy obsługi list szczegółowych jest CListCtri. W tabeli 6.6
wymienione są funkcje składowe tejże klasy, którymi posługiwać się możemy w celu dodawania nowych
i usuwania elementów listy.
Tabela 6.6. Funkcje klasy CListCtri Nazwa
funkcji Opis
insertColumn Umieszcza nową kolumnę we wskazanej pozycji
DeleteColumn Usuwa kolumnę z listy
Insertitem Umieszcza na liście nową pozycję
Deleteltem Usuwa z listy istniejącą pozycję
DeleteAllItems Usuwa z listy wszystkie pozycje
SetltemText Wstawia nagłówek podelementu


144_____________________________________Poznaj Visual C++ 6 ,
Przykładowy program Lists wykorzystywać będzie listę szczegółową, pracującą właśnie w trybie Report.
Danymi wyświetlanymi w jej kolumnach będą: nazwa katalogu, liczba plików zawartych wewnątrz oraz całkowita
objętość plików. Pierwszą konieczną czynnością jest umieszczenie kolumn. Ponieważ kolumny nie ulegają
zmianom, możemy ' je dodać wewnątrz funkcji ininitDialogO. Aktualne dane dotyczące tych pozycji zostaną
uwidocznione na liście poprzez funkcję PopulateListCtrl (), jak zostało to opisane w poprzednim punkcie. Teraz
zajmiemy się implementacją tej funkcji, a jako typ zwracanej wartości obierzemy void.
i
Dopiszemy teraz fragment kodu umieszczony w liniach od 8 do 11 w listingu 6.6.
Listing 6.6. LST06_6.CPP - mixcjalizacja pola listy kolumn

^
1 BOOL CListsDlg::OnInitDialog()
2 {
3
4 ... l
5 // TODO: Inicjalizacja pola listy wyświetlającego katalog główny
7 PopulateCombo() ;
8 // ** Inicjalizacja kolumn listy szczegółowej
9 m_lcDirDetails.InsertColumn(0, "Directory", LVCFMT_LEFT, 70); O
10 m_lcDirDetails.InsertColumn(l, "Files", LVCFMT_RIGHT, 50); O
11 m_lcDirDetails.InsertColumn(2, "Size KB", LVCFMT_RIGHT, 60); O
12
13 return TRUE; // zwraca TRUE jeśli nie ustawisz focusu
// na kontrolce )
14 >
O Inicjalizacja listy szczegółowej, zorganizowanej w trzech kolumnach.
Pierwszy parametr funkcji insertColumn ojest numerem kolumny. Numeracja rozpoczyna się od zera.
Możemy określić położenie poziome kolumny. Do wyboru mamy trzy możliwości: LVCFMT_LEFT (po lewej),
LVCFMT_CENTER (na środku) oraz * LVCFMT_RIGHT (po prawej). Ostatnim parametrem tej funkcji jest
początkowa szerokość kolumn mierzona w pikselach. Wymiar ten może zostać zmieniony przez użytkownika, za
pomocą myszy podczas pracy programu. Dopiszemy teraz kod z listingu 6.7, by wypełnić listę szczegółową.
>


Używanie list 145 Listing 6.7. LST06_7.CPP - wypełnianie
listy szczegółowej
1 void CListsDlg::PopulateListControl()
2 {
3 // ** Usunięcie dotychczasowej zawartości listy
4 ni_lcDirDetails.DeleteAllItems();
5
6 POSITION pos;
7 // ** Iteracja katalogów wybranych Q II ** w polu listy
9 for(pos = m_strList.GetHeadPosition(); pos != NULL;)
10 (
11 int nitem;
12 HANDLE hFind;
13 WIN32_FIND_DATA dataFind;
14 BOOL bMoreFiles = TRUE;
15 CString str;
16 CString strFind;
17
18 str = m_strList.GetAt(pos);
19 // ** Dodaj wiersz do listy (kolumna 0)
20 nitem = m_lcDirDetails.Insertltem(0, str);
21
22 strFind = m_strMainDir + "\\" + str + "\\*.*";
23 hFind = FindFirstFile(strFind, &dataFind);
24
25 int nFileCount = 0;
26 double nFileSize = 0;
27
28 // ** Pobranie nazw wszystkich plików w katalogu
29 II ** liczby plików oraz całkowitej objętości
30 while(hFind != INVALID_HANDLE_VALUE && O bMoreFiles == TRUE)
31 (
32 if(dataFind.dwFileAttributes === FILE_ATTRIBUTE_ARCHIVE)
33 {
34 nFileCount++;
35 nFileSize += (dataFind.nFileSizeHigh * @ MAXDWORD)
36 + dataFind.nFileSizeLow;
37 }
38 bMoreFiles = FindNextFile(hFind, &dataFind) ;
39 }


146 Poznaj Visual C++ 6





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// ** Zakończenie obsługi plików
FindClose(hFind) ;
// ** Formatowanie informacji o liczbie plików II ** i
umieszczenie ich w kolumnie l str.Format("%ld",
nFileCount); m_lcDirDetails.Set!temText(nitem, l,
str);
// ** Formatowanie informacji o rozmiarach plików f l
** i umieszczenie ich w kolumnie 2 str.Format("%-1.2f",
nFileSize / 1024.0); O
m_lcDirDetails.Set!temText(nitem, 2, str);
m_strList.GetNext(pos) ;
}





O Iteracja plików ze wszystkich podkatalogów.
Inkrementacja liczby plików i ogólnej objętości.
Umieszczenie szczegółów w kolumnie podającej liczbę plików.
O Umieszczenie danych w kolumnie podającej objętość plików.
Funkcja DeleteAllltems () występująca w linii 4 usuwa całą dotychczasową zawartość listy, ale nie
usuwa kolumn. Pętla for rozpoczęta w linii 9 dokonuje iteracji poprzez zmienną m_strList, która
utworzona została w funkcji OnSelChangeSubDirs (). Każda pozycja typu cstring obecna na liście
reprezentuje wybrany katalog. W linii 20 nazwa katalogu zostaje przekazana funkcji lnsertltem() i
umieszczona w kolumnie 0. Funkcja ta zwraca wartość ostatnio dołączonej pozycji, poczynając od zera
oraz zapisuje ją w nitem. Ta wartość z kolei przekazywana jest funkcji SetltemText (), wywoływanej w
liniach 46 i 51, która umieszcza odpowiednie informacje w pozostałych dwóch kolumnach.
Dla przypomnienia szczegółów dotyczących funkcji FindFirstItemO oraz Find-Nextltem() możemy
cofnąć się do punktu mówiącego o wypełnianiu list drzewiastych w tym samym rozdziale.
Skompilujemy i uruchomimy zatem program Lists. Aby sprawdzić poprawność jego działania,
zmienimy wybór katalogów. Spróbujemy dokonać wyboru wielopozycyjnego w polu listy. Okno
programu powinno wyglądać podobnie do tego na rysunku 6.7.


Używanie list 147
g








"łain
Difectóły






C:WIMDOWS ^J|i,


.
.:::::.
...^vi^.
Files SubDitectories 'B^:,,,!'





-s

^.

IFORMS AJ.:;





; : AODLFNPR.REG "

.JHELP^^^^^^^^""'



(i,

: !. ACCSTAT.EXE ^

i^l^BBBBIHHr-1 ^





', i ASP12HLP.SYS ,:|i

^ MEDIA .:::



ł

: i AWEMAN.OLL -J

uB^lISHHHBBBHBHLiJ:



|J

i ;-AWEMAN32.DLL



B

: i- - ACCESSOR GRP Selected Directory Delails



li

; ; Aclive Setup Log.BAK Dfectoły Files SizeKB





, ' Ac>ive SeSup Log.tKt OPTIONS 12 163.31



l

IS-B

JA','A 1 0.17 ,



ii

B C

"" A IMAGE B 7.79 B





Ig D

^r COMMAND 33 1065.77 :







OK l








Rysunek 6.7. Ostateczny wygląd okna programu Lists
PATRZ TAKŻE
4 Więcej szczegółów na temat stylów list szczegółowych znajduje się w rozdziale 19.


Wyszukiwarka

Podobne podstrony:
06 Nowy Testament List do Rzymian
06 List III
Tech tech chem11[31] Z5 06 u
FAQ Komendy Broń (Nazwy używane w komendach) do OFP
show list
srodki ochrony 06[1]
06 (184)
06
06 (35)

więcej podobnych podstron