2 12 Kontrolki (2)


Rozdział 12.
Kontrolki


W tym rozdziale:

Historia kontrolek w Windows
Anatomia kontrolki
Sposób wykorzystania standardowych kontrolek
Samodzielnie rysowane kontrolki
Klasa CButton
Klasa CListBox
Klasa CEdit
Klasa cstatic
Klasa CScrollBar
Klasa CComboBoK
Dostosowywanie kontrolek
Obsługa kontrolek za pomocą klawiatury


W tym rozdziale przyjrzymy się bliżej kontrolkom Windows oraz reprezentującym je klasom MFC. Pod koniec rozdziału będziesz ekspertem w praktycznym ich wykorzystaniu i dostosowywaniu.
Wprowadzenie
Nowa 32-bitowa wersja Windows jest dostarczana z ponad dwudziestoma rodzajami dostępnych kontrolek. Sześć z nich było dostępnych już w pierwszej wersji systemu; te kontrolki znajdują się w pliku user.exe. Pozostałe są nazywane kontrolkami standardowymi (common controls) i znajdują się w pliku comctl32.dll. O ile sześć oryginalnych kontrolek jest dostępnych we wszystkich wersjach Windows, o tyle kontrolki standardowe są dostępne wyłącznie w środowiskach 32-bitowych.
284
Część II Podstawy programowania Windows
Kontrolki to okna potomne ograniczone do swoich okien nadrzędnych. Gdy okno nadrzędne jest przesuwane, wraz z nim przesuwane są okna potomne. Podobnie, w momencie niszczenia okna nadrzędnego są niszczone również okna potomne. Kontrolki i pełnione przez nie funkcje są reprezentowane przez różne klasy MFC. Kontrolka listy jest reprezentowana przez klasę CListBox, kontrolka pola edycji przez klasę CEdit itd. Sześć oryginalnych kontrolek, odpowiadające im klasy MFC oraz klasy okien zostały zebrane w tabeli 12.1.
Tabela 12.1. Klasy oryginalnych kontrolek Windows
Kontrolka Klasa MFC lasa Windows(WNDCLASS)
Przycisk (Button), Cbutton BUTTON
Lista (List Box) CListBox LISTBOK
Rozwijana lista (Combo Box) CComboBox COMBOBOK
Pole edycji (Edit Control) CEdit
Element statyczny (Static Control) CStatic STATIC
Pasek przewijania (Scroll Bar) CScrollBar CROLLBAR
Ponieważ kontrolki to wyspecjalizowane okna, MFC wyprowadza klasy kontrolek z bazowej klasy cwnd. Korzyścią wyprowadzenia klas kontrolek z jednej klasy bazowej jest to, że w wielu przypadkach ta sama czynność w odniesieniu do różnych kontrolek może być wykonana przez wywołanie tej samej funkcji składowej, tak więc ctl->SetwindowText ( (char*) "Hello") zarówno ustawia tekst wyświetlany na przycisku, jak i wstawia napis "Hello" do kontrolki pola edycji.
Tworzenie kontrolek
Kontrolki można tworzyć na dwa sposoby. Jeden z nich polega na wstawieniu kontrolki do zasobów okna dialogowego. W momencie ładowania zasobu dialogu Windows automatycznie tworzy odpowiednie obiekty kontrolek. Kreatory wbudowane w Yisual Studio sprawiają, że jest to wprost trywialnie łatwe. Gdy zakończysz projektowanie okna dialogowego, możesz uruchomić ClassWizarda, który wygeneruje cały kod potrzebny do działania kontrolek. ClassWizard umożliwia także powiązanie (i to choćby za pomocą jedynie myszy) kontrolek z funkcjami pochodzących od nich komunikatów.
Druga metoda polega na jawnym wywołaniu funkcji tworzącej kontrolkę. Jeśli zechcesz utworzyć kontrolkę listy, wywołanie tej funkcji mogłoby wyglądać na przykład tak:
m_ListBox.Create(WS_CHILD | WS_VISIBLE | WS VSCROLL,
ctlRect, this, IDC LIST1)
Grupa stałych tworzących pierwszy parametr, WS_CHILD, WS_VISIBLE oraz WS_VSCROLL to znaczniki stylu określające wygląd i sposób działania kontrolki. W tym przypadku określają one, że kontrolka powinna zostać utworzona jako widoczne okno potomne
posiadające pionowy pasek przewijania. Następny parametr, ctiRect, to obiekt klasy CRect określający położenie i rozmiary listy. Kolejny parametr, this, jest wskaźnikiem do okna nadrzędnego. Właśnie dzięki niemu MFC jest w stanie ustanowić relacje zależności pomiędzy oknami. Ostatni z parametrów, IDC_LISTI, jest liczbą całkowitą bez znaku reprezentującą identyfikator zasobu kontrolki.
Gdy jawnie tworzysz kontrolkę, używając funkcji Create, musisz ją ręcznie umieścić w oknie nadrzędnym. Położenie i rozmiar kontrolki określa prostokąt otaczający zdefiniowany w obiekcie klasy CRect. Gdy obliczasz rozmiary kontrolki podczas jej tworzenia, zawsze weź pod uwagę wysokość i szerokość bieżącej czcionki. W przeciwnym razie napisy w kontrolce mogą być obcięte, a sama kontrolka może znaleźć się w niewłaściwym miejscu okna nadrzędnego. Pamiętaj także, że położenie kontrolki w oknie nadrzędnym określa się zawsze względem początku obszaru roboczego okna, tak jak pokazano na listingu 12.1.
Listing 12.1. Określanie położenia kontrolki
CClientDC dc (this); CFont TempFont; TEKTMETRIC metric; CRect TempRect; CEdit TempEdit;
// Pobieramy wymiary urządzenia wyjściowego i zamieniamy je na punkty
CharHeight = -((dc.GetDeviceCaps(LOGPIKELSY)*8/72));
// Tworzymy czcionkę
TempFont.CreateFont(CharHeight, O, O, O, FW_NORMAL, O, O, O, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS,
CLIP_CHARACTER_PRECIS, DEFUALT_QUALITY, DEFAULT_PITCH | FFJDONTCARE, "Arial");
// Wybieramy czcionkę w kontekście urządzenia obszaru roboczego // (z zachowaniem aktualnie wybranej czcionki) CFont *p01dFont = dc.SelectObject(&TempFont);
// Pobieramy rozmiary nowej czcionki
dc.GetTextMetrics(smetric);
CharX = metric.tmAveCharWidth;
CharY = metric.tmHeight+metric.tmExternalLeading;
// Obliczamy wymiary prostokąta otaczającego kontrolkę TempRect.SetRect(CharX*2, CharY*2, CharX*20, CharY*2);
// Tworzymy kontrolkę
TempEdit.Create(WS_CHILD | WS_VISIBLE, TempRect, this, IDC EDIT1);
Ten fragment kodu ilustruje zmianę czcionki obszaru roboczego na Arial, a następnie wykorzystanie jej wymiarów w celu ustalenia położenia kontrolki w obszarze roboczym. Najpierw pobieramy rozmiary obszaru roboczego okna i zamieniamy je z pikseli na cal logiczny na punkty. Ponieważ rozmiary monitorów są różne, Windows podaje szerokość ekranu w tzw. calach logicznych. Cal logiczny jest jednostką miary niezmienną baz względu na rozmiar obrazu i jest dość często używany w kodzie służącym do określania położenia okien, gdyż umożliwia programiście określenie pozycji na
ekranie bez względu na rzeczywisty rozmiar obrazu. Jednak aby zastosować tę jednostkę w naszych operacjach z rozmiarami czcionki, musimy zamienić ją na taką jednostkę miary, której możemy użyć, czyli w tym przypadku na punkty.
Gdy już mamy obliczoną wysokość znaków, możemy użyć jej do stworzenia egzemplarza czcionki Arial w obiekcie klasy CFont. Po utworzeniu czcionki musimy wybrać ją w bieżącym kontekście urządzenia. Wywołanie CDC: : Selectobject () wybiera nową czcionkę w kontekście urządzenia obszaru roboczego okna. Gdy mamy czcionkę wybraną w kontekście urządzenia, za pomocą funkcji CDC: :GetTextMetrics (), wypełniając strukturę TEKTMETRIC, możemy odczytać informacje o wysokości i szerokości czcionki. Używając pól tej Struktury, tmAveCharWidth, tmHeight oraz tmExternal-Leading, możemy obliczyć wysokość i średnią szerokość pojedynczego znaku.
Po wykonaniu całej tej pracy jesteśmy prawie gotowi do stworzenia kontrolki. Znając wysokość i szerokość pojedynczego znaku, możemy użyć ich do obliczenia wymiarów prostokąta (zawartego w obiekcie klasy CRect) i użycia go do określenia położenia kontrolki. Wywołując funkcję CRect: :SetRect (), definiujemy prostokąt o lewym górnym rogu w miejscu o współrzędnych 2,2 oraz szerokości 20 i wysokości 2 znaki. Gdy użyjemy go przy tworzeniu kontrolki pola edycji, spowoduje on utworzenie kontrolki dwa znaki na prawo od lewej krawędzi i dwa znaki poniżej górnej krawędzi obszaru roboczego. Szerokość kontrolki wyniesie dwadzieścia przeciętnych znaków, zaś jej wysokość - dwa znaki.
Przy konstruowaniu kontrolki w podany sposób objawia się pewna interesująca, choć czasem dość denerwująca "właściwość" Windows. Jeśli kontrolka zostanie wstawiona jako część zasobu dialogu, jest rysowana tak, jakby została "wyrzeźbiona" na powierzchni okna dialogowego. Takie kontrolki noszą nazwę kontrolek z trójwymiarową ramką (3D border). W kontrolkach tworzonych automatycznie nie stosuje się automatycznie tego efektu i są one rysowane z dwuwymiarową ramką (2D border). O tworzeniu trójwymiarowej ramki decyduje znacznik stylu WS_EX_CLIENTEDGE. Jak wskazuje przedrostek WS_EX, jest to znacznik rozszerzonego stylu kontrolki. Jednak omawiana przed chwilą funkcja Create () nie daje możliwości określenia rozszerzonego stylu.
Jak więc można rozwiązać ten problem? Klasa cwnd, z której zostało wyprowadzonych sześć oryginalnych kontrolek, posiada także funkcję składową CreateEx (), przyjmującą znaczniki stylu rozszerzonego. Wywołanie tej funkcji zamiast funkcji createo w listingu 12.1 wyglądałoby tak:
TempEdit.CreateEx(WS_EX_CLIENTEDGE, "EDIT", NULL,
WS_CHILD i WS_VISIBLE. TempRect, this, IDC_EDIT1);
Jak widać, składnia funkcji CreateEx () różni się nieco od składni funkcji Create (). Pierwszy argument określa rozszerzony styl okna, taki jak WS_EX_CLIENTEDGE. Drugi argument określa klasę okna (WNDCLASS) kontrolki, którą w tym przypadku jest EDIT. Czwarty argument zawiera nazwę okna; w przypadku tworzenia kontrolek powinieneś przekazać wartość NULL. Piąty, szósty, siódmy i ósmy argument określają, odpowiednio, znaczniki standardowego stylu, prostokąt otaczający w obiekcie CRect, wskaźnik do okna nadrzędnego oraz identyfikator zasobu kontrolki.
Jak dotąd poznaliśmy podstawy tworzenia kontrolek. Dowiedzieliśmy się jak tworzyć kontrolki w oknach dialogowych oraz ręcznie, w oknach nadrzędnych. Być może zastanawiasz się, w jaki sposób dostać się do informacji zawartych w kontrolce. Jeśli kon-trolkajest częścią zasobów dialogu, dostępem do danych kontrolki zarządza mechanizm nazywany DDX (Dialog Data Exchange - wymiana danych dialogu). Zajmiemy się nim szczegółowo w rozdziale 14. Jeśli jednak kontrolka jest częścią zwykłego okna, w celu dostępu do jej danych musisz skorzystać z funkcji składowych kontrolki. W następnych sekcjach zapoznamy się więc ze szczegółami programowania każdej z sześciu oryginalnych kontrolek.
Używanie klasy CButton
Klasa CButton służy do tworzenia przycisków w czterech różnych stylach: przycisków opcji, przycisków radiowych, ramki grupy oraz popularnych zwykłych przycisków. O rodzaju tworzonego przycisku decyduj ą znaczniki stylu. W tabeli 12.2 zebrano związane z tym znaczniki stylu, podając opis przycisku, jaki reprezentują.
Tabela 12.2. Znaczniki stylu klasy CButton
Styl
Opis
BS_PUSHBUTTON-Zwykły wciskany przycisk.
BS_DEFPUSHBUTTON-Wciskany przycisk z pogrubioną ramką. Używany w oknach dialogowych do wskazania domyślnego przycisku.

