3 24 Kontrolka widoku drzewa i kontrolka widoku listy (2)


Rozdział 24.
Kontrolka widoku drzewa i kontrolka widoku listy


W tym rozdziale:

Podstawy zarzÄ…dzania kontrolkami CTreeCtrl
Edycja "na miejscu" etykietek kontrolki CTreeCtrl
Obsługa klawiszy Enter i Esc podczas edycji etykietek
Dodanie obsługi menu kontekstowego do kontrolki CTreeCtrl
Podstawy zarzÄ…dzania kontrolkami CListctrl
Klasa ClmageList
Dostęp do kontrolki nagłówka listy
Dynamiczna zmiana rodzaju widoku w kontrolce CListctrl


Gdy Windows 95 pojawiło się na rynku, zawierało kilka nowych standardowych kontrolek. Znajdowały się one w pliku COMCTL32.DLL i odgrywała znaczącą rolę w skierowanym ku dokumentom interfejsie, do którego dążyły wszystkie poprzednie wersje Windows. Do nowych kontrolek należą między innymi elementy zaprojektowane do łatwiejszego i bardziej wydajnego zarządzania listami danych. Jeśli kiedykolwiek używałeś Eksploratora Windows do przeglądania przestrzeni nazw swojego systemu (czyli plików, folderów i urządzeń składających się na system), widziałeś już przynajmniej dwie z tych kontrolek: kontrolkę widoku drzewa oraz kontrolkę widoku listy. Kontrolka widoku drzewa jest używana do wyświetlania list elementów zorganizowanych hierarchicznie, zaś kontrolka widoku listy umożliwia wyświetlanie list danych w czterech różnych trybach (zwanych widokami). Są to: widok dużych ikon, widok małych ikon, widok listy oraz widok raportu (szczegółów). Każdy z nich zostanie w tym rozdziale szczegółowo opisany.
Zarówno kontrolka widoku listy, jak i kontrolka widoku drzewa korzystają z dodatkowych standardowych kontrolek Windows w celu poprawienia swojego wyglądu i użyteczności. Na przykład, obie kontrolki korzystają ze wspólnej kontrolki nazywanej kontrolka listy obrazów. Ta kontrolka jest używana do przechowywania listy bitmap lub ikon. W dalszej
części rozdziału zobaczysz, w jaki sposób można jej użyć w kontrolkach widoku listy i drzewa do wizualnej prezentacji poszczególnych elementów danych. Oprócz kontrolki listy obrazów kontrolka widoku listy korzysta z jeszcze jednej standardowej kontrolki: kontrolki nagłówka listy. Kontrolka nagłówka to pojedynczy rząd nagłówków kolumn, używany przez kontrolkę listy do lepszego zorganizowania i wyświetlania danych zawartych na liście. W zaawansowanych aplikacjach, kontrolka nagłówka pozwala użytkownikowi aplikacji sortowanie danych w kontrolce widoku listy. W niektórych aplikacjach kontrolka nagłówka umożliwia nawet organizowanie kolumn na różne sposoby, przez ich przeciąganie i upuszczanie w odpowiednim miejscu.
Choć kontrolki widoku listy i kontrolki widoku drzewa mają całkiem odmienne możliwości, często są używane łącznie w celu zapewnienia dwóch różnych widoków danych aplikacji. Przykładem takiej aplikacji wykorzystującej siłę obu kontrolek przy wyświetlaniu tych samych danych w pojedynczym oknie, jest Eksplorator Windows (rysunek 24.1). Wkrótce okazało się, że tak wielu programistów chciało w tym naśladować Eksploratora Windows, że Microsoft zdecydował się uzupełnić AppWizarda w Visual C++ o możliwość tworzenia szkieletów aplikacji posiadających dokładnie ten sam interfejs. W związku z tym w tym rozdziale my także zajmiemy się kontrolkami widoku listy i drzewa, a także reprezentującymi je klasami MFC, CListCtrl oraz CTreeCtrl.
CTreeCtrl
Choć w MFC do reprezentacji kontrolki widoku listy jest używana klasa CTreeCtrl, jednak stanowi ona tylko bardzo niewielki narzut. W rzeczywistości, jeśli przejrzysz kod źródłowy MFC dla tej klasy (znajdujący się w pliku \vinctrl2.cpp), okaże się, że większość funkcji składowych klasy CTreeCtrl nie robi niczego więcej poza wypełnianiem struktur danych i wysyłaniem komunikatów do reprezentowanej kontrolki widoku drzewa. Tak więc, zanim przejdziemy do omawiania składowych klasy CTreeCtrl, konieczne będzie zrozumienie działania reprezentowanej przez tę klasę kontrolki.
Podstawy kontrolki widoku drzewa
Kontrolka widoku drzewa jest używana do wyświetlania danych w hierarchicznej formie. Każdy element może mieć swoją bitmapę (lub parę bitmap). Wiele aplikacji decyduje się na użycie dla każdego z elementów dwóch bitmap. Pierwsza z nich jest używana do wyświetlania elementu, gdy jest zaznaczony, zaś druga, gdy element nie jest zaznaczony. Typowe obrazki używane do prezentacji zaznaczonego i niezaznaczonego elementu zostały pokazane na rysunku 24.2.
Oprócz Eksploratora Windows taka hierarchiczna prezentacja danych występuje także w wielu innych aplikacjach, na przykład w Yisual Studio (w widoku projektu), w Outlook Express (foldery poczty i grup dyskusyjnych) czy w MSDN (grupy artykułów i książek). Choć w każdym z tych programów zastosowanie kontrolki widoku drzewa w aplikacji jest nieco inne, jednak we wszystkich przypadkach mamy do czynienia z pewnymi wspólnymi cechami.
Szczytowy element hierarchii kontrolki drzewa jest nazywany elementem głównym (ang. root element). Jest główny, ponieważ nie posiada elementów nadrzędnych (ang. parent item). Element nadrzędny to element zawierający inne elementy (elementy potomne, child items). Elementy potomne (jeśli został rozwinięty ich element nadrzędny) są wyświetlane zawsze jako przesunięte względem elementu nadrzędnego. O ile element nadrzędny może mieć dowolną ilość elementów potomnych, o tyle element potomny może mieć tylko jeden element nadrzędny. Przykład hierarchicznej struktury wyświetlonej w kontrolce widoku drzewa przedstawia rysunek 24.3.
Jak widać w hierarchii zespołów NBA z rysunku 24.3, dwa elementy bez elementów nadrzędnych (Eastern Conference oraz Western Conference) są elementami głównymi. Oprócz tego, powinieneś pamiętać, że ten sam element może być zarówno elementem nadrzędnym, jak i podrzędnym. Na przykład, element Midwest jest elementem podrzędnym elementu Western Conference, a oprócz tego jest elementem nadrzędnym dla elementów Houston Rockets, San Antonio Spurs i innych.
Z kontrolką widoku drzewa powiązane są liczne style. Na przykład do stworzenia rysunku 24.3 zostały włączone trzy style w celu pokazania powiązań pomiędzy elementami tworzącymi hierarchię. Każdy z tych stylów został włączony w edytorze zasobów, w oknie dialogowym właściwości kontrolki widoku drzewa. W opisie poniżej w nawiasach podaliśmy stałą znacznika stylu, której użyłbyś przy programowym określaniu stylu kontrolki. Poszczególne style zostaną opisane bardziej szczegółowo przy okazji omawiania pierwszego programu demonstrującego użycie kontrolki widoku drzewa.
Styl Has buttons (TVS_HASBUTTONS) - powoduje wyświetlenie przycisków plus (+) i minus (-) obok elementów nadrzędnych.
Styl Has lines (TVS_HASLINES) - powoduje rysowanie linii obrazujących hierarchię elementów.
Styl Lines at root (TVS_LINESATROOT) - powoduje użycie linii do połączenia głównych elementów w kontrolce widoku drzewa.
Klasa CTreeCtrl
Choć klasa CTreeCtrl jest uważana za bardzo cienką warstwę pośrednią dla kontrolki widoku drzewa, jednak jej użycie znacznie zmniejsza ilość koniecznej pracy związanej z oprogramowaniem tej kontrolki. Ta klasa po prostu ukrywa złożony sposób zarządzania kontrolką poprzez udostępnienie odpowiednich funkcji składowych. Na przykład, w celu zwykłego wstawienia elementu do kontrolki konieczne jest utworzenie i wypełnienie struktury TYINSERTSTRUCT, a następnie wysłanie do kontrolki komunikatu TVM_INSERTITEM. W aplikacji SDK taki kod wyglądałby następująco:
TYINSERTITEM tvis;
tvis.hParent = hParent;
tvis.hlnsertAfter = hlnsertAfter;
tvis.item.mask = nMask;
tvis.item.pszText = (LPTSTR) Ipszltem;
tvis.item.ilmage = nlmage;
tvis.item.iSelectedlmage = nSelectedlmage;
tvis.item.state = nState;
tvis.item.stateMask = nStateMask;
tvis.item.iParam = IParam;
HTREEITEM hNewItem =
::SendMessage(m hWnd, TYM INSERTITEM, O, (LPARAM)&tvis);
Dla odróżnienia, przy użyciu jednej ze składowych klasy CTreeCtri, ten kod wyglądały tak:
treeControl.Insertltem(_T("Mój element"));
Tak więc, choć klasa CTreeCtri raczej nie wzbogaca możliwości kontrolki, jednak zdecydowanie ułatwia jej programowanie.
Tworzenie kontrolek CTreeCtri
Choć kontrolkę CTreeCtri można utworzyć dynamicznie za pomocą jej składowej funkcji create () Jednak najczęściej będziesz j ą tworzył, wykorzystując edytor zasobów. Aby w prosty sposób utworzyć kontrolkę CTreeCtri, wykonaj poniższe kroki:
1. W edytorze dialogów przeciągnij ikonkę kontrolki widoku drzewa z paska narzędzi Controls do tworzonego okna dialogowego.
2. W oknie ClassWizarda, na zakładce Member Variables, kliknij przycisk Add Variable.
3. Wpisz nazwę zmiennej składowej (na przykład m_treeControl).
4. Z rozwijanej listy Category wybierz pozycjÄ™ Control.
5. Z rozwijanej listy Variable type wybierz pozycjÄ™ CTreeCtri.
Teraz, gdy wyświetlisz okno dialogowe, mechanizm DDX (opisywany w rozdziale 13.) podmieni kontrolkę widoku drzewa kontrolka MFC CTreeCtri, którą dodałeś do klasy dialogu. To oznacza, że wszelkie odwołanie do funkcji składowych klasy CTreeCtri spowodują wysłanie komunikatów do rzeczywistej kontrolki widoku drzewa.
Wstawianie elementów do kontrolki CTreeCtrl
Jak już wiesz, do wstawiania elementów do kontrolki służy funkcja CTreeCtri: : Insertltem o . Jednak w zależności od potrzeb aplikacji możesz użyć jednej z kilku przeciążonych wersji tej funkcji.
Jednym z elementów wspólnych dla wszystkich wersji funkcji Insertltem() jest zwracana wartość. Tą wartością jest HTREEITEM, będąca uchwytem elementu drzewa i reprezentująca element wstawiony do kontrolki. Gdy element zostanie wstawiony do kontrolki, odwołanie do niego odbywa się zawsze poprzez ten uchwyt. Na przykład, niektóre wersje funkcji Insertltem o wymagają podania argumentu typu HTREEITEM o nazwie hParent. To oznacza, że wstawiany element będzie elementem potomnym innego elementu już znajdującego się w drzewie. Argument hParent musi być wtedy uchwytem HTREEITEM reprezentującym element nadrzędny dla wstawianego elementu.
HTREEITEM Insertltem(LPTYINSERTSTRUCT IpInsertStruct);
Ta funkcja jako jedyny parametr posiada wskaźnik do struktury TYINSERTSTRUCT. Ta wersja funkcji jest wywoływana zwykle wtedy, gdy aplikacja musi wypełnić większość składowych struktury TYINSERTSTRUCT.
HTREEITEM InsertItem(UINT nMask, LPCTSTR Ipszltem, int nlmage, int nSelectedlmage, UINT nState, UINT nStateMask, LPARAM 1Param, HTREEITEM hParent, HTREEITEM hlnsertAfter);
Podobnie jak w poprzedniej wersji, w tej funkcji aplikacja może określić każdą składową struktury TYINSERTITEM. Jedyna różnica polega na tym, że przed wywołaniem tej wersji nie trzeba alokować pamięci na strukturę i wypełniać jej składowych, lecz można przekazać je jako argumenty funkcji.
HTREEITEM InsertItem(LPCTSTR 1pszltem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hlnsertAfter = TVI_LAST);
Ta wersja funkcji jest już dużo prostsza. Korzystając z niej, aplikacja musi jedynie podać tekst, jaki ma znaleźć się w polu elementu drzewa. Jeśli nie podasz uchwytu elementu nadrzędnego, wstawiony element stanie się jednym z elementów głównych. Jednak w tej funkcji nie możesz określać obrazków powiązanych z elementami. Właśnie za pomocą tej wersji funkcji stworzyliśmy elementy drzewa pokazanego na rysunku 24.3.
HTREEITEM Insertltem(LPCTSTR 1pszItem, int nImage, int nSelectedlmage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hlnsertAfter = TVI_LAST);
Tej wersji funkcji Insertltem() prawdopodobnie będziesz używał najczęściej, gdyż umożliwia określenie tekstu elementu, elementu nadrzędnego, miejsca w drzewie, w którym element ma się znaleźć, oraz obrazków powiązanych z elementem. Argumenty nlmage oraz nSelectedlmage są indeksami obrazków. Tej wersji funkcji użyjemy w demonstracyjnym programie TreeCtrlDemo, który stworzymy w dalszej części rozdziału.
Edycja etykiet
Korzystając z Eksploratora Windows z pewnością miałeś okazję edytować etykietkę elementu drzewa, klikając ją po jej zaznaczeniu. Włączenie tej możliwości pozwoli użytkownikom aplikacji na zmianę tekstu elementu bez konieczności przywoływania osobnego okna dialogowego, zawierającego tylko jedno pole przeznaczone do wpisania treści etykietki. Przykład bezpośredniej edycji elementu drzewa pokazuje rysunek 24.4.
Włączenie możliwości edycji tekstu elementu wymaga trzech prostych kroków:
1. Ustaw styl TVS_EDITLABELS kontrolki widokudrzewa.
2. Obsłuż komunikat powiadamiający TVN_BEGINLABELEDIT.
3. Obsłuż komunikat powiadamiający TVN_ENDLABELEDIT.
Styl TVS_EDITLABELS można ustawić na dwa sposoby. Pierwszym z nich jest zmodyfikowanie stylu kontrolki widoku w edytorze dialogów. W tym celu po prostu wyświetl arkusz właściwości kontrolki, kliknij zakładkę Styles i włącz opcję Edit labels. Drugi sposób polega na użyciu funkcji Win32 SDK, SetwindowLong (). Oto przykład:
// Pobranie bieżącego stylu kontrolki
long IStyle = ::GetWindowLong(m_treeControl.GetSafeHwnd(),
GWL_STYLE);
// Ustawienie bitu stylu IStyle |= TVS EDITLABELS;
// Aktualizacja stylu kontrolki
::SetwindowLong(m treeControl.GetSafeHwndi
GWL STYLE,1Style)
Gdy już ustawisz styl TVS_EDITLABELS, powinieneś obsłużyć komunikat powiadamiający TVN_BEGINLABELEDIT. Obsługa tego komunikatu nie jest obowiązkowa. Jednak wiele aplikacji decyduje się na to, na przykład w celu ograniczenia długości tekstu, jaki może być wpisany do elementu kontrolki. Dodając funkcję obsługi tego komunikatu, możesz użyć ClassWizarda. Oto przykład takiej funkcji, w której ograniczamy długość wpisywanego tekstu do piętnastu znaków:
void CMyTreeCtrl::OnBeginLabelEdit(NMHDR* pNMHDR,
LRESULT* pResult)
{
TV_DISPINFO* pTVDisp!nfo = (TV_DISPINFO*)pNMHDR; *pResult = 1;
CEdit* pEdit = GetEditControl(); ASSERT(pEdit); if(pEdit)
{
pEdit->LimitText(15); *pResult = 0;
}
}
Ten fragment kodu nie jest zbyt skomplikowany, jednak może wymagać kilku wyjaśnień. Po pierwsze, wszystkie komunikaty powiadamiające zwracają typ void. W związku z tym, w celu wskazania sukcesu lub porażki funkcja musi odwołać się do wskaźnika LRESULT (parametru pResult) i ustawić wskazywaną wartość na l dla porażki lub na O dla sukcesu. Właśnie dlatego wartość *pResuit jest ustawiana na zero tylko wtedy, gdy powiedzie się ograniczenie tekstu w polu edycji kontrolki. Po drugie należy wyjaśnić wywołanie funkcji składowej GetEditControl () klasy CTreeCtrl. Aby umożliwić użytkownikowi edycję tekstu elementu, kontrolka widoku drzewa dynamicznie tworzy i wyświetla
kontrolkę pola edycji. Funkcja GetEditControl () służy właśnie do odwołania się do obiektu CEdit reprezentującego tę kontrolkę pola edycji. Dzięki temu w celu wykonania ograniczenia długości wpisywanego tekstu można użyć funkcji składowych klasy CEdit.
O ile obsługa komunikatu TVN_BEGINLABELEDIT nie jest konieczna, o tyle obsługa komunikatu TVN_ENDLABELEDIT jest obowiązkowa. Jeśli nie obsłużysz tego komunikatu, użytkownik będzie co prawda mógł edytować etykietkę, jednak po zakończeniu edycji zostanie przywrócona jej poprzednia wartość. W funkcji obsługi tego komunikatu możesz umieścić kod sprawdzający poprawność wprowadzonego tekstu. Na przykład, jeśli w swojej aplikacji nie zezwalasz na występowanie elementów o takich samych etykietach, musisz to sprawdzać właśnie w funkcji obsługi komunikatu TVN_ENDLABELEDIT. Listing 24.1 zawiera kod funkcji obsługi tego komunikatu, sprawdzającej, czy użytkownik nie wprowadził dwóch takich samych etykiet.
Listing 24.1. Sprawdzanie poprawności tekstu -wprowadzonego do elementu kontrolki widoku drzewa
void CMyTreeCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{ TV_DISPINFO* pWDispInfo = (TV_DISPINFO*)pNMHDR; BOOL bFoundDuplicate = FALSE;
if(pTVDisp!nfo->item.pszText
&& strlen(pTVDispInfo->item.pszText))
{
HTREEITEM hParent =
GetParentItem(pTVDispInfo->item.hItem);
HTREEITEM hChild =
GetChildltem(hParent ? hParent l TVI_ROOT);
while( NULL != hChild && !bFoundDuplicate)
{ if(pTVDisp!nfo->item.hitem != hChild)
{
CString strText = GetItemText(hChild); if(0 ==
strText.CompareNoCase(pTVDisp!nfo->item.pszText) )
{
bFoundDuplicate = TRUE;
}
else {
hChild = GetNextSiblingItem(hChild);
}
else {
hChild = GetNextSiblingItem(hChild);
}
}
}
^pResult = (bFoundDuplicate ? 0 : l) ;
}
Jeśli spróbowałeś wykorzystać poprzedni fragment kodu, prawdopodobnie odkryłeś, że jedynym sposobem zakończenia edycji tekstu było albo kliknięcie w innym miejscu okna, albo przełączenie się do innej aplikacji. Dzieje się tak, ponieważ MFC zostało zaprojektowane w taki sposób, że przez wirtualną funkcję PreTranslateMessage () okno nadrzędne kontrolki widoku drzewa otrzymuje komunikaty jako pierwsze. Jeśli nadrzędnym oknem kontrolki jest obiekt CDialog lub CFormView, sam obsługuje klawisze Esc i Enter i w związku z tym nigdy nie trafiają one do kontrolki widoku drzewa. Tak więc, aby móc przetwarzać klawisze Esc i Enter, musisz przesłonić funkcję PreTranslateMessage ().
Obsługa klawiszy Esc i Enter podczas edycji elementów kontrolki widoku drzewa
W poniższych krokach zakładamy, że stworzyłeś dialog zawierający kontrolkę widoku drzewa oraz że tę kontrolkę reprezentuje zmienna m_tree klasy CTreeCtri, powiązana z kontrolka poprzez mechanizm DDX.
1. Używając ClassWizarda stwórz nową klasę wyprowadzoną z klasy CTreeCtri (na przykład klasę CMyTreeCtrl).
2. W pliku nagłówkowym dialogu, przed deklaracją klasy dialogu, umieść dyrektywę #include włączającą deklarację nowej klasy.
3. Zmień typ zmiennej m_tree z CTreeCtri na CMyTreeCtrl.
4. Używając ClassWizarda, przesłoń wirtualną funkcję składową CMyTreeCtrl: : PreTranslateMessage () własną funkcją:
BOOL CMyTreeCtrl::PreTranslateMessage(MSG* pMsg)
{ BOOL bHandledMsg = FALSE; switch (pMsg->message)
{ case WM_KEYDOWN:
{ switch (pMsg->wParam)
{
case VK_ESCAPE: case VK_RETURN: if (::GetKeyState(VK CONTROL) & 0x8000)
{
break;
}
if (GetEditControl() ) {
::TranslateMessage(pMsg);
::DispatchMessage(pMsg);
bHandledMsg = TRUE;
}
break;
default: break; } // switch (pMsg->wParam) } // WM_KEYDOWN break;
default: break; } // switch (pMsg->message)
// kontynuuj normalne tłumaczenie i rozprowadzanie return (bHandledMsg ? TRUE : CTreeCtrl::PreTranslateMessage(pMsg));
}
Menu kontekstowe
Ostatnią rzeczą, jaką omówimy przed przejściem do pierwszego demonstracyjnego programu w tym rozdziale, będzie menu kontekstowe oraz sposób zaimplementowania go dla kontrolki widoku drzewa i jej elementów. Menu kontekstowe pojawiły się wraz z wprowadzeniem Windows 95 i ich interfejsu zorientowanego na dokumenty. Przykład menu kontekstowego możesz ujrzeć po kliknięciu prawym przyciskiem myszy na pliku lub folderze w Eksploratorze Windows.
Menu kontekstowe są dość popularne, gdyż pomagają w uproszczeniu interfejsu użytkownika. Przed pojawieniem się menu kontekstowych, w przypadku gdy aplikacja wyświetlała wiele różnych rodzajów elementów (na przykład klientów, zamówień, towarów itd.), konieczne było posiadanie odpowiedniego polecenia menu dla każdej z czynności, jaka mogła zostać wykonana dla każdego z elementów. W zależności od rodzaju elementu aktualnie wybranego przez użytkownika włączano lub wyłączano odpowiednie pozycje menu. Jednak w przypadku większych aplikacji powodowało to konieczność posiadania ogromnej ilości różnych menu, przez które użytkownik musiał się żmudnie przedzierać.
W wyniku prób rozwiązania tego problemu powstała idea menu kontekstowych. Menu kontekstowe pozwalają na zdefiniowanie menu zawierającego jedynie te polecenia, które odnoszą się bezpośrednio do danego elementu. Dzięki temu, w głównym menu mogą znaleźć się tylko te polecenia, które odnoszą się globalnie do całej aplikacji, podczas gdy operacje specyficzne dla danego elementu mogą być wybrane poprzez menu kontekstowe.
Menu kontekstowe stały się tak popularne, że obecnie w zdziwienie może wprawić aplikacja, która ich nie posiada. Użycie tych menu w aplikacji stało się tak oczywiste, że nowoczesne klawiatury posiadają nawet specjalny klawisz imitujący kliknięcie prawym przyciskiem myszy (wysłanie komunikatu WM_RBUTTONDOWN) w bieżącym oknie.
Przykładem aplikacji używającej menu kontekstowych dla elementów w kontrolce widoku drzewa jest Outlook Express. Ta popularna aplikacja pocztowa Microsoftu posiada kontrolkę widoku drzewa zawierającą wszystkie foldery poczty i grup dyskusyjnych używane przez użytkownika. Kliknięcie prawym przyciskiem myszy folderu Skrzynka odbiorcza powoduje wyświetlenie opcji i poleceń odnoszących się do tego folderu, innych niż opcje i polecenia odnoszące się na przykład do Skrzynki nadawczej.
Dodanie prostego menu kontekstowego wymaga jedynie dwóch kroków. Pierwszym z nich jest utworzenie zasobu menu zawierającego polecenia, jakie mają się pojawić w menu. To menu tworzy się dokładnie tak samo jak inne. Na przykład, jeśli chcesz stworzyć menu kontekstowe dla klienta w aplikacji księgowej, możesz zastosować polecenia podobne do pokazanych na rysunku 24.5.
Drugim krokiem w implementacji menu kontekstowego jest stworzenie w klasie wyprowadzonej z cireectri funkcji obsługi komunikatu WM_RBUTTONDOWN. Przykład kodu z listingu 24.2 pokazuje, w jaki sposób można zaimplementować wyświetlenie menu kontekstowego po kliknięciu prawym przyciskiem myszy elementu kontrolki widoku drzewa.
Listing 24.2. Wyświetlanie menu kontekstowego dla kontrolki widoku drzewa___________
void CMyTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) {
// Ustawienie ogniska wprowadzania na
// kontrolkÄ™ widoku drzewa
SetFocus();
// Odwzorowanie punktu przekazanego do funkcji // ze współrzędnych klienta na współrzędne // ekranu. ClientToScreen(spoint) ;
// Pobranie aktualnie zaznaczonego elementu. HTREEITEM hCurrSel = GetSelectedltem(};
// Sprawdzenie, na którym elemencie nastąpiło
// kliknięcie
CPoint pt(O, 0);
: .-GetCursorPos (&pt) ;
ScreenToClient (&pt);
HTREEITEM hNewSel = HitTest(pt, SnFlags);
// Przeniesienie zaznaczenia na element, // na którym nastąpiło kliknięcie prawym // przyciskiem myszy. if (NULL == hNewSel)
{
Selectltem(NULL);
}
else if (hCurrSel != hNewSel)
{
Selectltem(hNewSel); SetFocus();
}
// Załadowanie menu kontekstowego
CMenu Menu;
if (Menu.LoadMenu(IDM_CONTEXT_MENU)}
{
CMenu* pSubMenu = Menu.GetSubMenu(0);
if (pSubMenu!=NULL)
{
// Wyświetlenie menu kontekstowego pSubMenu->TrackPopupMenu( TPM_LEFTALIGN ! TPM_RIGHTBUTTON, point.x, point.y, this);
}
}
}
Kod z listingu 24.2 jest dość prosty i wyświetla to samo menu kontekstowe dla wszystkich elementów w kontrolce widoku drzewa. Jednak w większości aplikacji w takiej kontrolce wystąpią różne elementy, więc odpowiednie będzie zastosowanie różnych menu kontekstowych.
Program demonstracyjny CTreeCtrIDemo
Pierwszy demonstracyjny program w tym rozdziale będzie ilustrował zagadnienia, które przed chwilą omawialiśmy.
Kod źródłowy tego programu znajduje się na dołączonej do książki płytce CD-ROM, w kartotece Rozdz24\TreeeCtrlDemo. Aby zacząć go budować, za pomocą AppWizarda stwórz opartą na oknie dialogowym aplikację TreeCtrlDemo.
Tworzenie okna dialogowego
Gdy już stworzysz projekt, zmień okno dialogowe tak, by wyglądało jak na rysunku 24.6.
Gdy dodasz kontrolki, sprawdź, czy kontrolka widoku drzewa ma włączone następujące style:
Has buttons
Has lines
Lines at root
Editlabels
Za pomocą ClassWizarda stwórz zmienną składową m_tree klasy CTreeCtrl.
Tworzenie klasy wyprowadzonej z klasy CTreeCtrl
Ponieważ użytkownik będzie klikał prawym przyciskiem myszy kontrolkę, z punktu widzenia programowania obiektowego lepiej będzie, gdy komunikat WM_RBUTTONDOWN zostanie obsłużony w klasie kontrolki, a nie w klasie okna dialogowego. Tak więc, za pomocą ClassWizarda utwórz nową klasę CMyTreectrl, wyprowadzoną z klasy CTreeCtrl.
Gdy ClassWizard stworzy plik nagłówka oraz plik implementacji dla klasy CMyTreectrl, umieść dyrektywę #include w pliku nagłówkowym klasy okna dialogowego (TreeCtrl-DemoDlg.h), tuż przed deklaracją klasy CTreeCtrlDemoDlg.
#include "MyTreeCtrl.h"
Następnie zmień typ zmiennej składowej m_tree z klasy CTreeCtrl na CMyTreectrl, tak aby móc zacząć obsługiwać komunikaty w tej klasie.
Dodanie drugiego dialogu w celu pobierania tekstu elementu
Ponieważ nasz program będzie umożliwiał wpisywanie tekstu, jaki ma się pojawić we wstawianym elemencie, potrzebujemy kolejnego okna dialogowego. Stwórz proste okno dialogowe (IDD_ADD_ITEM) zawierające zwykłe pole edycji dla tekstu elementu. Gdy dodasz kontrolkę pola edycji, za pomocą ClassWizarda stwórz klasę dla nowego dialogu i nazwij ją CAdditemDlg.
Gdy ClassWizard stworzy pliki dla okna dialogowego, stwórz dla pola edycji zmienną składową m_stritem klasy cstring oraz dodaj funkcję obsługi onOK(), zawierającą kod przedstawiony poniżej. Ta funkcja obsługi będzie sprawdzać, czy wpisany tekst jest poprawny.
void CAdditemDlg::OnOK() {
UpdateData(TRUE);
if (l > m_strItem.GetLength())
{
AfxMessageBox(_T("Przykro mi, ale musisz wpisać poprawny napis."));
}
else {
CDialog::OnOK();
}
}
Dodawanie menu kontekstowego
Gdy masz już klasę wyprowadzoną z klasy CTreeCtrl, dodajmy jeszcze zasób menu oraz funkcję obsługi komunikatu WM_RBUTTONDOWN, wyświetlający to menu jako menu kontekstowe dla elementów kontrolki. Zostanie dodane proste menu umożliwiające użytkownikowi wstawianie nowych elementów do kontrolki. Po pierwsze, stwórz zasób menu o identyfikatorze IDM_CONTEXT_MENU, a następnie dodaj do niego polecenie &Wstaw. Gdy stworzysz zasób menu, za pomocą ClassWizarda dodaj do klasy CMyTre-ectri funkcję obsługi komunikatu WM_RBUTTONDOWN, po czym zmodyfikuj ją zgodnie z listingiem 24.3.
Listing 24.3. Implementacja funkcji obsługi WM_RBUTTONDOWN_______________
void CMyTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
// ustawienie ogniska wprowadzania na // kontrolkÄ™ widoku drzewa
SetFocus();
// Odwzorowanie punktu przekazanego do funkcji // ze współrzędnych klienta na współrzędne // ekranu. ClientToScreen(&point);
// Pobranie aktualnie zaznaczonego elementu. HTREEITEM hCurrSel = GetSelectedltem();
// Sprawdzenie, na którym elemencie nastąpiło
// kliknięcie
CPoint pt(O, 0);
::GetCursorPos(&pt);
ScreenToClient (&pt);
HTREEITEM hNewSel = HitTest(pt, SnFlags);
// Przeniesienie zaznaczenia na element,
// na którym nastąpiło kliknięcie prawym
// przyciskiem myszy,
if (NULL == hNewSel)
{
Selectltem(NULL); } else if (hCurrSel != hNewSel)
{
Selectltem(hNewSel); SetFocus();
}
// Załadowanie menu kontekstowego
CMenu Menu;
if (Menu.LoadMenu(IDM_CONTEXT_MENU))
{
CMenu* pSubMenu = Menu.GetSubMenu(0);
if (pSubMenu!=NULL)
{
// Wyświetlenie menu kontekstowego pSubMenu->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
}
}
}
W tym momencie kliknięcie prawym przyciskiem myszy dowolnego elementu kontrolki widoku drzewa spowoduje wyświetlenie menu IDM_CONTEXT_MENU. Musisz więc dodać do klasy CMyTreectrl kod, który sprawi, że po wybraniu polecenia z tego menu coś się stanie. W tym celu za pomocą ClassWizarda dodaj do klasy CMyTreectrl funkcję obsługi dla polecenia IDD_CONTEXTMENU_ADD, po czym zmodyfikuj ją zgodnie z kodem przedstawionym poniżej. Zwróć uwagę, że jako element nadrzędny nowo tworzonego elementu został użyty uchwyt HTREEITEM zaznaczonego elementu. W ten sposób nowy wstawiany element jest zawsze elementem potomnym elementu zaznaczonego przez użytkownika. Wywołanie funkcji selectitemO zapewnia, że nowo utworzony element nadrzędny zostanie rozwinięty i że będzie widoczny jego nowy potomny element.
void CMyTreeCtrl::OnContextmenuAdd() {
HTREEITEM hitemParent = GetSelectedltem();
CAddltemDlg dlg;
if (IDOK == dlg.DoModal())
{
HTREEITEM hitem = Insertltem(dlg.m_strltem, hitemParent);
Selectltem(hitem);
}
}
Unikanie powielonych równorzędnych elementów
Gdy użytkownik może już wstawiać elementy, musimy jeszcze zapewnić, że nie wstawi przez przypadek takich samych elementów na tym samym poziomie. W tym celu następująco zmodyfikuj funkcję OnContextmenuAdd ():
void CMyTreeCtrl::OnContextmenuAdd()
{
HTREEITEM hitemParent = GetSelectedltemf);
CAddltemDlg dlg;
if (IDOK == dlg.DoModal())
{
if (!DoesItemExist(hitemParent, dlg.m_strltem)) {
HTREEITEM hitem = Insertltem(dlg.mjstrltem, hitemParent) Selectltem(hitem);
}
}
}
Następnie dodaj funkcję DoesltemExist (), pokazaną na listingu 24.4. Ta funkcja po prostu używa funkcji składowych GetChilditemO oraz GetNextSiblingitem() klasy CTreeCtrl, przechodząc przez wszystkie równorzędne elementy i sprawdzając, czy nie wystąpiło powielenie tekstu elementu. Zwróć uwagę, że do odczytania tekstu elementu identyfikowanego przez uchwyt HTREEITEM została użyta funkcja GetitemText ().
Listing 24.4. Funkcja DoesltemExist()_________________________________
BOOL CMyTreeCtrl::DoesItemExist(HTREEITEM hitemParent,
CString consts strltem)
{
BOOL bDoes!temExist = FALSE; ASSERT(strltem.GetLength()) ;
HTREEITEM hChild =
GetChildltem(hitemParent ? hitemParent : TVI_ROOT);
while (NULL != hChild && !bDoes!temExist)
{
CString strText = GetItemText(hChild); if (O == strText.CompareNoCase(strltem))
{
bDoes!temExist = TRUE;
}
else {
hChild = GetNextSiblingItem(hChild);
}
}
return bDoes!temExist;
}
Dodanie możliwości edycji etykiet elementów
Gdy użytkownik może dodawać elementy, zaś powtarzane napisy nie są dopuszczane, dodajmy jeszcze kod potrzebny do edycji etykiet elementów już istniejących w kontrol-ce widoku drzewa. Jak już wspominaliśmy wcześniej, nie jest to trudne, o ile wiesz, które komunikaty powiadamiające należy obsłużyć. W tym momencie dodaj funkcję obsługi komunikatu TVN_ENDLABELEDIT sprawdzającą, czy nie nastąpiło powielenie już istniejącego tekstu elementu. Gdy skończysz, funkcja obsługi powinna wyglądać tak jak na listingu 24.5.
Listing 24.5. Funkcja obsługi komunikatu powiadamiającego TVN_ENDLABELEDIT_____
void CMyTreeCtrl::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{ TV_DISPINFO* pTYDispInfo = (TV_DISPINFO*)pNMHDR; BOOL bValidltem = FALSE;
CString strltem = pTVDispInfo->item.pszText; if (O < strltem.GetLength())
{
HTREEITEM hParent = GetParentltem(pTYDispInfo->item.hitem); CString strltem = pTYDispInfo->item.pszText;
bValidltem = !DoesItemExist(hParent, strltem);
} -^pResult = bValidltem;
}
Po zbudowaniu i uruchomieniu demonstracyjnego programu otrzymasz prostą kontrolkę widoku drzewa umożliwiającą wyświetlanie menu kontekstowych, edycję etykiet elementów oraz wstawianie elementów (przy zachowaniu warunku, że takie same elementy nie będą wstawione).
CListCtrl
Klasa CListctrl reprezentuje funkcje kontrolki widoku listy. Podobnie jak klasa CTreeCtri, klasa CListctrl pełni rolę pośrednika pomiędzy aplikacją a standardową kontrolka widoku listy w Windows. Tak więc, zanim przejdziemy do omawiania klasy CListctrl, musimy zrozumieć działanie samej kontrolki widoku listy.
Podstawy kontrolki widoku listy
Kontrolka widoku listy jest podobna do kontrolki listy, gdyż jest używana do wyświetlania grup podobnych elementów. Jeśli jednak chodzi o funkcjonalność, na tym podobieństwo się kończy. Kontrolka widoku listy może na przykład wyświetlić rząd nagłówków kolumn listy, czego nie potrafi zwykła kontrolka listy. W rzeczywistości, wiersz nagłówków kolumn w kontrolce widoku listy sam jest kolejną standardową kontrolka Windows, zwaną kontrolka nagłówka. Ta przydatna kontrolka jest wykorzystywana zwykle w celu umożliwienia użytkownikowi sortowania zawartości listy według określonej kolumny. Dzięki kontrolce nagłówka kontrolki widoku listy doskonale nadają się do wyświetlania wielu kolumn danych. Oprócz tego, kontrolki widoku listy umożliwiają wyświetlanie danych na kilka różnych sposób: w trybie Dużych ikon, Małych ikon, Listy oraz Szczegółów. W trybie Szczegółów, zwanym także trybem raportu (rysunek 24.7), jest wyświetlana szczegółowa informacja o każdym z elementów. Stanowi to przeciwieństwo do trzech pozostałych trybów, w których nie są widoczne szczegóły dotyczące elementów.
Klasa CListCtrl
Choć klasa CListCtrl jest uważana za bardzo cienką warstwę pośrednią dla kontrolki widoku listy, jednak jej użycie znacznie zmniejsza ilość koniecznej pracy związanej z oprogramowaniem tej kontrolki. Ta klasa po prostu ukrywa złożony sposób zarządzania kontrolką poprzez udostępnienie odpowiednich funkcji składowych. Na przykład, w celu zwykłego wstawienia elementu do listy konieczne jest utworzenie i wypełnienie struktury LV_ITEM, a następnie wysłanie do kontrolki komunikatu LVM_INSERTITEM. W aplikacji SDK taki kod wyglądałby następująco:
LV_ITEM item;
item.mask = nMask;
item.iltem = nitem;
item.iSubltem = 0;
item.pszText = (LPTSTR) Ipszltem;
item.state = nState;
item.stateMask = nStateMask;
item.ilmage =nImage;
item.lParam = 1Param;
int iIndex =::SendMessage(m_hWnd, LVM_INSERTITEM, O, (LPARAM)sitem);
Dla odróżnienia, przy użyciu jednej ze składowych klasy CListCtrl, ten kod wyglądałby tak:
listControl.Insertltem(_T("Mój element"));
Tak więc, choć klasa CListCtrl raczej nie wzbogaca możliwości kontrolki, jednak zdecydowanie ułatwia jej programowanie.
Tworzenie kontrolek CListCtrl
Choć kontrolkę CListCtrl można utworzyć dynamicznie za pomocą jej składowej funkcji create (), jednak najczęściej będziesz ją tworzył wykorzystując edytor zasobów. Aby w prosty sposób utworzyć kontrolkę CListCtrl, wykonaj poniższe kroki:
RozdziaÅ‚ 24. • Kontrolka widoku drzewa i kontrolka widoku listy
677
1. W edytorze dialogów przeciągnij ikonkę kontrolki widoku listy z paska narzędzi Controls do tworzonego okna dialogowego.
2. Ustaw styl View na żądany rodzaj widoku (Icon - duże ikony, Small icon -małe ikony, List - lista, Report - raport). Możesz także ustawić styl programowo, ale zajmiemy się tym dopiero za moment.
3. W oknie ClassWizarda, na zakładce Member Variables, kliknij przyciskAdd
Variable.
4. Wpisz nazwę zmiennej składowej (na przykład m_listcontrol).
5. Z rozwijanej listy Category wybierz pozycjÄ™ Control.
6. Z rozwijanej listy Variable type wybierz pozycjęCListCtrl.
Teraz, gdy wyświetlisz okno dialogowe, mechanizm DDX (opisywany w rozdziale 13.) podmieni kontrolkę widoku listy kontrolka MFC CListCtrl, którą dodałeś do klasy dialogu. To oznacza, że wszelkie odwołanie do funkcji składowych klasy CListCtrl spowodują wysłanie komunikatów do rzeczywistej kontrolki widoku listy.
Ustawianie listy obrazków dla kontrolki widoku listy
Jeśli chcesz, by elementy na liście posiadały obrazki, musisz stworzyć i powiązać z listą kontrolkę listy obrazków.
Tworzenie obiektu ClmageList i powiÄ…zanie go z obiektem CListCtrl
Aby stworzyć obiekt ClmageList i powiązać go z obiektem CListCtrl, wykonaj poniższe kroki:
1. Stwórz dwa zasoby bitmap. Te bitmapy będą skonstruowane tak, jak zasoby bitmap dla paska narzędzi, czyli będą zawierały szereg obrazków, do których będziemy odwoływać się poprzez ich indeks. Jeden z zasobów bitmapy będzie stosowany w widoku dużych ikon, zaś drugi z zasobów - w widoku małych ikon.
2. Zadeklaruj w klasie dialogu dwie zmienne składowe typu ClmageList. Także w tym przypadku jedna z nich będzie dla widoku dużych ikon, a jedna dla widoku małych ikon.
3. Po zainicjowaniu kontrolki widoku listy (zwykle w funkcji Oninitoialog()) wywołaj funkcję składową ClmageList: :Create() dla obu obiektów kontrolek list obrazków. Wywołując te funkcje Create {), podaj po prostu odpowiedni uchwyt zasobu bitmapy oraz rozmiary obrazków w bitmapie.
4. W celu powiązania obiektów list obrazków z kontrolka widoku listy, wywołaj funkcję składową CListCtrl: :SetimageList (). Pierwszy argument tej funkcji umożliwia określenie listy obrazków, zaś drugi argument wskazuje, która lista obrazków jest ustawiana (LVSIL_SMALL lub LVSIL_NORMAL).
Poniższy fragment kodu zakłada, że utworzyłeś wcześniej dwa zasoby bitmap o nazwach IDB_LARGE_IMAGES oraz iDB_SMALL_iMAGES. Zakłada także, że każdy obrazek jest szeroki na 17 pikseli. Oczywiście, w "prawdziwej" aplikacji obrazki w bitmapie IDB_SMALL_IMAGES byłyby mniejsze niż w bitmapie IDB_LARGE_IMAGES. Mając na uwadze te założenia, oto przykład, jak można utworzyć i powiązać obiekty list obrazków z kontrolką widoku listy:
// lista obrazków dla widoku Duże ikony m_imageListLarge!cons.Create(IDB_LARGE_IMAGES, 17, l, RGB(255,255,255)); m_listCtrl.SetlmageList(&m_imageListLargeIcons, LVSIL_NORMAL);
// lista obrazków dla widoku Małe ikony m_imageListSmallIcons.Create(IDB_SMALL_IMAGES, 17, l, RGB(255,255,255)); m_listCtrl.SetlmageList(&m_imageListSmallIcons, LVSIL_SMALL);
Ustawienie i zmiana widoku
Istnieją trzy różne sposoby ustawienia widoku w zależności od potrzeb aplikacji. Jeśli kontrolką widoku listy ma zawsze pokazywać ten sam widok, styl widoku można ustawić w edytorze dialogów, na arkuszu właściwości kontrolki widoku listy (opcja View). Jeśli jednak widok kontrolki ma być zmieniany w czasie działania programu, możesz użyć funkcji CWnd: :ModifyStyle (), tak jak W poniższym przykładzie (gdzie uiDesiredStyie
przybiera wartość LVS_ICON, LVS_SMALLICON, LVS_LIST lub LVS_REPORT): ModifyStyle(LVS_TYPEMASK, uiDesiredStyie);
Dodawanie kolumn do kontrolki widoku listy
Zanim zaczniesz dodawać do kontrolki elementy, musisz zdefiniować kolumny, które znajdą się w liście. Służy do tego funkcja składowa InsertColumn (). Ta funkcja występuje w dwóch wersjach:
int InsertColumn(int nCol, const LV_COLUMN* pColumn); int InsertColumn(int nCol, LPCTSTR IpszColumnHeading,
int nFormat = LVCFMT_LEFT, int nWidth = -l,
int nSubltem = -1);
Aby zilustrować różnice pomiędzy tymi funkcjami, zobaczmy, w jaki sposób można wstawić do kontrolki widoku listy następujące kolumny:
static struct
{
LPTSTR szColText; UINT uiFormat; } columns[] = {
_T("Kol. l"), LVCFMT_LEFT, _T("Kol. 2"), LVCFMT_CENTER, T("Koi. 3"), LVCFMT RIGHT
};
Pierwsza wersja funkcji insertcolumn() wymaga podania numeru kolumny (liczonego od zera) oraz wskaźnika do wypełnionej struktury LV_COLUMN. Oto przykład wstawiania trzech różnych kolumn za pomocą tej wersji funkcji. Zwróć uwagę, że tekst każdej kolumny jest odpowiednio wyrównywany. Oprócz tego, zwróć uwagę, ile pracy potrzeba do zwykłego wstawienia kolumny do kontrolki widoku listy. Dzieje się tak, ponieważ ta wersja funkcji insertcolumn () najprawdopodobniej wstawia kolumnę przy użyciu funkcji Win32 SDK. W rzeczywistości, ta funkcja nie robi niczego poza przekazaniem adresu otrzymanej struktury w postaci komunikatu do kontrolki widoku listy.
for(int i = 0;
i < sizeof (columns) / sizeof (columns [0] );
i++
{
LV_COLUMN lvc,
: : ZeroMemory ( &lvc, sizeof (lvc) ) ;
lvc.pszText = (LPTSTR) columns [i] .szColText;
lvc.mask = LVCF_TEXT | LVCF_FMT; lvc.fmt= columns [i] . ui Format ;
ClientDC dc(this);
CSize size = dc.GetTextExtent (lvc.pszText) ;
lvc . ex = size. ex;
m_listCtrl . InsertColumn (i, &lvc) ;
}
Druga funkcja insertcolumn o jest łatwiejszy w obsłudze. W tej wersji, większość składowych struktur LV_COLUMN przyjmuje sensowne wartości. Oto jak wyglądałoby wywołanie tej funkcji dla tych samych trzech kolumn:
for (int i = 0;
i < sizeof columns / sizeof columns [0] ;
i++
{
m_listCtrl . InsertColumn (i,
columns [i] . szColText , columns [i] . ui Format) ;
}
Oczywiście, jedynym powodem, dla którego miałbyś korzystać z pierwszej wersji tej funkcji, byłaby chęć ustawienia tych składowych struktury LV_COLUMN, których nie da się ustawić w drugiej wersji funkcji (na przykład składowej mask).
Zmiana szerokości kolumn
Gdy kolumny już zostaną dodane, należy określić ich szerokość. Fragment kodu przedstawiony na listingu 24.6 ilustruje sposób dostosowywania szerokości kolumn, tak aby mieścił się zawarty w nich tekst. Zwróć uwagę, że do pobrania kontrolki nagłówka listy została użyta funkcja GetDlgitem ().
Listing 24.6. Dostosowywanie szerokości kolumn
CHeaderCtrl* pHeader =
(CHeaderCtrl*)m_listCtrl.GetDlgltem(O); ASSERT(pHeader); if (pHeader) {
// Wyłączenie odświeżania na czas zmiany szerokości
// nagłówków kolumn
m_listCtrl.SetRedraw(FALSE);
// pobranie liczby kolumn
int iNbrOfColumns = pHeader->Get!temCount();
int iNbrOfCols = GetColumnCount();
for (int iCurrCol = 0; iCurrCol < iNbrOfCols; iCurrCol++)
{
m_listCtrl.SetColumnWidth(iCurrCol, LVSCW_AUTOSIZE);
int nCurrWidth = m_listCtrl.GetColumnWidth(iCurrCol); m_listCtrl.SetColumnWidth(iCurrCol, LVSCW_AUTOSIZE_USEHEADER) ; int nColHdrWidth = m_listCtrl.GetColumnWidth(iCurrCol) ;
m_listCtrl.SetColumnWidth(iCurrCol, max(nCurrWidth,
nColHdrWidth});
}
// Po zmianie szerokości kolumn przywracamy // odświeżanie okna kontrolki. m_listCtrl.SetRedraw(TRUE); m listCtrl. Irwalidate () ;
}
Wstawianie elementów do kontrolki CListCtrl
Jak już wiesz, do wstawiania elementów do kontrolki służy funkcja CListCtrl: : insertitem(). Jednak w zależności od potrzeb aplikacji możesz użyć jednej z kilku przeciążonych wersji tej funkcji:
int Insertltem(const LYITEM* pltem);
int Insertltemfint nitem, LPCTSTR Ipszltem);
int Insertltemfint nitem, LPCTSTR Ipszltem, int nlmage);
Jednym z elementów wspólnych dla wszystkich wersji funkcji insertitemO jest zwracana wartość. Tą wartością jest int, będąca indeksem (liczonym od zera) reprezentującym element wstawiony do kontrolki. Gdy element zostanie wstawiony do kontrolki, odwołanie do niego odbywa się zawsze poprzez ten indeks.
Choć funkcja insertitemO wstawia element do kontrolki widoku listy, jednak pozwala na podanie tekstu tylko dla pierwszej kolumny. Aby określić tekst dla innych kolumn, musisz użyć funkcji składowej setitemText ().
BOOL SetItemText(int nitem, int nSubltem, LPCTSTR lpszText);
Pierwszy argument funkcji (nitem) reprezentuje indeks elementu na liście (otrzymany od funkcji insertitem ()). Drugi i trzeci parametr służą do wskazania kolumny (liczonej od zera) oraz napisu, jaki ma znaleźć się w tej kolumnie. Na listingu 24.7 znajduje się przykład (korzystający z trzech wstawionych poprzednio kolumn) wstawienia kilku wierszy do kontrolki widoku listy.
Listing 24.7. Wstawianie danych ze statycznej struktury do kontrolki widoku listy_________
static struct
{
LPTSTR szColl;
LPTSTR szCo!2;
LPTSTR szCo!3; } rows [] = {
"Al", "A2", "A3",
"Bl", "B2", "B3",
"Cl", "C2", "C3" };
for (int iCurrRow = 0; iCurrRow < sizeof rows / sizeof rowsfO]; iCurrRow++)
{
m_listCtrl.Insertitem(iCurrRow, rows[iCurrRow].szCol1, 0); m_listCtrl.SetItemText(iCurrRow, l, rows[iCurrRow] .szCo!2 ); m listCtrl.SetItemText(iCurrRow, 2, rows[iCurrRow].szCo!3);
}
Podsumowanie
Mimo tego, że widzieliśmy jak proste jest korzystanie z tych kontrolek, wśród wielu programistów mają one opinię skomplikowanych i trudnych do oprogramowania. To prawda, że w porównaniu z innymi kontrolkami, takimi jak pole edycji czy rozwijana lista, programista musi włożyć w to więcej wysiłku, lecz jednocześnie zyskuje tym dużo większe możliwości. Warto więc chyba poświęcić nieco pracy, aby w swojej aplikacji otrzymać dużo lepszy interfejs użytkownika.

Wyszukiwarka

Podobne podstrony:
Komentarz do listy kontrolnej BHP na budowie
LISTY KONTROLNE ZAGROŻEŃ
rozporzadzenie MT BiGM w sprawie formularza listy kontrolnej i formularza protokolu kontroli2
Listy kontrolne do analizy stanu bezpieczeństwa w indywidualnych gospodarstwach wiejskich
Automatyka okrętowa – praca kontrolna 2
Automatyka okrętowa – praca kontrolna 4
Kontrola momentu obciążenia
kontrola zakażeń zapadalności na choroby zakaźne

więcej podobnych podstron