BS_RADIOBUTTON-Kontrolka przycisku radiowego.
BS_AUTORADIOBUTTON-Kontrolka przycisku radiowego, która po kliknięciu powoduje wyłączenie zaznaczenia wszystkich innych przycisków w grupie.

BS_GROUPBOX-Ramka grupy.
BS_CHECKBOX-Standardowy przycisk opcji.
BS_AUTOCHECKBOX-Przycisk opcji zmieniający stan po kliknięciu.
BS_3STATE-Przycisk opcji posiadający trzy stany: zaznaczony, niezaznaczony oraz pośredni.

BS _3STATEAUTO-To samo co BS_3STATE, z tym że po kliknięciu automatycznie przechodzi przez wszystkie trzy stany.

Tworzenie zwykłych przycisków
Zwykły przycisk (rysunek 12.1) tworzy się przez zastosowanie w wywołaniu funkcji CButton:-.Create() znacznika BS_PUSHBUTTON lub BS_DEFPUSHBUTTON. Znacznika BS_DEFPUSHBUTTON zwykle używa się tylko w celu zaznaczenia domyślnego przycisku w dialogu lub w oknie. Przycisk utworzony z użyciem stylu BS_DEFPUSHBUTTON jest automatycznie wybierany w chwili, gdy użytkownik wciśnie klawisz Enter w czasie, gdy okno lub dialog znajduje się w ognisku wprowadzania.
Obsługa komunikatów przycisku
Po kliknięciu wszystkie rodzaje przycisków wysyłają do okna nadrzędnego komunikat WM_COMMAND. Odpowiednia funkcja obsługi tworzona przez MFC nosi nazwę OnNazwa-Przycisku, gdzie NazwaPrzycisku odpowiada nazwie identyfikatora zasobu przycisku. Jeśli chcesz obsłużyć zdarzenie kliknięcia przycisk, po prostu dodaj odpowiedni kod do tej funkcji obsługi.
Tworzenie przycisków radiowych
Do tworzenia przycisków radiowych (rysunek 12.2) służy wywołanie funkcji CButton: :Create (} z zastosowaniem znacznika stylu BS_RADIOBUTTON lub BS_AUTORADIOBUTTON. Ponieważ przyciski radiowe zwykle są używane do reprezentowania grup wzajemnie wykluczających się opcji, najczęściej używa się właśnie stylu BS_AUTORADIOBUTTON.
Ustawianie i odczytywanie stanu przycisków radiowych
Jeśli zdecydujesz się na stworzenie przycisków radiowych bez użycia stylu BS_AUTO-RADIOBUTTON, musisz ręcznie zapewnić odpowiedni stan wszystkich przycisków w grupie. W tym celu w każdej z funkcji obsługi komunikatu przycisków (BN_CLICKED) w grupie wykonaj poniższe kroki:
1. Za pomocą wywołania CButton: : Setstate () ustaw stan przycisku na BST_CHECKED (zaznaczony).
2. Stan pozostałych przycisków ustaw na BST_UNCHECKED (nie zaznaczony). Te kroki demonstruje poniższy fragment kodu:
void CTestDlg:rOnRadioButtonl() {
// Zaznacz przycisk, gdyż to właśnie na nim nastąpiło kliknięcie
m_ctlRadioButtonl.SetCheck(BST_CHECKED);
// Usuń zaznaczenie z innego przycisku, gdyż nastąpiło kliknięcie
// gdzie inedziej
m_ctlRadioButtonl.SetCheck(BST UNCHECKED);
}
Dużo prostsze jest użycie stylu BS_AUTORADIOBUTTON. Ponieważ ten styl operuje na grupie kontrolek, musisz dopomóc Windows w określeniu, które kontrolki przycisków radiowych należą do grupy. Aby stworzyć grupę przycisków radiowych automatycznie zmieniających stan po kliknięciu ich, wykonaj poniższe kroki:
1. Utwórz sekwencję przycisków radiowych. Pamiętaj, by pomiędzy przyciskami radiowymi nie tworzyć innych kontrolek.
2. Dla pierwszego przycisku z grupy użyj stylu WS_GROUP; w ten sposób zaznaczysz początek grupy.
3. Jeśli chcesz stworzyć kilka grup przycisków radiowych, zastosuj styl WS_GROUP dla pierwszego przycisku w każdej grupie. Windows korzysta ze znaczników WS_GROUP do wyznaczenia granic pomiędzy grupami.
4. Po stworzeniu grupy użyj funkcji Setcheck(), aby mieć pewność, że jeden z przycisków grupy jest zaznaczony.
5. Bieżący stan przycisku radiowego zwraca funkcja CButton: :Getcheck(). Przyciski radiowe zwracają wartość BST_CHECKED (zaznaczony) lub BST_ UNCHECKED (nie zaznaczony).
Tworzenie przycisków opcji
Przyciski opcji (rysunek 12.3) to przyciski tworzone z użyciem jednego ze znaczników
Stylu: BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE lub BS_AUT03STATE. Przyciski
opcji tworzone z jednym ze stylów "Auto" po kliknięciu automatycznie zmieniają swój stan. Podobnie jak w przypadku przycisków radiowych, jeśli zdecydujesz się na stworzenie przycisku bez użycia stylu "Auto", będziesz musiał ręcznie zadbać od odpowiednią zmianę stanu przycisku po kliknięciu.
Ustawianie i odczytywanie stanu przycisków opcji
Do odczytu stanu przycisków opcji służy funkcja CButton: :GetCheck (). Przyciski opcji zwracają wartość BST_CHECKED (zaznaczony) lub BST_UNCHECKED (nie zaznaczony).
Możesz ręcznie ustawić stan przycisku, wywołując funkcję CButton: : Setcheck (). Dla przycisków dwu- i trójstanowych ta funkcja akceptuje wartości BST_CHECKED (zaznaczony) oraz BST_UNCHECKED (nie zaznaczony).
Używanie klasy CListBox
Klasa MFC CListBox reprezentuje klasę okna kontrolki listy. Kontrolki list wyświetlają listy napisów nazywanych pozycjami (item). Kontrolki list doskonale nadają się do wyświetlania jednowymiarowych list elementów, takich jak lista miast czy kodów pocztowych, jednak nadają się również do wyświetlania wszystkich innych danych, które mogą być reprezentowane przez napisy.
Kontrolki list występują w kilku odmianach. Domyślna lista prezentuje dane w pojedynczej pionowej kolumnie i umożliwia zaznaczenie tylko jednego elementu w danej chwili. Używając znaczników stylu zebranych w tabeli 12.3, możesz tworzyć kilka odmian standardowej kontrolki listy.
Tabela 12.3. Znaczniki stylu klasy CListBox
Styl
Opis
LBS_STANDARD-Domyślna kontrolka listy posiadająca ramkę oraz pionowy pasek przewijania, elementy posortowane alfabetycznie oraz wysyłająca do okna nadrzędnego komunikaty informujące o wybraniu innej pozycji listy lub dwukrotnym kliknięciu którejś z pozycji.

LBS_SORT-Sortuje elementy alfabetycznie. Kontrolki list nie posiadające tego stylu wyświetlają elementy w takiej kolejności, w jakiej zostały one dodane.

LBS_NOSEL-Umożliwia przeglądanie elementów, lecz bez możliwości ich zaznaczania.

LBS_MULTIPLESEL-Umożliwia zaznaczanie kilku elementów naraz.
LBS_EXTENDEDSEL-Umożliwia zaznaczanie grup elementów przy wciśniętych klawiszach Ctrl lub Shift. Zwykle łączony ze stylem
LBS_MULTIPLESEL.

LBS_NOTIFY-Powiadamia okno nadrzędne o zmianie zaznaczonego elementu lub dwukrotnym kliknięciu którejś z pozycji.

LBS_ DISABLENOSCROLL-Powoduje wyświetlenie pionowego paska przewijania bez względu na ilość pozycji listy. Jeśli na liście nie ma wystarczającej ilości pozycji, aby umożliwić przewijanie, pasek przewijania zostaje wyłączony. Domyślne kontrolki list ukrywają pasek przewijania, gdy nie jest potrzebny.

LBS_MULTICOLUMN-Umożliwia wyświetlanie kilku kolumn.

LBS_USETABSTOPS-Powoduje rozwinięcie znaków tabulacji zawartych w napisach w pozycjach listy. Do ustawiania tabulatorów służy funkcja
CListBox::SetTabStops().
LBS_NORĘDRAW-Wyłącza automatyczne odrysowywanie listy w momencie dodania lub usunięcia pozycji. Takie odrysowywanie można włączać lub wyłączać za pomocą komunikatu WM_SETREDRAW.

LBS_HASSTRINGS-Powoduje zapamiętanie elementów dodanych do listy. Ten znacznik jest zawarty także w stylu LBS_STANDARD.

LBS_WANTKEYBOARDINPUT-
Gdy lista znajduje się w ognisku wprowadzania i nastąpi wciśnięcie klawisza, do okna nadrzędnego są wysyłane komunikaty WM_VKEYTOITEM oraz WM_CHARTOITEM.

LBS_NOINTEGRALHEIGHT-Powoduje, że wysokość okna listy nie musi być wielokrotnością wysokości pozycji.



Tworzenie kontrolek list
Kontrolki list (rysunek 12.4) mogą być tworzone za pomocą funkcji CListBox: : Create () lub CListBox: : GreateEx (). Jeśli chcesz skonstruować standardową kontrolkę listy z trójwymiarową ramką i alfabetycznie sortowanymi elementami, wywołanie funkcji będzie wyglądało następująco:
ra_ListStates.CreateEx(WS_EX_CLIENTEDGE,
"LISTBOK", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD, TempRect, this, IDC_LIST1);
Styl LBS_STANDARD jest czymś w rodzaju wzorcowego stylu dla wszystkich kontrolek list. Zawiera alfabetyczne sortowanie, pionowy pasek przewijania wyświetlany tylko w razie potrzeby oraz zapewnia wysyłanie do okna nadrzędnego komunikatów BN_CLICKED
i BN _ DOUBLECLICKED.
Dodawanie i usuwanie elementów
Do dodawania elementów do listy służy funkcja składowa AddString (): m_ListBox1.AddString(NowyElement) ;
Funkcja akceptuje zarówno wskaźniki do ciągów znaków zakończonych zerem, jak i obiekty klasy cstring. Jeśli lista została utworzona z użyciem stylu LBS_STANDARD lub LBS_SORT, w momencie dopisywania do listy elementy są sortowane alfabetycznie. Pozycje dodawane do list utworzonych bez stosowania wymienionych styli są dopisywane do końca listy. Działaniu stylów LBS_STANDARD lub LBS_SORT można zapobiec, stosując funkcję składową InsertString () :
m_ListBox1.InsertString,NowyElement);

InsertString () wstawia pozycję do listy w miejsce określone przez liczony od zera indeks. W podanym przykładzie NowyElement zostanie wstawiony na ósmej pozycji. Zarówno funkcja AddString (), jak i InsertString () zwraca pozycję nowo wstawionego elementu.
Do usuwania pozycji listy służy funkcja składowa DeleteStringO . Funkcja wymaga podania pojedynczego argumentu będącego indeksem elementu przeznaczonego do usunięcia. Jeśli chcesz usunąć wszystkie pozycje listy, użyj funkcji ResetContent ().
Zaznaczanie i wyszukiwanie elementów
Klasa CListBox posiada kilka funkcji składowych umożliwiających odczytywanie informacji o zaznaczonych elementach oraz wybór zaznaczonych elementów. W przypadku list z zaznaczanym pojedynczym elementem użyj funkcji GetCurSel (). Ta funkcja zwraca liczony od zera indeks aktualnie zaznaczonego elementu. Jeśli nie jest zaznaczony żaden element, funkcja zwraca wartość LB_ERR (-1).
Z drugiej strony, ustawienie zaznaczenia elementu odbywa się przez przekazanie funkcji SetCurSel () indeksu pozycji, która ma zostać zaznaczona. Aby usunąć zaznaczenie z listy, w funkcji SetCurSel () przekaż wartość -1. Możesz także dokonać zaznaczenia pozycji w oparciu o napis; służy do tego funkcja Selectstring ().
m ListBoxl.Selectstring(1, "CA");
Funkcja selectstring () wymaga podania dwóch argumentów. Pierwszy z nich informuje, od którego elementu ma rozpocząć się poszukiwanie. Jeśli chcesz zacząć od początku listy, użyj wartości -1. Jeśli zastosujesz inną wartość, funkcja i tak przeszuka całą listę, lecz począwszy od wskazanego elementu, po dojściu do końca listy zacznie poszukiwanie od elementu zerowego. Drugi argument zawiera początkowy tekst pozycji. Zostaje zaznaczony pierwszy element spełniający podane kryteria, ważne jest, by wybierać odpowiednie teksty do wyszukiwania.
Aby przeszukać listę bez zaznaczania żadnego z elementów użyj funkcji Findstring () lub FindStringExact () . FindString ( ) UŻywa początku tekstu tak samo jak Select-String (), podczas gdy FindstringExact () wyszukuje napis całkowicie zgadzający się z podanym tekstem. Obie funkcje zwracają albo indeks znalezionego elementu, albo wartość LB_ERR w przeciwnym przypadku.
Listy umożliwiające wybór kilku elementów naraz działają nieco inaczej. Do zaznaczania elementów służą funkcje SetSel () (do zaznaczenia pojedynczego elementu) oraz SelltemRange (). Wywołania tych funkcji mogą być łączone w celu zaznaczania rozłącznych grup elementów:
m_ListBoxl.SetSel(5) ;
m_ListBoxl.SelltemRange(TRUE, 7, 12);
m_ListBoxl.SelltemRange(FALSE, l, 4 ) ;
Ten kod zaznacza elementy: 5. oraz od 7. do 12. i usuwa zaznaczenie elementów od l. do 4.
Obsługa komunikatów przycisków
Jak już widzieliśmy, kontrolki list wysyłają do okien nadrzędnych informacje zawarte w komunikatach WM_COMMAND. Makra MFC odwzorowują te komunikaty do pozycji mapy komunikatów ON_LBN. Tabela 12.4 zawiera listę komunikatów pochodzących od kontrolek list, powiązanych z nimi makr oraz przyczyn wygenerowania komunikatu.
Tabela 12.4. Komunikaty klasy CListBox
Komunikat
Przyczyna
Powiązane makro
LBN_SELCHANGE
Zmienił się zaznaczony element
(w wyniku interwencji użytkownika)
ON_LBN_SELCHANGE

LBN_SELCANCEL
Anulowano zaznaczenie
ON_LBN_SELCANCEL

LBN_SETFOCUS
Kontrolka znalazła się w ognisku wprowadzania
ON_LBN_SETFOCUS

LBN_KILLFOCUS
Kontrolka utraciła ognisko wprowadzania ON_LBN_KILLFOCUS

LBN_DBLCLK
Nastąpiło dwukrotne kliknięcie któregoś z elementów listy
ON_LBN_DBLCLK

LBN_ERRSPACE
Operacja nie powiodła się z powodu braku pamięci
ON LBN ERRSPACE


Używanie klasy CEdit
Klasa MFC CEdit reprezentuje klasę okna kontrolki pola edycji. Kontrolka CEdit to jedno- lub wielowierszowe pole edycji, które może zawierać tekst. Klasa MFC dostarcza dodatkowych możliwości w postaci obsługi wycinania, kopiowania, wklejania i anulowania, a także prostego formatowania tekstu.
Tworzenie pól edycji
Obiekty pól edycji (rysunek 12.5) są tworzone przez wywołanie funkcji CEdit: : Create ().
Klasa CEdit rozpoznaje znaczniki zebrane w tabeli 12.5. Tabela 12.5. Znaczniki stylu klasy CEdii
Styl
Opis
ES_LEFT-Tekst zawarty w kontrolce zostanie wyrównany do lewej.

ES_RIGHT-Tekst zawarty w kontrolce zostanie wyrównany do prawej.

ES_CENTER-Tekst zawarty w kontrolce zostanie wyśrodkowany.

ES_LOWERCASE-Wszystkie napisy będą wyświetlane małymi literami.

ES_UPPERCASE-Wszystkie napisy będą wyświetlane wielkimi literami.

ES_WANTRETURN-Wciśnięcie klawisza Enter, w momencie gdy kontrolka posiada ogniskowprowadzania, powoduje przejście do nowej linii tekstu, a nieuaktywnienie domyślnego przycisku okna dialogowego.

ES_AUTOVSCROLL-Kontrolka automatycznie przewija zawartość w pionie.
ES_AUTOHSCROLL-Kontrolka automatycznie przewija zawartość w poziomie.
ES_OEMCONVERT-Dla wszystkich znaków jest przeprowadzana konwersja ANSI do OEM do ANSI.

ES_NOHIDESEL-W momencie utraty ogniska wprowadzania kontrolka nie ukrywa stanu selekcji.
WS_VSCROLL-Powoduje, że kontrolka wyświetla pionowy pasek przewijania. Musi być stosowany łącznie ze stylem ES_AUTOVSCROLL.
WS HSCROLL-Powoduje, że kontrolka wyświetla poziomy pasek przewijania. Musi być stosowany łącznie ze stylem ES_AUTOHSCROLL.



Sterowanie kontrolka CEdit
Wywołując funkcję CEdit: :SetLimitText (), możesz programowo ograniczyć ilość znaków przyjmowanych przez kontrolkę CEdit:
m Edit1.SetLimitText(40);
W każdym przypadku górną granicą pojemności kontrolki jest około 60K tekstu. Powoduje to, że kontrolka CEdit dobrze nadaje się do mniejszych zadań związanych z obróbką tekstu. Jeśli musisz operować tekstami o objętości większej niż 60K, użyj zamiast tego kontrolki CRichEditctrl.
Funkcja składowa SetTabstops () służy do ustawiania tabulatorów w nowo utworzonej kontrolce pola edycji. Funkcja CEdit: : SetTabstops () określa odległości w jednostkach dialogu. Jednostka dialogu wynosi w przybliżeniu jedną czwartą szerokości czcionki systemowej. Domyślna odległość pomiędzy tabulatorami w kontrolkach CEdit wynosi 32 jednostki dialogu. Za pomocą funkcji CEdit: :SetTabstops () możesz zmienić odległości pomiędzy tabulatorami lub ustalić bezwzględny rozmiar każdego z tabulatorów. Obie koncepcje ilustruje poniższy przykład:
m_Editl.SetTabstops(16);
// Ustawia tabulatory na szesnaście jednostek dialogu
int nTabStops[] = { 5, 10, 30, 45, 52 };
m_Editl.SetTabstops(5, nTabStops);
// Ustala zmienny odstęp tabulatorów na 5, 10, 30, 45, 52
Wstawianie i usuwanie tekstu
Jeśli chodzi o wstawianie i odczytywanie tekstu z kontrolki CEdit, masz do wyboru dwie możliwości. Funkcje CEdit: :SetWindowText () i CEdit: :GetWindowText () wpływają na cały tekst zawarty w kontrolce. Funkcja CEdit: : setwindowText () zastępuje nowym tekstem cały tekst zawarty w kontrolce, zaś funkcja CEdit: : GetwindowText () zwraca tekst zawarty w kontrolce.
Jeśli chcesz zmienić jedynie część tekstu w kontrolce, musisz użyć innego zestawu funkcji. Funkcja CEdit: : GetLine () zwraca pojedynczą linię tekstu. Wywołanie tej funkcji wygląda następująco:
m_Edit1.GetLine(5, pBuf, sizeof(pBuf)};
GetLine () oczekuje trzech parametrów: liczonego od zera numeru linii przeznaczonej do odczytu, wskaźnika do bufora znaków przeznaczonego do umieszczenia odczytanego tekstu oraz maksymalnego rozmiaru bufora. Do wyznaczenia ilości miejsca w buforze możesz użyć funkcji CEdit: : LineLength (). Tekst skopiowany do bufora funkcją GetLine () nie zawiera kończącego znaku NULL. Aby móc użyć wypełnionego bufora, musisz znaleźć jakiś sposób wyznaczenia końca łańcucha znaków. Na szczęście funkcja GetLine () zwraca również długość kopiowanej do bufora linii, więc na tej podstawie możesz określić długość łańcucha.
Jeśli chcesz znać całkowitą ilość linii w kontrolce CEdit, użyj funkcji CEdit: : GetLineCount (). Ta funkcja zwraca aktualną ilość linii w kontrolce. Pamiętaj jednak, że funkcja zwraca wartość l także wtedy, gdy kontrolka jest zupełnie pusta. Zapomina o tym wielu początkujących programistów Windows.
Wycinanie, kopiowanie, wklejanie i anulowanie
CEdit dostarcza przejrzystych funkcji składowych umożliwiających programowe wycinanie, kopiowanie i wklejanie tekstu ze schowka, a także anulowanie dokonanych zmian. Instrukcja
m_Editl.Cut();
powoduje wycięcie z kontrolki zaznaczonego tekstu i umieszczenie go w schowku Windows. Instrukcja
m_Editl.Copy();
powoduje skopiowanie z kontrolki zaznaczonego tekstu i umieszczenie go w schowku Windows.
Jeśli kontrolka nie zawiera zaznaczonego tekstu, funkcje Cut () i Copy () nie robią niczego.
Jeśli chcesz ręcznie zaznaczyć tekst kontrolki w swoim programie, użyj funkcji CEdit:
:SetSel ():
ra_Editl.SetSel(25, 100);
Ten przykład zaznacza 75 znaków począwszy od znaku o numerze 25. Jeśli zaznaczenie rozciąga się na kilka wierszy tekstu, kontrolka CEdit automatycznie przewija tekst w czasie zaznaczania. Jeśli chcesz wyłączyć to przewijanie, przekaż funkcji SetSel () trzeci parametr o wartości FALSE:
m_Editl.SetSel(25, 100, FALSE};
W ten sposób zostanie zaznaczonych tych samych 75 znaków, lecz tym razem bez denerwującego przewijania.
Co jednak zrobić, gdy chcesz zaznaczyć tekst, lecz znasz jedynie indeks linii? Klasa CEdit dostarcza przydatnej funkcji składowej, CEdit: :Lineindex (). Ta funkcja przyjmuje liczony od zera indeks linii i zwraca indeks pierwszego znaku w tej linii. Na tej podstawie możesz określić początek zaznaczenia. Wyszukanie końca wiąże się z nieco większą ilością pracy. Poniższy fragment kodu demonstruje sposób zlokalizowania początku i końca zaznaczenia w oparciu o wartości indeksów linii. Dla celów tego przykładu zakładamy, że zaznaczenie ma zacząć się od linii 5. i skończyć na linii 12:
int SelStart;
int SelEnd = 0;
int t;
SelStart = m_Editl.Linelndex(5);
// Pobranie indeksu znaku dla linii 5.
// Przejście przez każdą z linii i dodanie jej długości for (t = 5; t < 13; t++) {
SelEnd += m Editl.LineLength(t);
}
m_Editl.SetSel(SelStart,SelEnd,FALSE);
// W tym momencie mamy zaznaczone linie od 5. do 12.
Funkcja CEdit: : Pastę () wkleja zawartość schowka do kontrolki. Jeśli w kontrolce jest zaznaczony tekst, funkcja Pastę () zastępuje go tekstem wstawianym ze schowka. Jeśli w kontrolce nie ma zaznaczonego tekstu, tekst ze schowka wstawiany jest w miejsce aktualnego punktu wstawiania. Jeśli schowek jest pusty, funkcja Pastę () nie robi niczego. W celu wyznaczenia czy schowek jest pusty, możesz wywołać funkcję Windows API : : isciipboardFormatAvaiiable (), przekazując jej stałą CF_TEXT. Funkcja zwraca wartość logiczną wskazującą, czy w schowku znajduje się jakaś zawartość żądanego typu:
b_bHasText = ::IsClipboardFormatAvailable(CF_TEXT); Do anulowania dokonanych zmian można użyć funkcji CEdit: :Undo ().
Korzystanie z funkcji Undo()
Funkcja CEdit: :Undo() może służyć do wielokrotnego anulowania zmian, pod warunkiem, że w międzyczasie nie zostały dokonane zmiany w zawartości kontrolki. Oznacza to, że możesz dokonać zmian w zawartości kontrolki, po czym wywołać funkcję CEdit: : Undo () w celu anulowania tych zmian. Dopóki do kontrolki nie wpiszesz czegoś innego, funkcja Undo () będzie anulować kolejne zmiany. Edycja tekstu dokonana po wywołaniu funkcji Undo () powoduje wyzerowanie bufora zmian i zapisanie w nim tylko ostatniej zmiany.
Obsługa komunikatów kontrolki CEdit
Kontrolki pola edycji wysyłają informacje do okien nadrzędnych poprzez komunikaty EN_. Makra MFC odwzorowują te komunikaty do pozycji mapy komunikatów ON_EN. Tabela 12.6 zawiera listę komunikatów pochodzących od kontrolek CEdit, powiązanych z nimi makr oraz przyczyn wygenerowania komunikatu.
Tabela 12.6. Komunikaty klasy CEdit


Komunikat
Przyczyna
Powiązane makro

EN_ UPDATE
Tekst kontrolki ma ulec zmianie
ON_ EN_ UPDATE

EN_CHANGE
Tekst kontrolki uległ zmianiON
ON_EN _ CHANGE

EN_ HSCROLL
Tekst jest przewijany w poziomie
przy użyciu paska przewijaniaON
ON_EN _ HSCROLL

EN_VSCROLL
Tekst jest przewijany w pionie przy użyciu paska przewijania
ON_EN_VSCROLL


EN_SETFOCUS
Kontrolka znalazła się w ognisku wprowadzania
ON_EN_SETFOCUS
EN_KILLFOCUS
Kontrolka utraciła ognisko wprowadzania
ON_EN_KILLFOCUS

EN_MAXTEXT
Wprowadzono maksymalną dozwoloną ilość tekstu lub punkt wstawiania znajduje się w prawym dolnym rogu prostokąta formatowania
ON_EN MAXTEXT

EN_ERRS PACE
Operacja nie powiodła się z powodu braku pamięci
ON_EN_ERRS PACE

Używanie klasy CStatic
Klasa MFC cstatic reprezentuje klasę okna STATIC. Kontrolka tego typu jest prostokątem reprezentującym albo prostokątny obszar, wyświetlany tekst lub obrazek. W zależności od znaczników stylu używanych podczas tworzenia kontrolki obiekt cstatic może również przekazywać komunikaty do okna nadrzędnego.
Tworzenie kontrolek CStatic
Obiekty cstatic (rysunek 12.6) są tworzone wywołaniem cstatic: :Create ().
Rys. 12.6.
Obiekt CStatic
Klasa cstatic rozpoznaje znaczniki stylu zebrane w tabeli 12.7. Tabela 12.7. Znaczniki stylu kontrolek statycznych
Styl
Rodzaj kontrolki
Opis
SS_ LEFT
Tekst
Wyrównuje tekst do lewej strony. Jeśli tekst nie mieści się w linii, jest przenoszony do następnej.

SS_ CENTER
Tekst
To samo co SS_LEFT, z tym że tekst jest wyśrodkowany.

SS_ RIGHT
Tekst
To samo co SS_LEFT, z tym że tekst jest wyrównany do prawej strony.

SS_ LEFTNOWORDWRAP
Tekst
Wyrównuje tekst do lewej strony.
Jeśli tekst nie mieści się w linii, jest obcinany.

SS_ CENTERNOWORDWRAP
Tekst
To samo CO SS_LEFTNOWORDWRAP, z tym że tekst jest wyśrodkowany.

SS_ RIGHTNOWORDWRAP
Teksto samo CO SS_LEFTNOWORDWRAP,
z tym że tekst jest wyrównany do prawej strony.

SS_ SIMPLE
Tekst
Tworzy obiekt CStatic, którego tekst nie może być zmieniony po utworzeniu kontrolki.
SS_ CENTERIMAGE
Tekst
Tekst kontrolki jest wyśrodkowany zarówno w poziomie, jak i w pionie.
SS_ NOPREFIX
Tekst
Wyłącza domyślne wyświetlanie znaków ampersand (&ć) jako skrótów klawiatury.

SS_ SUNKEN
Tekst
Dookoła kontrolki wyświetlana jest ramka dająca wrażenie, że kontrolka zagłębia się w tle.

SS_BLACKRECT
Prostokąt
Jest rysowany jednolity prostokąt
w kolorze systemowym COLOR_WINDOWFRAME.

SS_WHITERECT
Prostokąt
Jest rysowany jednolity prostokąt
w kolorze systemowym COLOR_WINDOW.







SS_ GRAYRECT Prostokąt Jest rysowany jednolity prostokąt w kolorze systemowym COLOR BACKGROUND.
SS_BLACKFRAME Prostokąt Jest rysowany pusty prostokąt (kontur) w kolorze systemowym COLOR WINDOWFRAME.
SS_ WHITEFRAME Prostokąt Jest rysowany pusty prostokąt (kontur) w kolorze systemowym COLOR WINDOW.
SS_ GRAYFRAME Prostokąt Jest rysowany pusty prostokąt (kontur) w kolorze systemowym COLOR BACKGROUND.
SS_ETCHEDFRAME Prostokąt Jest rysowany pusty prostokąt (kontur) z zagłębionymi krawędziami.
SS_ ETCHEDHORZ Prostokąt Jest rysowany pusty prostokąt (kontur) z zagłębioną dolną i górną krawędzią.
SS_ ETCHEDYERT Prostokąt Jest rysowany pusty prostokąt (kontur) z zagłębioną lewą i prawą krawędzią.
SS_ BITMAP Obrazek Tworzy statyczną kontro Ikę wyświetlającą bitmapę.
SS_ ENHMETAFILE Obrazek Tworzy statyczną kontrolkęwyświetlającą zawartość metapliku.
SS_REALSIZEIMAGE
Obrazek
Wyłącza automatyczne dopasowanie rozmiaru kontrolki do rozmiaru wyświetlanego obrazka.

SS_ICON
Obrazek
Tworzy statyczną kontrolkę wyświetlającą ikonę.
SS_NOTIFY
Tekst,
prostokąt,
obrazek
Powoduje, że kontrolka wysyła komunikaty powiadamiania do okna nadrzędnego.


Ponieważ występują trzy różne rodzaje statycznych kontrolek, każda wymaga nieco innych kroków przy tworzeniu. Najprościej jest stworzyć statyczną kontrolkę zawierającą tekst. Wykonaj po prostu standardowe wywołanie funkcji create i przekaż te znaczniki stylu, które są ci potrzebne:
m_Staticl.Create("Nazwy", WS_CHILD | WS_VISIBLE | SS LEFT | SS_SUNKEN, TempRect, this, IDC_STATIC1);
Wywołanie funkcji setwindowText () powoduje ustawienie napisu kontrolki, podczas gdy wywołanie GetwindowText () służy do odczytu wyświetlanego tekstu. Tworzenie statycznej kontrolki w postaci prostokąta jest prawie równie łatwe:
m_Staticl.Create("", WS_CHILD | WS_VISIBLE |
SS_BLACKFRAME, TempRect, this, IDC_STATIC1);
Stworzenie i wyświetlenie statycznej kontrolki zawierającej obrazek wymaga paru dodatkowych kroków, jednak także nie jest trudne. Samo tworzenie kontrolki odbywa się tak jak uprzednio. Każdy rodzaj obrazka wymaga wywołania innej funkcji składowej w celu
załadowania go do kontrolki. Poniższy przykład tworzy obiekt cstatic i wyświetla w nim ikonę. Zakładamy, że himage jest uchwytem ikony:
m_Staticl.Create("", WS_CHILD | WS_VISIBLE | SS_ICON, TempRect, this, IDC_STATIC1);
m_Staticl.Setlcon(himage);
Z kolei poniższy kod ładuje zawartość metapliku (przy założeniu, że himage jest uchwytem obrazka w metapliku):
m_Staticl.Create("", WS_CHILD | WS_VISIBLE |
SS_ENHMETAFILE, TempRect, this, IDC_STATIC1);
m_Staticl.SetEnhMetaFile(himage);
Poniższy kod ładuje zawartość bitmapy (przy założeniu, że himage jest uchwytem bitmapy):
m_Staticl.Create("", WS_CHILD | WS_VISIBLE | SS_BITMAP, TempRect, this, IDC_STATIC1);
m_Static1.SetBitmap(himage);
Możesz także otrzymać uchwyt wyświetlanego przez kontrolkę obrazka; w tym celu wywołaj funkcję Getlcon (), GetEnhMetaFile () lub GetBitmap ().
Obsługa komunikatów kontrolek CStatic
Domyślnie kontrolki cstatic nie wysyłają do okien nadrzędnych komunikatów powiadamiania. Jeśli jednak utworzysz kontrolkę ze znacznikiem stylu SS_NOTIFY, kontrolka zacznie wysyłać komunikaty do okna nadrzędnego. Wysyłane komunikaty zostały zebrane w tabeli 12.8.
Tabela 12.8. Komunikaty klasy CStatic
KomunikatPrzyczyna Powiązane makro
STN_ ENABLE Kontrolka została włączona.ON_ STN_ ENABLE STN_DISABLE Kontrolka została wyłączona. ON_STN_ DISABLE STN_ CLICKED Nastąpiło kliknięcie w obszarze kontrolk iON_ STN_ CLICKED STN_ DBLCLK Nastąpiło podwójne kliknięcie w obszarze kontrolki. ON_STN_DBLCLK
Stworzenie obiektu cstatic z użyciem znacznika SS_NOTIFY pozwala na uzyskanie pewnych ciekawych efektów. Możesz tworzyć "przezroczyste" aktywne obszary reagujące na kliknięcia myszką, reagujące na kliknięcia mapki graficzne lub nawet obrazki o kształcie przycisków, reagujące na kliknięcia myszką.
Używanie klasy CScrollBar
Klasa MFC CScrollBar reprezentuje klasę okna SCROLLBAR. Paski przewijania tworzone z użyciem klasy CScrollBar są ogólnie takie same jak paski przewijania, które masz okazje często oglądać w oknach. Występuje jednak kilka zasadniczych różnic. Paski przewijania Windows są ułożone wzdłuż dolnej lub bocznej krawędzi obszaru roboczego okna nadrzędnego i rozciągają się na całą szerokość lub wysokość tego obszaru. Oprócz tego, system sam je tworzy dla Ciebie. Paski przewijania CScrollBar mogą wystąpić w dowolnym miejscu obszaru roboczego okna, mogą mieć dowolną wysokość i szerokości oraz muszą zostać jawnie utworzone.
Tworzenie kontrolek CScrollBar
Paski przewijania akceptuj ą style znaczników zebrane w tabeli 12.9. Wywołanie funkcji Create () wygląda następująco:
m_VertScrollBar.Create(WS_CHILD | WS_VISIBLE | SBS VERT | SBS_RIGHTALIGN, TempRect, IDC SBYERT);
Po pierwsze podajemy wszystkie znaczniki stylu. W tym przypadku podajemy, że widoczne okno potomne jest pionowym paskiem przewijania, ułożonym wzdłuż prawej krawędzi prostokąta opisanego w zmiennej TempRect. Jak widać w tabeli 12.9, ponieważ użyto stylu SBS_RIGHTALIGN, CScrollBar używa prostokąta TempRect jedynie do ustalenia końców paska przewijania. Szerokość prostokąta TempRect nie wpływa na szerokość paska przewijania. Szerokość paska jest zgodna z domyślną szerokością systemowych pasków przewijania.
Następnym parametrem jest TempRect, prostokąt opisujący zwykle rozmiary kontrolki. Jeśli nie użylibyśmy stylu SBS_RIGHTALIGN, pasek przewijania miałby rozmiary takie same jak prostokąt TempRect. Dwa ostatnie parametry już dobrze znamy: są to wskaźnik do okna nadrzędnego oraz identyfikator zasobu kontrolki.
Sterowanie paskiem przewijania
Klasa CScrollBar posiada kilka funkcji składowych, których możesz użyć do ustawienia bieżącej pozycji suwaka paska, odczytu położenia suwaka oraz określenia zakresu paska przewijania. Do ustawiania i odczytywania pozycji suwaka na pasku przewijania służą funkcje CScrollBar: : SetScrollPos () oraz CScrollBar : :GetScrollPos (). Do ustawiania i odczytywania zakresu paska przewijania służą funkcje CScrollBar: :SetScrollRange() orazCScrollBar::GetScrollRange().
Tabela 12.9. Znaczniki stylów klasy CScrollBar
Styl
Opis
SBS_BOTTOMALIGN
Używany ze stylem SBS_HORZ. Dolna krawędź paska przewijania jest wyrównana do dolnej krawędzi prostokąta podanego w wywołaniu funkcji składowej Create (). Pasek przewijania ma domyślną wysokość systemowego paska przewijania.

SBS_HORZ
Tworzy poziomy pasek przewijania. Jeśli nie zostanie użyty styl SBS_BOTTOMALIGN ani SBS_TOPALIGN, pasek przewijania ma wysokość, szerokość i położenie zgodne z wymiarami zawartymi w prostokącie przekazanym w funkcji składowej Create ().

SBS_LEFTALIGN
Używany ze stylem SBS_VERT. Lewa krawędź paska przewijania jest wyrównana do lewej krawędzi prostokąta podanego w wywołaniu funkcji składowej Create (). Pasek przewijania ma domyślną szerokość systemowego paska przewijania.

SBS_RIGHTALIGN
Używany ze stylem SBS_VERT. Prawa krawędź paska przewijania jest wyrównana do prawej krawędzi prostokąta podanego w wywołaniu funkcji składowej Create (). Pasek przewijania ma domyślną szerokość systemowego paska przewijania.

SBS_SIZEBOK
Tworzy prostokąt skalowania. Jeśli nie zostanie użyty styl
SBS_SIZEBOXBOTTOMRIGHTALIGN ani SBS_SIZEBOX-TOPLEFTALIGN, prostokąt skalowania ma wysokość, szerokość i położenie zgodne z wymiarami zawartymi w prostokącie przekazanym w funkcji składowej Create ().

SBS_
SIZEBOKBOTTOMRIGHTALIGNUżywany ze stylem SBS_SIZEBOX. Prawy dolny róg prostokąta skalowania jest wyrównany z prawym dolnym rogiem prostokąta podanego w wywołaniu funkcji składowej Create (). Prostokąt skalowania ma domyślny rozmiar systemowego prostokąta skalowania.
SBS_ SIZEBOXTOPLEFTALIGN
Używany ze stylem SBS_SIZEBOX. Lewy górny róg prostokąta skalowania jest wyrównany z lewym górnym rogiem prostokąta podanego w wywołaniu funkcji składowej Create (). Prostokąt skalowania ma domyślny rozmiar systemowego prostokąta skalowania.

SBS_TOPALIGN
Używany ze stylem SBS_HORZ. Górna krawędź paska przewijania jest wyrównana do górnej krawędzi prostokąta podanego w wywołaniu funkcji składowej Create (). Pasek przewijania ma domyślną wysokość systemowego paska przewijania.

SBS_ VERT
Tworzy pionowy pasek przewijania. Jeśli nie zostanie użyty styl SBS_RIGHTALIGN ani SBS_LEFTALIGN, pasek przewijania ma wysokość, szerokość i położenie zgodne z wymiarami zawartymi w prostokącie przekazanym w funkcji składowej
Create ().



Choć możesz użyć tych funkcji do sterowania paskiem przewijania, jeśli programujesz w środowisku 32-bitowym, wszystkie te operacje możesz wykonać w jednym kroku. Umożliwiają to dwie funkcje składowe: cscrollBar: :SetScrollinfo() orazcscrollBar: :GetScroiimfo o . Obie akceptuj ą strukturę SCROLLINFO:
typedef struct tagSCROLLINFO { // si
UINT cbSize;
UINT fMask;
int nMin;
int nMax;
UINT nPage;
int nPos;
int nTrackPos; } SCROLLINFO; typedef SCROLLINFO FAR *LPSCROLLINFO;
zawierającą prawie wszystkie informacje związane z paskami przewijania. Pierwsze pole, cbSize, zawiera całkowity rozmiar struktury. fMask to maska bitowa określająca żądane parametry paska przewijania. Możeszjej przypisać stałe wymienione w tabeli 12.10.
Tabela 12.10. Stałe atrybutów paska przewijania
Stała
Opis
SIF_DISABLENOSCROLL
Wyłącza pasek przewijania, jeśli nie jest potrzebny. Ta stała jest używana tylko w wywołaniu funkcji
CScrollBar::SetCrollInfo (}.

SIF_PAGE
Pole nPage struktury SCROLLINFO zawiera rozmiar strony dla proporcjonalnego paska przewijania.

SIF_POS
Pole nPos zawiera pozycję suwaka na pasku przewijania.
SIF_RANGE
Pola nMin i nMax zawieraj ą dolny i górny limit zakresu paska przewijania.

SIF_ ALL
Łączy w sobie wszystkie inne stałe.

Pole nTrackPos określa pozycję suwaka na pasku przewijania, przeciąganego w danej chwili przez użytkownika. Aplikacja może odczytać tę wartość podczas przetwarzania komunikatu powiadamiania SB_THUMBTRACK. Osobiście nie możesz ustawić tej wartości, gdyż funkcja CScrollBar: :SetCrollInfo () ją i tak ignoruje. Teraz, gdy znamy już funkcje składowe klasy CScrollBar, spójrzmy na fragment kodu z listingu 12.2, który tworzy i steruje paskiem przewijania.
Listing 12.2. Tworzenie i sterowanie paskiem przewijania
CScrollBar VertBar; SCROLLINFO si; CRect TempRect; int nCurrentPos; LPINT nMin; LPINT nMax;
TempRect.SetRect(100, 10, 100, 50); VertBar.Create(WS_CHILD | WS_VISIBLE | SBS_VERT |
SBS_SIZEBOXTOPLEFTALIGN, TempRect, this, IDC SCYERT1);
.
.
.
.
VertBar.GetRange(nMin, nMax);
// Teraz nMin i nMax zawierają limit zakresu przewijania
si.fMask= SIF_ALL;
YertBar.GetScrollInfo(&si) ;
// Teraz struktura si zawiera wszystkie informacje
// o pasku przewijania
s i.nMin = 10;
si.nMax = 90;
VertBar.SetScrollInfo(&si) ;
// Zakres przewijania został zmieniony w jednym wywołaniu

Obsługa komunikatów paska przewijania
Obiekt cscroiiBar, w odróżnieniu od innych omawianych dotąd kontrolek, nie wysyła do okna nadrzędnego komunikatów WM_COMMAND. Paski przewijania wysyłają komunikaty WM_VSCROLL lub WM_HSCROLL zawierające nową pozycję suwaka na pasku oraz identyfikator paska przewijania wysyłającego komunikat. Identyfikator kontrolki ma duże znaczenie, gdyż MFC kieruje te komunikaty do funkcji obsługi onVScroll () oraz OnHScroii (). Ponieważ okno może posiadać tylko jedną funkcję obsługi komunikatów, musi więc mieć jakiś sposób na zidentyfikowanie paska przewijania wysyłającego komunikat. Właśnie do tego służą identyfikatory kontrolek. Gdy MFC wywołuje funkcję obsługi komunikatu paska przewijania, poszczególne części komunikatu są przekazywane jako osobne parametry funkcji. Dzięki temu możesz łatwo stwierdzić, który pasek wysłał komunikat. Bardziej szczegółowo zagadnieniami przewijania zajmiemy się w rozdziale 20.
Używanie klasy CComboBox
Klasa MFC ccomboBox reprezentuje klasę okna rozwijanej listy. Rozwijana lista stanowi swoiste połączenie kontrolki CEdit z kontrolką CListBox. Ponieważ klasa ccomboBox posiada wiele funkcji składowych wspólnych z klasami CEdit oraz CListBox, skupimy się jedynie na tym, co jest unikalne dla klasy ccomboBox.
Tworzenie kontrolek CComboBox
Do tworzenia kontrolki ccomboBox służy standardowe wywołanie funkcji CreateO, zaś sama kontrolką została przedstawiona na rysunku 12.8.
Funkcja ccomboBox: :Create () przyjmuje znaczniki stylu zebrane w tabeli 12.1 1.
Tabela 12.11. Znaczniki stylu klasy CComboBox
Styl
Opis
CBS_AUTOHSCROLL
pole edycji należące do rozwijanej listy automatycznie przewija się w poziomie.

CBS_DISABLENOSCROLL
Jeśli nie ma wystarczającej ilości elementów do przewijania. pionowy pasek przewijania jest wyłączany, lecz cały czas jest widoczny. Domyślnie, jeśli pasek przewijania nie jest potrzebny, zostaje ukryty.

CBS_DROPDOWNTworzy listę rozwijaną na żądanie.

CBS_DROPDOWNLIST
Tworzy rozwijaną listę cały czas rozwiniętą.

CBS_LOWERCASEZnaki we wszystkich napisach są zamieniane na małe litery.

CBS_UPPERCASE
Znaki we wszystkich napisach są zamieniane na wielkie litery.

CBS_OWNERDRAWFIXED
Tworzy rozwijaną listę rysowaną przez użytkownika, w której wszystkie elementy mają taką samą wysokość.

CBS_OWNERDRAWVARIABLE
Tworzy rozwijaną listę rysowaną przez użytkownika,
w której poszczególne elementy mogą mieć różną wysokość.

CBS_SIMPLE
Tworzy zwykłą rozwijaną listę.

CBS_SORT
Powoduje automatyczne sortowanie dodawanych elementów.

CBS_HASSTRINGS
Powoduje, że rozwijana lista zapamiętuje dodawane do niej napisy. Ten styl jest włączony domyślnie. Listy rysowane przez użytkownika nie posiadają tego stylu.

CBS OEMCONVERT
Dokonywana jest konwersja znaków ANSI na OEM na ANSI.




Funkcja ccomboBox: :Create () przyjmuje także standardowe znaczniki stylu, z którymi mieliśmy do czynienia już w innych kontrolkach:
m_Combol.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST
CBS SORT | WS BORDER | WS_VSCROLL, TempRect, this, IDC COMBOi


Ważne jest, by pamiętać, że TempRect opisuje nie tylko szerokość pola edycji listy, ale także wysokość rozwijanej części listy. Pamiętaj więc, by odpowiednio dobrać rozmiary.
Sterowanie rozwijaną listą
W rzeczywistości nie ma zbyt wielu nowych funkcji, których mógłbyś użyć do sterowania rozwijaną listą. Do ustawiania i odczytywania napisu w polu edycji listy służą funkcje CComboBox: : SetWindowText () oraz CComboBox: : SetWindowText () . Funkcje CComboBox::AddString(), CComboBox::DeleteString() oraz CComboBox: :Insert-string () służą do manipulowania listą pozycji tak samo jak w przypadku kontrolki listy, obiektu CListBox.
Do funkcji unikalnych dla klasy ccomboBox należą ccomboBox: : showDropDown () wyświetlająca lub ukrywająca rozwijaną część listy; ccomboBox: :GetDroppedState () zwracająca informacje o stanie rozwijanej listy; ccomboBox: :GetLBText() zwracająca pozycję listy na podstawie liczonego od zera indeksu czy GComboBox: :GetLBTextLen() zwracająca długość pozycji listy na podstawie liczonego od zera indeksu.
Jedną z ważniejszych funkcji klasy ccomboBox jest SetExtencłedui (). Ta funkcja włącza rozszerzenie interfejsu użytkownika dla rozwijanej części listy. Domyślnie, lista jest rozwijana po kliknięciu listy, bez względu na rodzaj kontrolki. Jeśli zostanie włączony rozszerzony interfejs użytkownika, lista jest rozwijana tylko wtedy, jeśli została stworzona z użyciem stylu CBS_DROPDOWNLIST. Dodatkowo, przy normalnych ustawieniach, jeśli lista znajduje się w ognisku wprowadzania, wciśnięcie kombinacji Alt+F4 powoduje rozwinięcie listy. Do przewijania listy jest używany klawisz kursora w dół. Jeśli zostanie włączony rozszerzony interfejs użytkownika, do rozwinięcia i przewijania listy wystarczy samo wciśnięcie klawisza kursora w dół. Większość użytkowników oczekuje od rozwijanych list właśnie takiego działania, tak więc jeśli to możliwe, staraj się używać funkcji SetExtendedUI ( ) .
Obsługa komunikatów rozwijanej listy
Kontrolki ccomboBox mogą generować kilka specyficznych komunikatów. Jednak tylko pewne rodzaje rozwijanych list mogą zgłaszać te komunikaty. Przekazywane informacje zostały zebrane w tabeli 12.12.
Tabela 12.12. Komunikaty kontrolek rozwijanych list
Komunikat
Styl rozwijanej listy Przyczyna
Powiązane makro
CBN_ DBLCLK
CBS_ SIMPLE
Nastąpiło
dwukrotne
kliknięcie
pozycji listy.
ON_CBN_DBLCLK
CBN_SELCHANGE
Wszystkie
Został wybrany inny element
listy.
ON_CBN_SELCHANGE

CBN_ SELENDOKWszystkie

Dokonano selekcji.
ON_ CBN_ SELENDOK


CBN_SELENDCANCEL
CBS_DROPDOWNC

BS_DROPDOWNLIST
Anulowano
selekcję
.ON_ CBN_ SELENDCANCEL



CBN_EDITUPDATE CBS_SIMPLEC
BS_DROPDOWNTekst W polu
edycji zostanie
zaraz
zmieniony.
ON_CBN_EDITUPDATE

CBN_EDITCHANGE CBS_SIMPLEC
BS_DROPDOWN
Tekst w polu edycji uległ zmianie
ON CBN EDITCHANGE



CBN_ DROPDOWNC BS_DROPDOWNCBS_DROPDOWNLIST Została wyświetlona rozwijana część listy. ON CBN DROPDOWN

CBN_ CLOSEUP CBS_DROPDOWN CBS_DROPDOWNLIST Została zwi-nięta rozwijana część listy .ON_ CBN_ CLOSEUP

CBN KILLFOCUSWszystkieKontrolka utraciła ognisko wprowadzania. ON_CBN_ KILLFOCUS
CBN_SETFOCUS Wszystkie Kontrolka zyskała ognisko wprowadzania. ON_ CBN_ SETFOCUS
CBN ERRSPACE Wszystkie Operacja nie powiodła się z powodu braku pamięci. ON_ CBN_ ERRSPACE
Uff! W ostatniej sekcji poznaliśmy ogromną ilość informacji. Poznaliśmy proces tworzenia oryginalnych kontrolek, potrafimy je tworzyć samemu, a także znamy sposoby sterowania nimi. Zanim jednak przejdziesz do następnej sekcji, spróbuj samemu stworzyć przykładowy kod, zbierając razem wszystko to, czego się dowiedziałeś.
Program Mini edytora
Na dołączonej do książki płytce CD-ROM znajduje się demonstracyjny program ilustrujący sposób wykorzystania wielu z omawianych kontrolek. Program jest bardzo prostym edytorem plików tekstowych i rozpoznaje jedynie pliki z rozszerzeniem .mnę. Korzystając z tej aplikacji, możesz wyszukiwać pliki w kartotekach, a także otwierać, wyświetlać, edytować i zapisywać te pliki. Możesz również tworzyć nowe pliki. Miniedytor został stworzony za pomocą kreatora AppWizard w oparciu o aplikację okna dialogowego.
MiniEdit
Miniedytor
Położenie na płytce: Rozdzl2\MiniEdit
Nazwa programu: MiniEdit.exe
Zaawansowane programowanie kontrolek
Do tej chwili zajmowaliśmy się jedynie podstawowymi zagadnieniami związanymi z programowaniem kontrolek, takimi jak ich tworzenie, umieszczanie w odpowiednim miejscu okna czy obsługa komunikatów informacyjnych. W wielu sytuacjach wbudowane właściwości kontrolki są w zupełności wystarczające. Jednak może się zdarzyć, że będziesz zmuszony zmodyfikować działanie kontrolki lub choćby zmienić jej wygląd na ekranie. Tak więc w tej sekcji zajmiemy się:
Uzupełnianiem kontrolki o interfejs klawiatury
Rozszerzaniem wbudowanego działania kontrolek
Tworzeniem własnych przycisków
Zmianą koloru kontrolek
Dodawanie interfejsu klawiatury
Poznaliśmy już jedną z korzyści płynących z użycia kontrolek w oknach dialogowych. Dzięki temu nie musisz ręcznie męczyć się z tworzeniem i pozycjonowaniem kontrolek w oknie. Oprócz tego, dodatkową ogromną korzyścią jest odziedziczenie obsługi za pomocą klawiatury wszystkich kontrolek w dialogu. Gdy dialog zawiera kilka kontrolek, za pomocą klawisza Tab możesz przełączać się (właściwie przełączać ognisko wprowadzania) pomiędzy kolejnymi kontrolkami. Za obsługę tego mechanizmu odpowiada okno dialogowe.
Zwykłe okno nie posiada tej właściwości. Oznacza to, że musisz sam zająć się przeniesieniem ogniska wprowadzania za każdym razem, gdy zostanie wciśnięty klawisz Tab. Nie jest to tak trudne jak mogłoby się wydawać, wymaga jednak wiedzy na temat wykorzystania komunikatów w Windows oraz kolejności, w jakiej komunikaty są przetwarzane przez bibliotekę MFC. Głęboko w ciemnych trzewiach "szkieletu" aplikacji znajduje się segment kodu nazywany pompą komunikatów (message pump). Pompa komunikatów nieustannie sprawdza czy w kolejce nie znajdują się nowe komunikaty. Gdy pojawi się komunikat, zostaje tłumaczony na znane nam komunikaty MFC, takie jak na przykład ON_DBLCLICK, a następnie jest przekazywany do odpowiedniej kontrolki lub okna potomnego.
Do sprawdzania komunikatów klawiatury i zamiany ich w odpowiednie polecenia wyboru dla dialogu lub - w naszym przypadku - okna, służy funkcja Win32 API,IsDialog-Message (). Na przykład, wciśnięcie klawisza Tab powoduje wybranie następnej kontrolki lub grupy kontrolek, zaś wciśnięcie klawisza kursora w dół powoduje wybranie następnej kontrolki w grupie.
Aby funkcja : : isDialogMessage () mogła poprawnie działać, musimy wywołać ją, jeszcze zanim MFC przystąpi do przetłumaczenia komunikatu. Właśnie dlatego ważne jest zrozumienie kolejności operacji związanych z przetwarzaniem komunikatów przez MFC. Gdy okno otrzymuje komunikat, wywołuje funkcję TranslateMessage () w celu przetworzenia wszelkich komunikatów związanych z klawiaturą na odpowiednie kody
wirtualne. Następnie MFC wywołuje funkcję DispatchMessage () w celu wysłania komunikatu do odpowiedniej kontrolki lub, ogólnie, okna potomnego. Na szczęście MFC dostarcza odpowiedniej funkcji, preTranslateMessage (), której możemy użyć do zmodyfikowania domyślnego zachowania okna.
To, czy okno przetłumaczy komunikat, zależy od wartości zwróconej przez funkcję PreTranslateMessage (). Jeśli ta funkcja zwróci zero, komunikat jest przekazywany do funkcji TransiateMessage (). Jeśli funkcja zwróci wartość różną od zera, MFC zakłada, że komunikat został przetworzony i przechodzi do następnego komunikatu w kolejce. Jeśli funkcja PreTranslateMessage () zwróci wartość różną od zera, funkcja TransiateMessage () wcale nie zostanie wywołana.
Właśnie w tym miejscu wstawimy więc wywołanie funkcji : : isDiaiogMessage o. Gdy ta funkcja otrzyma komunikat, który będzie mogła przetworzyć, zwróci wartość logiczną TRUE. Ponieważ z definicji wartość TRUE jest wartością różną od zera, wartość zwrócona przez funkcję : : IsDiaiogMessage () może zostać wygodnie użyta także jako wartość zwracana przez funkcję PreTranslateMessage () :
BOOL CMainWin::PreTranslateMessage(MSG* pMsg) {
return ::IsDiaiogMessage(m_hWnd, pMsg); }
Funkcja : : IsDiaiogMessage () oczekuje dwóch parametrów. Pierwszy z nich to uchwyt okna otrzymującego komunikat. Można go łatwo przekazać, podając zmienną składową m_hwnd klasy cwnd. Drugim parametrem jest wskaźnik do struktury MSG.
Funkcja : : IsDiaiogMessage () używa uchwytu okna oraz informacji w strukturze MSG do wyznaczenia, czy komunikat zawiera komunikat mogący odnosić się do okna dialogowego, na przykład wciśnięcie klawisza Tab, czy klawisza kursora w dół. Jeśli tak, funkcja przekazuje odpowiedni komunikat wyboru w celu przeniesienia ogniska wprowadzania do następnej kontrolki.
Modyfikowanie działania kontrolki
Gdy dłużej popracujesz z Visual C++ i MFC, z pewnością zdarzy się, że będziesz chciał zmienić domyślne działanie pewnych kontrolek. Na przykład, załóżmy, że piszesz aplikację związaną z intensywnym wprowadzaniem danych. Duża część kodu będzie wiązać się z zatwierdzaniem danych i analizą błędów. Czy nie byłoby miło, gdybyś mógł tworzyć własne wersje kontrolek, zawierające wbudowane procedury związane z zatwierdzaniem danych? Dzięki mapowaniu komunikatów przeprowadzanemu przez MFC i mechanizmom dziedziczenia języka C++ stworzenie własnej kontrolki jest całkiem proste.
Dla celów niniejszej demonstracji załóżmy, że piszesz aplikację do zarządzania zasobami ludzkimi. Jednym z pól jest kontrolka CEdit zawierająca numer NIP. Tak więc to pole może zawierać jedynie myślniki lub cyfry. Sprawdza to poniższy kod:
class CNipEdit : public CEdit
{
protected:
afx_msg void OnChar(UINT, UINT, UINT)
DECLARE MESSAGE MAP()
};
BEGIN_MESSAGE_MAP (CNipEdit, CEdit)
ON_WM_CHAR() END_MESSAGE_MAP(}
void CNipEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(((nChar >= 'O') && (nChar <= '9' )) | | (nChar == '-')) CEdit::OnChar(nChar, nRepCnt, nFlags);
}
Linia afx_msg void OnChar (UINT, UINT, UINT) i odpowiadająca jej pozycj a mapy komunikatów ON_WM_CHAR () przechwytuje wszelkie wciśnięcia klawiszy i kieruje je do wyspecjalizowanej funkcji obsługi. Wewnątrz funkcji obsługi OnCharO sprawdzamy, czy wpisany znak to cyfra lub myślnik. Jeśli tak, wywołujemy funkcję CEdit: :OnChar() w celu dopisania znaku do kontrolki. Jeśli komunikat nie spełnia kryteriów, jest ignorowany, więc do kontrolki nie jest dopisywany żaden znak.
Aby móc wyprowadzić własną kontrolkę, powinieneś postępować zgodnie z następującymi krokami. Po pierwsze, wyprowadź własną klasę z kontrolki, która funkcjonowaniem najbardziej przypomina funkcjonowanie kontrolki, jaką chcesz uzyskać. Po drugie, stwórz pozycję mapy komunikatów i zadeklaruj funkcję obsługi komunikatu, który chcesz przetwarzać. Ponieważ większość klas kontrolek jest wyprowadzonych z klasy cwnd, zajrzyj do dokumentacji tej klasy w systemie pomocy Visual Studia w celu przejrzenia pełnej listy komunikatów okien cwnd. Następnie do funkcji obsługi komunikatu wstaw kod służący do dostosowania działania kontrolki.
Przyciski z bitmapami
Oprócz dostosowywania działania kontrolki możesz zmienić także jej wygląd na ekranie. W dwóch następnych sekcjach zajmiemy się zmianą wyglądu przycisków oraz zmianą kolorów kontrolek.
MFC i Windows 95/98/NT udostępniają dwa różne sposoby tworzenia przycisków o innym wyglądzie. MFC udostępnia klasę CBitmapButton, wyprowadzoną bezpośrednio z klasy CButton. Windows 95/98/NT udostępnia dwa nowe style przycisków, BS_BITMAP oraz BS_ICON. Każda z tych metod umożliwia tworzenie przycisków o zmienionym wyglądzie.
Tworzenie własnego przycisku z użyciem klasy CBitmapButton jest bardzo proste. Musisz posiadać przynajmniej dwie bitmapy przedstawiające wygląd przycisku. Te obrazki reprezentują przycisk w momencie zwolnienia oraz wciśnięcia (na przykład przez klik-nięcie myszką). Możesz także dostarczyć dwie inne bitmapy, reprezentujące przycisk posiadający ognisko wprowadzania oraz przycisk wyłączony. Choć nie istnieją żadne ograniczenia co do wyglądu przycisku, jednak powszechną praktyką jest tworzenie
przycisków choć trochę przypominających wygląd zwykłych przycisków. Oznacza to, że przycisk wyłączony powinien być "wyszarzony", przycisk z ogniskiem wprowadzania powinien posiadać kropkowaną ramkę, zaś przycisk wciśnięty powinien być zagłębiony w tle. Bitmapy powinny obejmować także krawędzie przycisków. Gdy już stworzysz własne bitmapy, możesz dodać je do pliku zasobów aplikacji:
SENDU BITMAP sendu.bmp SENDD BITMAP sendd.bmp SENDF BITMAP sendf.bmp SENDX BITMAP sendx.bmp
Ostatnim krokiem jest stworzenie przycisku i załadowanie zasobów bitmap:
m_Send.Create("", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON |
BS_OWNERDRAW, TempRect, this, IDC_SEND); m_Send.LoadBitmaps("SENDU", "SENDD", "SENDF", "SENDK");
Zwróć uwagę na użycie stylu BS_OWNERDRAW w wywołaniu funkcji Create (). Musisz użyć tego stylu właśnie po to, aby przycisk mógł wyświetlać Twoje bitmapy. Oprócz tego, podane rozmiary przycisku powinny odpowiadać rozmiarom bitmap.
Jeśli piszesz aplikację mającą działać wyłącznie w środowiskach 32-bitowych, możesz zechcieć użyć któregoś z nowych stylów przycisków, BS_ICON lub BS_BITMAP. Użycie któregoś z tych stylów redukuje ilość pracy koniecznej do stworzenia własnego przycisku z bitmapą. Wadą jest to, że oba style są dostępne wyłącznie w Windows 95/98/NT.
BS BITMAP
Użycie stylu BS_BITMAP jest jeszcze prostsze niż użycie klasy CBitmapButton. Wystarcz}', że dostarczysz tylko jednej bitmapy przycisku. Windows samo zajmie się narysowaniem wersji wciśniętej, posiadającej ognisko wprowadzania lub wyłączonej. Tworzenie przycisku z użyciem stylu BS_BITMAP wygląda tak:
hBmp = ::LoadBitmap(AfxGetInstanceHandle(), "SEND");
m_Send.Create("", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON i BS_BITMAP, TempRect, this, IDC_SEND);
m_Send.SetBitmap(hBmp);
Bitmapą nie obejmuje krawędzi przycisku. Stanowi to kolejną zaletę użycia tego stylu. Jeśli w przyszłych wersjach Windows zmienią się krawędzie przycisków, stworzone przez Ciebie przyciski w dalszym ciągu będą wyglądały poprawnie. Ponieważ przyciski stworzone z użyciem klasy CBitmapButton zawierają krawędzie, w takim przypadku będziesz musiał stworzyć nowe bitmapy. Domyślnie bitmapy są wyśrodkowane względem przycisku. Aby zmienić to położenie, możesz użyć stylów z tabeli 12.13.
W momencie zniszczenia obiektu CBitmapButton bitmapy przycisku są niszczone automatycznie. Gdy używasz stylu BS_BITMAP, musisz usunąć bitmapę samodzielnie:
::DeleteObject(hBmp);
Tabela 12.13. Stałe określające położenie bitmapy przycisku
Styl
Opis
BS_TOPWyrównuje bitmapę do górnej krawędzi przycisku.

BS_BOTTOMWyrównuje bitmapę do dolnej krawędzi przycisku.

BS_CENTERWyśrodkowuje bitmapę w poziomie.

BS_VCENTERWyśrodkowuje bitmapę w pionie.

BS_LEFTWyrównuje bitmapę do lewej krawędzi przycisku.
BS_ RIGHTWyrównuje bitmapę do prawej krawędzi przycisku.


BS ICON
Użycie stylu BS_ICON wygląda podobnie do użycia stylu BS_BITMAP. Jedyna różnica polega na tym, że styl BS_ICON wiąże się z użyciem zasobu ikony. Poniższy fragment kod ilustruje sposób tworzenia przycisku korzystającego ze stylu BS_ICON:
m_Send.Create("", WS_VISIBLE l WS_CHILD | BS_ ICON, TempRect, this, IDC SEND);
m_Send.Set!con(AfxGetApp()->LoadIcon("SEND"));

Jedyną wadą korzystania z ikon jest ograniczenie rozmiarów przycisku do maksymalnego rozmiaru ikony, czyli 48 x 48 pikseli. Jednak przyciski tworzone z użyciem stylu BS_ICON mają jedną interesującą właściwość, której brakuje przyciskom ze stylem BS_BITMAP. Chodzi mianowicie o możliwość użycia "przezroczystego" koloru. Dzięki temu przyciski BS_ICON dostosowują się do zmian kolorów systemowych. Z drugiej strony, po zmianie kolorów systemowych przyciski klasy CBitmapButton mogą wyświetlać brzydkie kolorowe prostokąty.
Zmiana koloru kontrolki
Jednym z największych braków w projektach kontrolek jest brak funkcji składowych służących do zmiany koloru kontrolki. Za pomocą funkcji SetFont () można zmienić czcionkę kontrolki, nie istnieje jednak odpowiednia funkcja służąca zmianie koloru, na przykład SetColor ().
Używając MFC masz do dyspozycji dwa sposoby zmiany koloru kontrolki. Oba wykorzystują fakt, że przed odmalowaniem się kontrolka wysyła do okna nadrzędnego komunikat WM_CTLCOLOR. Ten komunikat zawiera uchwyt kontekstu urządzenia używanego do namalowania kontrolki. Ponieważ mamy dostęp do kontekstu urządzenia, możemy wywołać funkcje składowe takie jak CDC: : setTextColor () czy CDC: : setBkColor () w celu zmiany kolorów kontrolki. Uzbrojony w tę wiedzę możesz napisać funkcję obsługi komunikatu wybierającą inne kolory. Funkcja obsługi musi zwracać uchwyt pędzla (HBRUSH), który zostanie użyty przez kontrolkę do namalowania swojego tła. Prototyp takiej funkcji obsługi wygląda następująco:
afx_msg HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor)
MFC przekazuje do funkcji obsługi trzy wartości. Pierwsza z nich, poć, jest wskaźnikiem do kontekstu urządzenia dla kontrolki, pwnd jest wskaźnikiem do samej kontrolki, zaś ncticolor określa rodzaj komunikatu WM_CTLCOLOR powodującego wywołanie funkcji obsługi. Rodzaje tych komunikatów zostały zebrane w tabeli 12.14.
Tabela 12.14. Rodzaje komunikatów WM_CTLCOLOR
Wartość nCtlColor
Rodzaj kontrolki
CTLCOLOR STATIC
Statyczne kontrolki tekstowe, wszystkie przyciski z wyjątkiem zwykłych wciskanych przycisków, wyłączone lub przeznaczone tylko do odczytu kontrolki pola edycji, pole edycji wyłączonej rozwijanej listy.

CTLCOLOR_EDIT
Pole edycji oraz pole edycji rozwijanej listy.

CTLCOLOR_LOSTBOX
Kontrolki list oraz część listy w kontrolkach rozwijanych list.

CTLCOLOR_BTNZwykły wciskany przycisk - w Windows 95 przetwarzanie tego komunikatu nie daje efektu.

CTLCOLOR_SCROLLBAR
Pasek przewijania.
CTLCOLOR_DLG
Okno dialogowe.
CTLCOLOR_MSGBOX
Okno komunikatu.



Poniższy fragment kodu ilustruje prostą funkcję obsługi komunikatu WLM_CTLCOLOR. Zakładamy przy tym, że m_Name jest kontrolką pola edycji, zaś m_brGrnBrush jest obiektem klasy CBrush.
HBRUSH CMainWnd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCt1Color)
{ if(m_Name.m_hWnd == pWnd->m_hWnd)
{
pDC->SetTextColor(RGB(255, 255, 255)}; pDC->SetBkColor(RGB(255, O, 0));} return (HBRUSH) m_brGrnBrush;
}
CFrameWnd::OnCtlColor(pDC, pWnd, nCtlColor);
}
Ten kod zmienia kolor kontrolki m_Name na biały tekst z czerwonym tłem. Taki jest jeden ze sposobów zmiany kolorów kontrolki. Jedyną wadą korzystania z tej techniki jest to, że okno nadrzędne jest odpowiedzialne za zmianę koloru każdej z kontrolek. Byłoby lepiej jeśli moglibyśmy wbudować to zachowanie wewnątrz samej kontrolki. W ten sposób każda z kontrolek stałaby się osobną jednostką, łatwo nadającą się do ponownego wykorzystania. Ponieważ przed odmalowaniem się kontrolki wysyłają komunikaty swoim oknom nadrzędnym, potrzebujemy jakiegoś sposobu przekazania tego komunikatu z powrotem do tego okna potomnego (kontrolki), z którego pochodzi komunikat.
MFC dostarcza takiego mechanizmu. Używając makra mapy komunikatów ON__WM_ CTLCOLOR_REFLECT, możemy spowodować, że okno nadrzędne będzie przekazywać wszystkie nieprzetworzone komunikaty WM_CTLCOLOR z powrotem do tych okien potomnych, z których pochodziły te komunikaty. Teraz możemy stworzyć dostosowane
Rozdział 12. Kontrolki
313
kontrolki zmieniające swój kolor bez wsparcia ze strony okna. Poniższy fragment kodu opisuje kontrolkę zmieniającą swój kolor tła, tekstu oraz tła tekstu:
class CMyStatic : public CStatic
{
public:
CMyStatic(); protected:
CBrush m_Brush;
afx_msg HBRUSH CtrlColr(CDC*, UINT);
DECLARE MESSAGE MAP()
}
BEGIN_MESSAGE_MAP(CMYsTATIC,csTATIC)
ON_WM_CTLCOOR_REFLEC()
END_MESSAGE_MAP()CMyStatic: : CMyStatic()
{
m_Brush.CreateSoliBrush)RGB(255, 255, 255));
}
HBRUSH CMyStatic::CtrlColr(CDC *pDC, UINT nCtlColor)
{

pDC->SwtTextColor(RGB(nRed.nGreen,nBlue));
pDC->SetBkColor(RGB(255, 0, 0));
retrun (HBRUSH) m_Brush;
}
Podsumowanie
W tym rozdziale nauczyłeś się używać podstawowych kontrolek stanowiących część systemu operacyjnego Windows. Poznaliśmy proces tworzenia kontrolki oraz znamy różnice pomiędzy rozmieszaniem kontrolek w oknach dialogowych i w zwykłych oknach. Następnie skupiliśmy się na poszczególnych rodzajach kontrolek i sposobach ich użycia. Znamy unikalne style oraz ich znaczenie przy tworzeniu różnych odmian kontrolek. Na koniec przyjrzeliśmy się kilku zaawansowanym zagadnieniom programowania kontrolek i nauczyliśmy się dostosowywać kontrolki do prawie każdej sytuacji.
W tym momencie nie powinieneś mieć już kłopotów z użyciem kontrolek we własnych projektach. Gdy nauczysz się czegoś więcej na temat programowania okien innego rodzaju - dialogów i okien modelu dokument-widok - będziesz mógł w jeszcze większym stopniu wykorzystać swoją wiedzę o programowaniu kontrolek.
W tym rozdziale nie omawialiśmy tzw. standardowych kontrolek Windows. Zajmiemy się nimi dopiero w rozdziale 24.

Wyszukiwarka

Podobne podstrony:
12 H Marcuse Nowe formy kontroli Człowiek jednowymiarowy
12 Technologia i kontrola zagęszczenia gruntów w nasypach drogowychid301
248 12
Biuletyn 01 12 2014
12 control statements
Rzym 5 w 12,14 CZY WIERZYSZ EWOLUCJI
12 2krl

więcej podobnych podstron