07 Stosowanie wskaźników postępu


Rozdział 7
Stosowanie wskaźników postępu, pasków
przewijania, suwaków oraz obiektów
pobierających datę i godzinę
Użycie wskaźnika postępu do wyświetlania stopnia wykonania zadania
Zastosowanie suwaków oraz pasków przewijania do ustalania pozycji
wewnątrz obszaru
Używanie obiektów pobierających dane czasowe
Obiekty zorientowane na zakres wartości
Programy często muszą umożliwiać użytkownikowi określenie pewnego zakresu spośród
dostępnych wartości, zdefiniować punkty graniczne tego zakresu, a także wskazywać stopień wykonania
zadania zleconego przez użytkownika. Zakresy, które określać ma użytkownik, mogą reprezentować
różne rodzaje jednostek i danych, takie jak jednostki numeryczne, data, godzina, a także jednostki
specyficzne dla danej aplikacji, jak metry lub mile. Visual C++ 6 dostarcza nam szerokiego wyboru
obiektów tego rodzaju, które możemy umieszczać w aplikacjach za pomocą edytora zasobów i
dostępnego w nim paska narzędziowego Controls. Biblioteka MFC zapewnia dostęp do mechanizmów
umożliwiających aplikacji podejmowanie interakcji z użytkownikiem. Rozdział niniejszy mówi o tego
rodzaju obiektach sterujących i objaśni sposoby integracji tych mechanizmów z aplikacją.
Użycie wskaźnika postępu
Wskaźnik postępu jest zwykle obiektem umożliwiającym użytkownikowi kontrolę stopnia
wykonania zleconego zadania. Ma on postać okna, stopniowo wypełnianego przez niebieski pasek lub
ciąg prostokątów. Jego przykładowy wygląd widzimy na rysunku 7.1. Obiekt tego typu możemy
wykorzystać również w innych dziedzinach. Możemy się nim posłużyć w celu reprezentowania wartości
z określonego zakresu. Przykładowo, rysunek


150 Poznaj Visual C++ 6
7.2 przedstawia sposób wykorzystania wskaźników postępu jako wskaźników korektora
graficznego, spotykanego w sprzęcie Hi-Fi.
OK
Caneel
Rysunek 7.1. Typowe zastosowanie wskaźnika postępu do identyfikacji stopnia wykonania zadania
Caneet
l.
Rysunek 7.2. Zespół wskaźników postępu wykorzystanych do odwzorowania wybranych wartości w
danym zakresie
Umieszczenie wskaźnika postępu w oknie dialogowym
Wskaźnik postępu możemy umieścić w oknie dialogowym w sposób analogiczny do
wszelkich innych obiektów sterujących: przeciągając go z paska narzędziowego Controls,
wywoływanego podczas pracy z edytorem zasobów i ustalając jego pozycję wewnątrz okna.
Po umieszczeniu wskaźnika, możemy także zmieniać jego wymiary. Na rysunku 7.3 ikona
wskaźnika postępu jest wskazana myszą i widoczny jest również "dymek" opisujący znaczenie
ikony.
Kopiowanie i wklejanie obiektów sterujących
Obiekty sterujące każdego typu mogą być kopiowane do schowka, a następnie wklejane z
niego do szablonu okna. Do skopiowania używa się skrótu klawiaturowego CtrI+C, do
wklejania natomiast Ctrl+V. Wklejona kopia obiektu zachowuje wymiary i cechy
pierwowzoru.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 151

Rysunek 7.3. Umieszczenie wskaźnika postępu w oknie dialogowym za pomocą edytora zasobów
Na rysunku tym widzimy również okno właściwości Progress Properties z otwartą kartą Styles.
Okno to możemy wywołać zaznaczając wskaźnik umieszczony na szablonie, a następnie naciskając
klawisze Alt+Enter lub też wybierając pozycję Properties z otwartego kliknięciem prawego klawisza
myszy menu skrótów.
Okno właściwości na karcie Generał umożliwia nam zmianę identyfikatora ID przypisanego
wskaźnikowi. Powinniśmy zmienić ten identyfikator na jak najjaśniej opisujący zastosowanie wskaźnika
oraz ustawić pozostałe jego parametry według potrzeb.
Karta Styles pozwala na dokonanie zmian wizualnych cech wskaźnika poprzez zaznaczenie lub
usunięcie zaznaczenia następujących opcji:
Border. Jeśli zaznaczymy tę opcję, wokół wskaźnika wyświetlana będzie wąska czarna ramka.
Vertical. Zaznaczenie tej opcji spowoduje zmianę orientacji wskaźnika, z poziomej na pionową.
Smooth. Jeżeli wybierzemy tę pozycję, wskaźnik będzie miał formę paska, zamiast oddzielnych
prostokątów.
Domyślne ustawienia stylu wskaźnika postępu
Jeśli nie zostaną dokonane zmiany opcji stylu wskaźnika postępu, domyślnie ustalonymi będą opcje:
Border, Vertical oraz Smooth.
Przykład pokazany na rysunku 7.1 prezentuje sposób wykorzystania wskaźnika postępu w aplikacji
utworzonej za pomocą AppWizard, w oparciu o architekturę okna dialogo-


152_____________________________________Poznaj Visual C++ 6
wego. Wartość wskazywana jest inkrementowana za każdym razem, gdy użytkownik kliknie przycisk
Step It. Chcąc wykonać ten przykład, musimy zacząć od wywołania AppWizard i utworzenia w nim
aplikacji o budowie okna dialogowego, a następnie umieścić w nim wskaźnik postępu, jak widać na
rysunku 7.13. Wskaźnik ten w naszym przykładzie otrzyma identyfikator IDC_MY_PROGRESS, a przycisk
widniejący po jego lewej stronie IDC_STEPIT. Kolejne punkty pokażą jak połączyć klasę MFC ze
wskaźnikiem i jak odświeżać jego wskazania.
PATRZ TAKŻE
Więcej szczegółów na temat edycji okien dialogowych i właściwościach obiektów sterujących znajduje
się w rozdziale 3.
Przypisanie zmiennej do wskaźnika postępu
Przypisania zmiennej do wskaźnika postępu dokonać możemy za pomocą CIassWi-zard. Wskaźniki
tego rodzaju są obsługiwane przez klasę CProgressCtrI.
Przypisanie zmiennej składowej do wskaźnika postępu
1. W edytorze zasobów zaznacz wskaźnik, któremu będziesz przypisywać zmienną.
2. Naciśnij Ctri+W lub wybierz z menu View pozycję uruchamiającą CIassWizard. W jego otwartym
oknie zaznacz kartę Member Yariables. Upewnij się, że została wybrana właściwa klasa; w tym
przypadku CProgressDIg.
3. Poprzez dwukrotne kliknięcie pozycji IDCJMY PROGRESS lub kliknięcie przycisku Add Variable
otwórz okno dialogowe Add Member Variable.
4. Jako nazwę nowej zmiennej w polu Member Variable Name wpisz: m_MyProgress.
5. Zauważ, że lista Category wyświetla pozycję Control, natomiast Variable Type wskazuje
CProgressCtri. Są to jedyne dostępne opcje w przypadku wskaźnika postępu.
6. Kuknij OK w celu zatwierdzenia nowej zmiennej i zamknięcia okna Add Member Variable. Nowa
zmienna powinna być teraz widoczna na liście Control IDs.
7. Kliknij OK, by zamknąć CIassWizard i dodać nową zmienną do wybranej klasy.
Gdy posiadamy już zmienną przypisaną do wskaźnika, manipulując jej zawartością możemy
powodować zmiany w jego wskazaniach. Jest to opisane w następnym punkcie.
Wskaźnik postępu jest nowym rodzajem obiektu sterującego
Ponieważ wskaźnik postępu to jeden z nowych rodzajów obiektów sterujących, użytkownik musi
pracować w systemie Windows 95/NT 3.51 (lub wersji późniejszej), aby móc stosować te obiekty.


rM i ru. i Mrv.c
Bardziej szczegółowe wyjaśnienie przypisywania zmiennych składowych znajduje się w rozdziale 10.
Manipulowanie i zmiany wskazań wskaźnika postępu
Operacji tych dokonywać możemy wywołując metody klasy cprogressCtrl, wykorzystującej nową
zmienną. Wskaźnik postępu operuje na pewnym zakresie wartości całkowitych, które reprezentują pusty
wskaźnik (0% wykonania) i na przeciwległym końcu, wskaźnik wypełniony (100% wykonania).
Wewnątrz tego zakresu znajdują się wartości reprezentujące aktualny stan wykonania zadania, co
determinuje stopień wypełnienia wskaźnika. Możemy również określić wartość kroku, o którą
następować będzie inkrementacja wskazań w momentach wywoływania funkcji składowej s tęp 11 ().
Używanie 32-bitowych zakresów wartości we wskaźnikach postępu
Funkcja SetRange () ograniczona jest do posługiwania się tylko 16-bitowymi wartościami. Oznacza to,
iż wartości przez nią wykorzystywane mieszczą się w zakresie od -32 768 do 32 767. Jeśli zadanie
wymaga większego zakresu tych wartości, użyć należy funkcji SetRange32 (), posługującej się
wartościami 32-bitowymi, czyli od -2 147 483 648 do 2 147 483 647.
Ustalanie zakresu wartości dla wskaźnika postępu
Powinniśmy teraz ustalić zakres wartości, który wykorzystywany będzie przez wskaźnik. Możemy
to osiągnąć wywołując funkcję składową SetRange (), podając jej dwa parametry w postaci wartości
całkowitych, które określać będą wartość najniższą i najwyższą. Oczywiście wartości te powinny
korespondować z zadaniem, którego stopień wykonania będzie identyfikował wskaźnik. Przykładowo,
gdy dokonujemy obliczeń liczb pierwszych z zakresu od 3000 do 7000, zakres wartości dla wskaźnika
postępu powinien być ograniczony tymi właśnie dwoma liczbami.
Zakres ten określać będziemy zazwyczaj w momencie inicjalizacji wskaźnika, jednakże możemy go
zmienić w każdym momencie. Najlepszym miejscem na inicjalizację tego obiektu jest końcówka zapisu
funkcji okna dialogowego OninitDialog ().
W przykładowym programie Progress wartościami granicznymi dla wskaźnika będą O i 10. Liczba
O reprezentować będzie całkowicie pusty wskaźnik, 10 natomiast wypełniony. Poprzez kliknięcie karty
ClassView, a następnie rozwinięcie kolejnych pozycji, uzyskamy dostęp do wszystkich klas
wykorzystanych w programie, ich funkcji składowych oraz zmiennych. Skoro aplikację zbudowaliśmy
na bazie okna dialogowego i nazwaliśmy ją Progress, w panelu ClassView powinna być obecna klasa
cprogressDlg, która służy do obsługi głównego okna dialogowego aplikacji. Powinniśmy widzieć tam
również funkcję składową tej klasy, OninitDialog (), której zapis ujrzymy w oknie edytora po dwukrot-


154 _____ ____ __ Poznaj Visual C++ 6
nym jej kliknięciu. Inicjalizacji zakresu wartości wskaźnika dokonać możemy wpisując
poniższą linię na samym końcu zapisu funkcji, tuż przed rozkazem powrotu. Linia, którą
musimy wpisać, wygląda następująco:
m_MyProgress.SetRange(O, 10);
Od tego momentu zakres wartości wskaźnika zawierał się będzie pomiędzy O a 10.
Mamy do dyspozycji jeszcze jedną funkcję GetRange (), która pobiera dwie wartości
poprzez odwołania i ustawia je jako wartość minimalną i maksymalną. Możemy wykorzy-
stywać tę funkcję do dokonywania zmian aktualnego zakresu wartości.
PATRZ TAKŻE
Więcej informacji o inicjowaniu okien dialogowych znajduje się w rozdziale 6.
Przykładowa aplikacja Fire
Przykładowa aplikacja Fire demonstruje współdziałanie wskaźnika postępu z suwakiem. Aplikację
można pobrać z dysku MSDN CD bądź ściągnąć ze strony WWW pod
adresem:www.microsoft.com/msdn.
Ustalanie pozycji wskaźnika
Gdy ustaliliśmy już zakres wartości wskaźnika, możemy określić również wyświetlaną
wartość poprzez wywołanie funkcji składowej SetPos O . Jej użycie spowoduje ustawienie
wartości identyfikowanej aktualnie przez wskaźnik na wartość równą przekazanej jako
argument i odświeżenie wskazań wizualnych. Jeśli przekazana do SetPos ((wartość będzie
większa od maksymalnej, wskaźnik zostanie narysowany jako całkowicie wypełniony, gdy zaś
mniejsza, wskaźnik nie będzie wskazywał nic.
W programie Progress możemy posłużyć się funkcją SetPos () do ustalenia wartości
początkowej na 0. Uczynimy to poprzez wpisanie kolejnej linii, tuż pod poprzednią. Wpi-
szemy:
m_MyProgress.SetPos(0) ;
Taka deklaracja nie jest co prawda konieczna, gdyż wskaźnik postępu automatycznie
przyjmuje jako wartość początkową minimalną wartość określonego zakresu. Możemy jednak
spowodować ustalenie wskazania początkowego na 50%, co wymaga zmiany ostatnio
wpisanej linii na:
m_MyProgress.SetPos(5) ;
Zamiast poprzedniej metody, określającej wskazanie początkowe jako wartość absolutną
wewnątrz danego zakresu, możemy wskazanie ustalić za pomocą wartości relatywnej,
używając w tym celu funkcji OffsetPos (). Gdy podamy tej funkcji jako parametr


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 155
pewną wartość, zostanie ona dodana do obecnie wskazywanej, a wskaźnik zostanie odry-sowany tak, by
odzwierciedlić aktualną wartość.
Ustalanie i używanie wartości kroku
Krok inkrementacji wartości wskazań może być ustalony automatycznie. Możemy jednak wpłynąć
na wartość, o którą będzie się przesuwał wskaźnik postępu po każdym sygnale do odświeżenia wskazań.
Funkcją, która nam to umożliwi, jest SetStep (). Jako argument możemy podać jej wartość inkrementacji.
Po jej zaimplementowaniu będziemy mogli powodować zmiany wskazań poprzez wywołania funkcji
Steplt(), bez żadnych parametrów. W programie Progress ustalmy wartość inkrementacji na l,
umieszczając jeszcze jedną linię kodu na końcu OninitDialog ();
m_MyProgress.SetStep(l) ;
Teraz możemy już dodać funkcję obsługi dla przycisku Step 11. Po jego dwukrotnym kliknięciu w
edytorze zasobów poproszeni zostaniemy o zatwierdzenie nazwy nowej funkcji OnStepit (), a gdy go
dokonamy, dopisany zostanie kod inicjujący nową funkcję:
void CProgreeDlg::OnStepIt()
( m_MyProgress.Step!t() ;
}
Po skompilowaniu i uruchomieniu programu za pomocą przycisku Step it będziemy zwiększać
wartość wyświetlaną na wskaźniku, powiększając ją za każdym razem o zadaną wartość inkrementacji.
Gdy wskazanie osiągnie wartość maksymalną, wskaźnik zostanie opróżniony i cała operacja będzie
mogła zostać powtórzona.
Stosowanie pasków przewijania
Paski przewijania są częstym elementem ramki okna, co pozwala przesuwanie widoku, który
fizycznie nie może zostać wyświetlony w obrębie. Zagadnienie to omówione jest szerzej w rozdziale 18.
Paski mogą być jednakże zdefiniowane jako odrębne obiekty, służące do poruszania się w określonym
obszarze. Do zadań tych częściej stosuje się obiekty sterujące w postaci suwaków. Musimy jednak
poznać zasady funkcjonowania pasków przewijania, gdyż suwaki wykorzystują wiele ich cech
funkcjonalnych.
PATRZ TAKŻE
4 Więcej informacji o wykorzystaniu pasków przewijania znajduje się w rozdziale 18.
Dodawanie pasków przewijania do okna dialogowego
Edytor zasobów umożliwia wyposażenie okna dialogowego w paski przewijania, które pobierane są
z paska narzędziowego Controls. Na palecie tej znajdziemy dwie ikony,


156_____________________________________Poznaj Visual C++ 6
symbolizujące paski przewijania poziome oraz pionowe (rysunek 7.4). W tradycyjny sposób możemy
umiejscowić takie paski na szablonie okna dialogowego, zwiększyć ich wymiary oraz korzystając z okna
dialogowego właściwości Scrollbar Properties (wywoływanego przez naciśnięcie Alt+Enter po
zaznaczeniu pasków), nadać im odpowiednie identyfikatory.
^ H Aa ab|
Q o lx c
1ż IH EB j i
i |ni7| JxSLlEa_J_________.
^ iHonzontalScrollBarI
EJ R= C3"
Rysunek 7.4. Dodawanie pasków przewijania z paska narzędziowego Controls
Na karcie Styles dostępnej w oknie właściwości pasków dokonać możemy ustalenia tylko jednego
parametru, czyli wyrównania paska. Parametr ten określony jest jako Align i daje nam do dyspozycji trzy
możliwości:
None. Ustawienie domyślne, umieszczające pasek przewijania w takim położeniu i z takimi
wymiarami, jak na szablonie okna dialogowego.
Top/Left. Przy tym wyborze pasek przewijania otrzymuje wymiary zgodne ze standardowo
stosowanymi w systemie Windows (niezależnie od ustawień na szablonie) i zostaje wyrównany do
lewej i górnej krawędzi paska umieszczonego na szablonie okna.
Bottom/Right. Podobnie jak poprzednio, z tą różnicą, że pasek wyrównany jest do prawej i dolnej
krawędzi wzorca na szablonie
PATRZ TAKŻE
Więcej informacji na temat edycji okien dialogowych i ustalania właściwości obiektów sterujących znajduje się w
rozdziale 3.
Przypisanie zmiennych paskom przewijania
Czynność tę możemy wykonać w taki sam sposób jak w przypadku wskaźnika postępu, o czym
mówiliśmy wcześniej w tym samym rozdziale. Jedyną różnicą jest ustalenie kategorii oraz typu zmiennej
Variable Type, co wówczas następowało w 5 kroku. Pasek przewijania może być wyłącznie obiektem
typu Control, podczas gdy obiekty w postaci suwaków pozwalają na stosowanie typów zarówno
Control jak i Value.


Stosowanie wskaźników postępu, pasków przewijania, suwaków. 157
Jeśli wybierzemy opcję Value, typ zmiennej zostanie ustalony jako int. Zmienna tego typu
przypisana do obiektu suwaka zostaje wpisana do wybranej klasy. Zawartość tej nowej zmiennej
składowej będzie zmieniała się w zależności od położenia suwaka w sposób podobny do stosowanego w
przypadku obiektów edycyjnych, co omówione zostanie w punkcie "Dodawanie zmiennych składowych,
przechowujących dane okna dialogowego", w rozdziale 10.
Jeżeli natomiast wybierzemy jako kategorię nowej zmiennej pozycję Control, jako jej typ zostanie
automatycznie wskazana klasa cscrollBar.
PATRZ TAKŻE
Więcej szczegółów dotyczących przypisywania zmiennych składowych znajduje się w rozdziale 10.
Kategorie przypisywanych zmiennych
Zawsze, gdy typ zmiennej przypisywanej do obiektu sterującego ustalony jest jako Control, właściwą
dla niej klasą będzie cscrollBar, wywodząca się z klasy CWnd. Oznacza to, że wszelkie operacje
przeprowadzane na oknie, takie jak zmiana wymiarów lub położenia, będą się odbywały przy użyciu
przypisanej zmiennej składowej. Przykład takiej sytuacji znaleźć można w punkcie rozdziału 18.
Inicjalizowanie pasków przewijania
Paski przewijania możemy inicjalizować wewnątrz funkcji OninitDialog (), tak jak w przypadku
wskaźników postępu. Paski te również posiadają określony zakres działania, który określać możemy za
pomocą funkcji SetScroilRange () z klasy cscrollBar, podając jej wartości minimalną i maksymalną jako
argumenty. Możliwe jest również umieszczenie jako trzeciego argumentu, znacznika wywołującego
przerysowywanie (domyślnie jest przyjmowana wartość TRUE, jeśli nie podamy tego parametru).
Ograniczenia działania pasków przewijania
Zakres wartości, jakimi posługują się paski przewijania, jest ograniczony. Określać go można
używając liczb całkowitych (int) przestrzegając zasady, iż różnica pomiędzy wartością minimalną i
maksymalną nie może przekroczyć 32767.
Przykładowo, jeśli przypisaliśmy dwie zmienne składowe klasy cscrollBar, nazwane m_ScrollBarl
oraz m_ScrollBar2 umieszczonym w oknie dialogowym paskom przewijania pionowego i poziomego,
to ich inicjalizację możemy przeprowadzić umieszczając na końcu funkcji OninitDialog () następujące
dwie linie kodu:


158_____________________________________Poznaj Visual C++ 6
m_ScrollBarl.SetScrollRange(O, 100) ;
m_ScrollBar2.SetScrollRange(O, 200) ;
W ten sposób zakres wartości dla paska pionowego zawiera się pomiędzy O a 100, natomiast
poziomego w granicach O do 200. Ponieważ nie zapisaliśmy trzeciego parametru, domyślnie paski będą
przerysowywane (moglibyśmy wpisać wartość FALSE, aby tę czynność zablokować). Funkcja
GetScrolIRange () może nam posłużyć do pobierania wartości granicznych dla zakresów z
wykorzystaniem wskaźników do właściwych wartości:
int nMin, nMax;
m ScrollBar2.GetScrolIRange(&nMin, &nMaxO;
TRACĘ("Rangę = (%d to %d)\n", nMin, nMax);
Gdybyśmy chcieli wyłączyć widok strzałek na końcach paska przewijania, możemy to zrealizować
poprzez wywołanie funkcji paska EnableScrollBar(), przekazując jej parametr w jednej z postaci
wymienionych w tabeli 7.1.
Tabela 7.1. Wartości parametru podawanego funkcji EnableScrollBar () w celu wyłączenia widoku
strzałek
Wartość Opis
ESB_DI SABLE_BOTH Wyłącza widok strzałek na obu końcach paska
ESB_DISABLE_LTUP Wyłącza widok lewej lub górnej strzałki (w zależności od orientacji paska
przewijania)
ESB_DISABLE_RTDN Wyłącza strzałki po przeciwnych w stosunku do poprzedniej pozycji stronach
paska.
ESB_ENABLE_BOTH Włącza widok obu strzałek - jest to domyślna wartość, jeśli żaden parametr nie
zostanie podany funkcji EnableScrollBar ()
Podobnie jak w wypadku wskaźników postępu, również i tutaj możemy określić początkowe
położenie uchwytu do przesuwania wewnątrz paska. Osiągniemy to wywołując funkcję paska
przewijania SetScrollPos (), przekazując jej parametr w postaci liczby całkowitej zawartej wewnątrz
określonego wcześniej zakresu wartości. Korespondująca z tą funkcją inna, GetScrollPos (), zwraca
aktualne położenie uchwytu przesuwającego.-
Jeśli chcemy ustawić rozmiar tego uchwytu na wartość wynikającą z pewnej proporcji w stosunku
do całego zakresu (na przykład, by równał się jednej stronie tekstu), wyznaczyć go możemy za pomocą
funkcji SetScrollinfo (), podając jej jako parametr wskaźnik do struktury SCROLLINFO. Struktura ta w
dużej mierze duplikuje działanie funkcji służących do określania zakresu wartości paska i pozycji
początkowej uchwytu przesuwającego.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 159
Struktura SCROLLINFO
GetScroliinfo () oraz SetScrollInfo () są dwiema korespondującymi funkcjami, których można użyć do
zapisywania wewnątrz struktury SCROLLINFO danych dotyczących pasków przewijania. GetScroliinfo
() wymaga podania dwóch parametrów - pierwszy jest wskaźnikiem struktury, w której będą zapisane
dane, drugi parametr natomiast stanowi maskę bitową wartości znaczników SCROLLINFO, które należy
pobrać. Wartości te mogą być zestawem SIF_RANGE, SIF_POS, SIF_TRACKPOS oraz SIF_PAGE,
ustalającym wartość zmiennych składowych SCROLLINFO odpowiednio na: nMin, nMax, nPos,
nTrackpos i nPage. Znacznik SIF_ALL dokonuje ustawienia wszystkich zmiennych.
Związaną z tym zagadnieniem składową zmienną struktury SCROLLINFO jest nPage. Jej wartość
powinniśmy określić liczbą całkowitą, stanowiącą rozmiar strony w proporcji do całego dokumentu czy
też zakresu działania. Posłużyć się możemy przykładem programu do edycji tekstu. Zakres działania
paska przewijania, reprezentujący całość dokumentu ustalić możemy w granicach od O do 100, a ekran
może wyświetlać tylko jedną stronę tekstu. Dla dwustronicowego dokumentu zatem zmiennej nPage
moglibyśmy nadać wartość 50, co powodowałoby wyświetlanie jednej strony jako połowy dokumentu. Z
kolei dla dokumentu o objętości 20 stron wartość zmiennej powinna wyrażać się liczbą 5, co determinuje
podział dokumentu na 20 widoków (1/20 zakresu od O do 100).
Musimy jednocześnie określić wartość zmiennej f Ma s k na SIF_PAGE w celu powiadomienia
funkcji SetScrollInfo ()o zatwierdzeniu zmiennej nPage, a także ustalić rozmiar struktury w zmiennej
cbSize (jest to normalne działanie w strukturach Win32). Przykładowo, aby określić rozmiar
przesunięcia widoku dokumentu za pomocą uchwytu o 30, powinniśmy za wywołaniem funkcji
SetScrolIRange () umieścić następujący kod inicjalizujący:
SCROLLINFO s i;
si.cbSize = sizeof(SCROLLINFO);
si.nPage = 30;
si.fMask = SIF_PAGE;
m_ScrollBarl.SetScrollInfo(&si) ;
Po uruchomieniu aplikacji z tym wpisem rozmiar uchwytu pionowego będzie wyraźnie większy od
domyślnie zwymiarowanego uchwytu na pasku przewijania poziomego.
PATRZ TAKŻE
Więcej informacji o stosowaniu makra TRACĘ znajduje się w rozdziale 27.


160_____________________________________Poznaj Visual C++ 6
Obsługa powiadomień pasków przewijania
Zawsze, gdy użytkownik klika przycisk strzałki, naciska klawisz PgDn/PgUp lub też
klawisze strzałek na klawiaturze, pasek przewijania wysyła powiadomienie do okna rodzica.
Powiadomienia te są komunikatami systemu Windows: WM_HSCROLL w wypadku paska
poziomego oraz WM_VSCROLL w przypadku paska pionowego. Funkcje obsługujące te komu-
nikaty możemy umieścić w programie korzystając z okna dialogowego New Windows
Messages/Events. Klasa głównego okna dialogowego aplikacji będzie obsługiwała okno
rodzica w zakresie wykorzystywania pasków przewijania, zatem funkcja obsługi powiadomień
również powinna być w niej zlokalizowana. Dla przykładu: jeśli aplikacja oparta o okno
dialogowe ma nazwę Scroll, klasa dla tego okna będzie nosiła nazwę cscroliDig. Klasa ta
powinna zostać wskazana na liście Ciass or Object to Handle znajdującej się w oknie
dialogowym New Windows Messages/Events (jeżeli ktoś ma z tym kłopoty, może posłużyć
się procedurą opisaną w punkcie "Dodawanie funkcji obsługi OnHScroll() w celu
przechwytywania komunikatu WM_HSCROLL lub WM_VSCROLL"; odwołania do klasy
widoku trzeba zastąpić odwołaniami do klasy głównego okna dialogowego.
Dołączenie funkcji obsługi komunikatu WM_VSCROLL, spowoduje dopisanie przez
CIassWizard następującego kodu:
void CScrollDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
( // TODO: dodaj tu własny kod obsługi komunikatów i/lub
przywołaj CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}
Funkcja obsługi komunikatu WM_HSCROLL jest identyczna z powyższą w definicji i
strukturze, oprócz nazwy, którą jest w tym wypadku OnHScroll (). Jeśli okno wyposażymy w
paski przewijania w obu płaszczyznach, będziemy musieli dołączyć dwie osobne funkcje
obsługi powiadomień.
Ujemne wartości określające pozycję paska przewijania
Jeśli początkowo ustawiony zakres wartości umożliwia posługiwanie się wartościami
ujemnymi, możliwe, iż nPos wyrażona jest właśnie taką wartością. Ponieważ jednak jest ona
przekazywana jako UINT (wartość całkowita nieoznaczona), do reprezentacji wartości
ujemnych użyte zostaną większe wartości dodatnie. Jeśli zostanie stwierdzona taka sytuacja,
należy zmienić typ zmiennej nPos na int, co pozwoli jej reprezentować wartości ujemne.
Pierwszym parametrem podawanym funkcji (nSBCode) jest znacznik identyfikujący
rodzaj wykonanej przez użytkownika czynności. Chodzi tu o to, w jaki sposób dokonał on
przesunięcia widoku na ekranie (czy przesunął go za pomocą uchwytu, skorzystał z
przycisków strzałek na pasku, czy też nacisnął klawisz Page Up lub Page Down). War-


Stosowanie wskaźników postępu, pasków przewijania, suwaków...____________161
tości, które znacznik ten może przybierać, opisane są w tabeli 7.2. Przede wszystkim określić musimy, o
który pasek nam chodzi (w omawianym wypadku funkcją obsługi będzie OnVScroll (), dla której klasą
bazową jest CDialog). Następnie za pomocą tego znacznika należy ustalić, w jaki sposób uchwyt
przesuwania ma zmienić swoje położenie. Jeśli nie określimy tego w sposób jednoznaczny w wywołaniu
funkcji SetScrollPos (), uchwyt po przesunięciu go przez użytkownika jak sprężyna powróci do
położenia początkowego!
Tabela 7.2. Wartości znacznika przekazywane poprzez parametr cSBCode do funkcji obsługi
Wartość znacznika Znaczenie





SB_THUMBTRACK
SB_THUMBPOSITION
SB_ENDSCROLL
SB_LINEUP SB_LINELEFT
SB_LINEDOWN
SB_LINERIGHT
SB_PAGEUP SB_PAGELEFT
SB_PAGEDOWN S B
PAGELEFT
Użytkownik przesunął uchwyt w określone położenie. Położenie to
odczytać można z drugiego parametru, npos
Użytkownik przeciągnął uchwyt w określone położenie, zwalniając
klawisz myszy. Położenie można pobrać z parametru nPos
Użytkownik zwolnił klawisz myszy po przesunięciu widoku za pomocą
przycisków strzałek lub kliknięciu wewnątrz paska przewijania (bez
użycia uchwytu)
Pozycja uchwytu zmniejsza się o jednostkę
Tak samo jak w przypadku SB_LINELEFT, lecz w odniesieniu do paska
poziomego
Pozycja uchwytu zwiększa się o jednostkę
Tak samo jak w przypadku SB_LINEDOWN, lecz w odniesieniu do paska
poziomego
Pozycja uchwytu zmniejsza się o jedną stronę, w proporcji do całego
dokumentu (wielkość zależna od wcześniejszych ustaleń)
Pozycja uchwytu zmniejsza się o jedną stronę, jak w poprzednim
przypadku, ale w zastosowaniu do paska poziomego
Pozycja uchwytu zwiększa się o jedną stronę, w proporcji do całego
dokumentu (wielkość zależna od wcześniejszych ustaleń)
Pozycja uchwytu zmniejsza się o jedną stronę, jak w poprzednim
przypadku, ale w zastosowaniu do paska poziomego





Możemy sprawdzić, który z pasków przewijania wysłał komunikat powiadamiający.
Wykorzystać do tego należy trzeci parametr funkcji OnVScroll (). Jest on wskaźnikiem paska,
w którym zaszły zmiany. Prawdopodobnie najlepszą i najprostszą zarazem metodą
zidentyfikowania paska jest użycie jego identyfikatora ID. Możemy to osiągnąć wywołując
funkcję GetDlgCtrllD() z użyciem wskaźnika pScrollbar. Funkcja ta zwraca identyfikator
przypisany paskowi, który następnie zostaje porównany z identyfikatorami pasków, aby
określić, czy i w jaki sposób powinien zostać potraktowany zidentyfikowany pasek.


162_____________________________________Poznaj Visual C++ 6
Kod zapisany na listingu 7.1 jest przykładowym zapisem funkcji obsługi komunikatu WM_VSCROLL.
Po zidentyfikowaniu paska zostaje zbadany rodzaj przeprowadzonej przez użytkownika operacji i na tej
podstawie określony jest sposób zmiany położenia uchwytu przesuwania. Następnie zmieniona zostaje
również pozycja uchwytu na pasku poziomym. Gdy więc użytkownik przesunie uchwyt na pasku
pionowym, przesunięcie nastąpi również na pasku poziomym.
Powiadomienia WM_VSCROLL oraz WMJHSCROLL
Pamiętać należy, iż pasek przewijania pionowego wysyła powiadomienie WM_VSCROLL, obsługiwane
przez funkcję OnYScroll (). Pasek poziomy natomiast wysyła powiadomienie WM_HSCROLL,
wymagające oddzielnej funkcji obsługi OnHScroll (). Częstym błędem jest implementacja tylko jednej
funkcji, obsługującej tylko jeden z pasków przewijania. Byłoby z pewnością lepiej, gdyby Windows
wysyłał tylko jeden rodzaj powiadomienia ze znacznikiem orientacji paska. Niestety, wcześniejsze 16-
bitowe ograniczenia wymusiły stosowanie dwóch komunikatów.
Listing 7.1. LST07_1.CPP - obsługa powiadomień pasków przewijania oraz zmiana położenia
uchwytów
1 void CScrollDlg::OnVScroll(UINT nSBCode, UINT nPos,
CScrollBar* pScrollBar)
2 {
3 if (pScrollBar->GetDlgCtrlID() == IDC_SCROLLBAR1) O
4 {
5 int nCurrentPos = pScrollBar->GetScrollPos () ;
6 switch(nSBCode)
7 {
8 case SB_THUMBTRACK:
9 case SB_THUMBPOSITION:
10 pScrollBar->SetScrollPos(nPos); @
11 break;
12 case SB_LINEUP:
13 pScrollBar->SetScrollPos(nCurrentPos-1) ;
14 break;
15 case SB_LINEDOWN:
16 pScrollBar->SetScrollPos(nCurrentPos+1) ;
17 break; -
18 case SB_PAGEUP:
19 pScrollBar->SetScrollPos(nCurrentPos-5) ;
20 break;
21 case SB PAGEDOWN:


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 163
22 pScrollBar->SetScrollPos(nCurrentPos+5) ;
23 break;
24 }
25 m_ScrollBar2.SetScrollPos(
26 2 * pScrollBar->GetScrollPos());
27 }
28
29 CDiaiog::OnVScroll(nSBCode, nPos, pScrollBar) ;
30 }
O Sprawdzenie identyfikatora paska.
Zmiana położenia uchwytu w oparciu o komunikat wysłany przez pasek przewijania po dokonaniu
zmian przez użytkownika.
W linii tej następuje zmiana położenia w drugim pasku, o wartość dwukrotnie większą od zmian w
pierwszym, gdyż zakres wartości drugiego paska jest dwa razy większy od zakresu paska pierwszego.
W linii 3 powyższego listingu sprawdzony zostaje identyfikator zwrócony przez funkcję
GetDigCtriiD () w celu upewnienia się, iż jest to identyfikator paska pionowego
(IDC_SCROLLBARI). Jeśli tak jest rzeczywiście, określone zostaje aktualne położenie uchwytu
poprzez wywołanie funkcji GetScrollPos (), a pobrana wartość zapisana zostaje w zmiennej
nCurrentPos w linii 5.
Wyrażenie switch, które widzimy w linii 6, oddziela kody opisujące poszczególne rodzaje
działań użytkownika z parametru nSBCode. Jeśli zmiana położenia uchwytu nastąpiła
wskutek przeciągnięcia myszą lub przeciągnięcia i zwolnienia klawisza myszy, pozycja
uchwytu zostaje ustalona zgodnie z życzeniem użytkownika na wartość npos, poprzez
wywołanie funkcji SetScrollPos () w linii 10.
Jeśli użytkownik dokonał przesunięcia o jedną linię w górę lub w dół (za pomocą
przycisków strzałek), zmiana pozycji uchwytu wyniesie jedną jednostkę, co zapisane jest w
liniach 12-17.
Jeżeli natomiast użytkownik kliknie wewnątrz paska przewijania, nakazując tym samym
przesunięcie widoku w oknie o jedną stronę, uchwyt przesunięty zostanie o 5 jednostek, co
zostało określone jako równoważnik jednej strony dokumentu. Dzieje się to w liniach 18-23.
Na koniec, poziomy pasek przewijania przypisany do zmiennej m_ScrollBar2 od-
wzorowuje przesunięcia następujące na pasku pionowym przez wywołanie funkcji Set-
ScrollPos (). Pobranie informacji o aktualnym położeniu uchwytu na pasku pionowym
następuje w liniach 25 oraz 26. Zauważmy, iż w linii 26 wartość zmiany położenia zostaje
pomnożona przez 2. Dzieje się tak dlatego, gdyż rozmiar paska poziomego jest dwukrotnie


164 Poznaj Visual C++ 6
większy niż pionowego, który ustaliliśmy przy użyciu funkcji SetScrolIRange (O, 200), wywołanej z
OnInitDialog ().
Wywołanie funkcji obsługi z klasy bazowej okna dialogowego CDialog: :OnV-Scroll () widniejące
w linii 29 pozwala temu oknu na obsługę jego pasków, służących do przesuwania widoku w nim samym
(jest to szerzej omówione w rozdziale 18).
PATRZ TAKŻE
Na temat powiadomień wysyłanych przez paski przewijania mówimy więcej w rozdziale 18.
Stosowanie suwaków kontrolnych
Suwaki kontrolne pozwalają określać użytkownikowi pewne wartości poprzez prze-
suwanie wskaźnika wzdłuż podziałki i ustawienie go w żądanej pozycji (jak na rysunku 7.5),
podobnie do potencjometrów suwakowych, na przykład w sprzęcie HI-FI.
Rysunek 7.5. Suwak kontrolny z widocznymi u góry punktami podziałki; wskaźnik postępu widoczny u
dołu wskazuje aktualne położenie wskaźnika.
Obiekt tego typu jest w pewnym sensie rozwinięciem paska przewijania. Obydwa te rodzaje
obiektów sterujących łączy stosowanie określonego zakresu działania oraz pojęcie pozycji wskaźnika.
Jednakże suwaki kontrolne pozwalają na dużo elastyczniejszą konfigurację niż paski przewijania.
Umieszczenie suwaka kontrolnego w oknie dialogowym
Podobnie jak w przypadku pozostałych obiektów sterujących, suwak kontrolny również
możemy umieścić w oknie dialogowym przeciągając go z paska narzędziowego Con-trols na
szablon okna. Suwak także można wymiarować, ustalać jego położenie w oknie, a także
nadawać mu charakterystyczny identyfikator ID na karcie Generał, w oknie dialogowym
Slider Properties. Karta Styles (pokazana na rysunku 7.6) z kolei umożliwia nam określenie
kilku aspektów działania oraz wyglądu suwaka.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 165
Slldei Propeities


-W ? Generał Slyles j Entended Styles )
Orientation: F Tickmaiks r" Enableselection |
Honzontal3 1^ Autoticks
:;:jEoint.: ::5: ::^
') r Botttet







Rysunek 7.6. Ustalanie właściwości suwaka na karcie Style w oknie Slider Properties
Na karcie tej znajdujemy dwie listy rozwijane. Pierwsza z nich to Orientation, w której
umieszczone zostały dwie pozycje: Horizontal oraz Vertical. Pozwalają one na ustalenie
orientacji suwaka, poziomej lub pionowej. Domyślnie ustawiona jest orientacja pozioma.
Jeżeli ją zmienimy, może okazać się konieczna także zmiana wymiarów okna dialogowego,
aby zmieścić suwak w żądanym rozmiarze. Druga lista obecna na karcie Styks to lista Point.
Początkowo wybraną pozycją jest Both, co oznacza, iż wskaźnik suwaka będzie miał postać
prostokąta. Zmiana wyboru na Top/Left temu wskaźnikowi ostre zakończenie, skierowane ku
górze w przypadku suwaka poziomego lub w lewo, gdy suwak ma orientację pionową.
Alternatywnie możemy ustalić kierunek wskaźnika na prawy lub dolny, wybierając pozycję
Bottom/Right.
Poza tymi dwoma listami, na karcie Styles znajdują się jeszcze cztery pola wyboru, w
których możemy wstawiać znaczniki w zależności od dokonanego wyboru.
Tick Marks. Jeśli zaznaczymy tę opcję, na suwaku pojawi się podziałka ułatwiająca wybór
pozycji znacznika, umieszczona w zależności od ustawienia znacznika, po prawej lub
lewej stronie suwaka (gdy stylem wybranym jest Tol/Left lub Bottom/Right), albo po
obu jego stronach, jeśli wybierzemy styl Both.
Auto Ticks. W przypadku zaznaczenia tej opcji punkty podziałki zostają umieszczone
zgodnie z przyjętą wartością inkrementacji wartości określającej położenie wskaźnika, w
odniesieniu do całego zakresu działania.
Enable Selection. Ta opcja zmienia wnętrze suwaka ze "szczeliny" na biały pasek, co
umożliwia programowi wyświetlenie zakresu działania za pomocą małych trójkąci-ków.
Border. Wybór tej opcji spowoduje umieszczenie czarnej obwódki wokół suwaka.
PATRZ TAKŻE
Więcej szczegółów dotyczących edycji okien dialogowych oraz właściwości obiektów ste-
rujących znajduje się w rozdziale 3.


166_____________________________________Poznaj Visual C++ 6
Przypisanie zmiennej obiektowi suwaka
Procedura przypisywania zmiennej temu obiektowi jest bardzo podobna, jak w wypadku wskaźnika
postępu. Możemy więc posłużyć się procedurą opisaną w punkcie "Przypisanie zmiennej składowej do
wskaźnika postępu" wcześniej w tym rozdziale. Musimy jedynie zwrócić uwagę na wskazania listy
Category oraz Variable Type, w kroku 5. Podobnie jak pasek przewijania, suwak pozwala na wybór
kategorii Control lub Value.
Jeśli spośród dwóch dostępnych wybierzemy pozycję Value, typ zmiennej zostanie określony jako
int. Zmienna ta, przypisana obiektowi suwaka, zostanie następnie wpisana do wybranej klasy. Zawartość
zmiennej będzie odświeżana w oparciu o zmiany położenia wskaźnika, podobnie jak w przypadku paska
przewijania, gdy przypisana mu zmienna jest typu int.
W pozostałej części tego podrozdziału zajmiemy się przypadkiem, gdy kategorię zmiennej ustalimy
na Control. Wybór ten determinuje automatyczną zmianę typu zmiennej na zmienną klasy MFC
CSliderCtrI. Po dokonaniu ustaleń co do nowej zmiennej, możemy przeprowadzić procedurę opisaną w
punkcie "Przypisanie zmiennej składowej do wskaźnika postępu".
Dynamiczne uaktywnianie i dezaktywowanie obiektów sterujących
Przy użyciu przypisanej obiektowi zmiennej (jak csliderCtrl) możliwe jest programowe aktywowanie i
dezaktywowanie obiektów sterujących. Można to osiągnąć stosując funkcję EnableWindow(), podając
jej parametr TRUE lub FALSE (na przykład m_mySliderCtrl.EnableWindow(FALSE)). Może się to
okazać przydatne do uniemożliwienia użytkownikowi wprowadzania zmian za pomocą danego obiektu
sterującego w pewnych okolicznościach.
PATRZ TAKŻE
4 Więcej na temat przypisywania zmiennych mówimy w rozdziale 10.
Inicjalizacja obiektu suwaka
Zakres działania ustalamy przy użyciu funkcji SetRangeO, podając jej jako dwa pierwsze
argumenty wartość minimalną oraz maksymalną. Opcjonalnie możemy także podać trzeci argument o
wartości FALSE, co zablokuje automatyczne odświeżanie widoku suwaka. Zakres działania określić mogą
również dwie funkcje: SetRangeMin ()oraz Se-tRangeMax (), dla których parametrami są odpowiednio
wartość minimalna i maksymalna. Korespondujące z nimi dwie inne funkcje GetRangeMin () oraz
GetRangeMax (), służą do pobierania aktualnie ustalonych wartości granicznych.


Stosowanie wskaźników postępu, pasków przewijania, suwaków.. 167
Pozycję wskaźnika możemy ustalić używając funkcji SetPos () i podając jej w charakterze
parametru nową wartość reprezentującą żądane położenie. Wartość opisującą położenie aktualne można
pobrać z funkcji składowej GetPos (), która tę wartość zwraca.
Tak jak w przypadku pasków przewijania, użytkownik może przesuwać widok na ekranie o linię
lub stronę, naciskając klawisze strzałek lub Page Up/Page Down. Jednakże nie musimy tu stosować
specjalnych powiadomień dla odświeżania widoku suwaka, jak to się dzieje w przypadku pasków
przewijania. Kontrolę nad wartością przesunięcia widoku o linię lub stronę zapewniają nam funkcje
obiektu suwaka SetLineSize () oraz SetPage-Size(), którym przekazać należy odpowiednie wartości.
Bieżące ustawienia możemy pobrać z wartości zwróconych przez dwie korespondujące z powyższymi
funkcje składowe: GetLineSize () iGetPageSize().
Ustalić można również wartość odstępów pomiędzy punktami podziałki. Użyć w tym celu należy
funkcji SetTickFreq (), podając jej jako parametr wartość pojedynczego odstępu. Gdybyśmy chcieli na
przykład ustalić ten odstęp na 5 jednostek, powinniśmy wpisać następujący kod:
m_Slider.SetTickFreq(5) ;
Programowe usuwanie znaczników
Aby programowo usunąć z widoku suwaka znaczniki podziałki, należy posłużyć się funkcją clearTics
(). Odświeżenie widoku suwaka nastąpi po niej automatycznie, gdy przekazany jej zostanie parametr
TRUE.
Aby funkcja ta mogła działać, musimy wcześniej ustalić właściwy styl, wybierając opcję Auto
Ticks z okna dialogowego Slider Properties. Wywołanie funkcji składowej GetNumTicks () pomoże
nam określić, ile punktów znajduje się obecnie na podziałce suwaka.
Jeżeli na karcie stylów zaznaczyliśmy opcję Enable Selection, możemy użyć funkcji składowej
SetSelection (), by zaznaczyć pewien obszar zakresu działania. Obszar ten będzie zaznaczony
niebieskim kolorem na białym pasku pod wskaźnikiem (widać to na rysunku 7.5). Aby ustalić granice
tego obszaru musimy podać funkcji SetSelection () wartości minimalną oraz maksymalną wewnątrz
obecnego zakresu działania. W celu określenia wartości granicznych obecnie dokonanej selekcji musimy
wywołać funkcję GetSe-lectionO, podając jej odwołania do zmiennych przechowujących bieżące
wartości. Użycie funkcji ciearSel () natomiast powoduje usunięcie selekcji.
PATRZ TAKŻE
Więcej informacji na temat inicjalizacji okien dialogowych znajduje się w rozdziale 10.


168 Poznaj Visual C++ 6
Odpowiedzi na powiadomienia obiektu suwaka
Obiekty tego typu stosują ten sam rodzaj komunikatów powiadamiających, jakich używają paski
przewijania, czyli WM_VSCROLL oraz WM_HSCROLL. Jedyną różnicą jest to, że nie musimy nakazywać
odświeżenia pozycji wskaźnika, gdyż dzieje się to automatycznie. Możliwe jest jednakże wykorzystanie
tych komunikatów do podejmowania innych, specyficznych działań.
Przykładowo, za pomocą suwaka możemy sterować wskazaniami wskaźnika postępu, co
pokazaliśmy na rysunku 7.5. Należałoby w tym celu przypisać suwakowi (o identyfikatorze IDC_SLIDERI)
zmienną składową m_siider klasy CSliderCtrl, a wskaźnikowi postępu (o identyfikatorze IDC_PROGRESSI)
zmienną o nazwie m_Progress klasy CProgressCtrI. Aby spowodować zmiany wskazań na wskaźniku
postępu wraz ze zmianami położenia wskaźnika suwaka, należy dodać funkcję obsługi OnHScroll () oraz
poniższy kod:
void CSliderDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
(
if (pScrollBar->GetDlgCtrlID() == IDCJ3LIDER1)
m_Progress.SetPos(m_Slider.GetPos() ) ;
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
Użyta tu funkcja GetDIgCtrIlDO służy do identyfikacji suwaka, następnie pozycja wskaźnika
postępu zostaje ustalona przez funkcję składową SetPos () w oparciu o wartość położenia wskaźnika
suwaka pobraną za pomocą funkcji suwaka GetPos ().
Jeżeli chcemy poznać wartość przesunięcia o linię lub stronę, powinniśmy sprawdzić wartość
parametru nSBCode i porównać ją z tabelą 7.2.
Odnajdywanie obiektu sterującego na podstawie identyfikatora ID
GetDIgitemO oraz GetDIgCtrl () są funkcjami zwracającymi wskaźnik cwnd do obiektu, którego
identyfikator ID zostanie im podany jako pierwszy parametr. Jeżeli żaden obiekt o podanym
identyfikatorze nie zostanie odnaleziony, zwrócona zostanie wartość NULL. Jeżeli zachodzi potrzeba
wykorzystania zwróconego wskaźnika, należy włączyć go do klasy MFC, obsługującej dany rodzaj
obiektu sterującego.
PATRZ TAKŻE
Informacje o identyfikatorach obiektów sterujących oraz komunikatach powiadamiających znajdują
się w rozdziale 4.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 169
Stosowanie próbników daty i godziny
Do czasu pojawienia się Visual C++ 6.0 programiści musieli konstruować własne mechanizmy
pozwalające użytkownikowi na określanie daty i godziny bądź też korzystać z kontrolek ActiveX.
Obecnie Microsoft dołączył do paska narzędziowego Controls dwa obiekty temu służące, czyli próbnik
daty oraz godziny i kalendarz miesięczny. Próbnik daty automatycznie otwiera kalendarz (omówiony w
dalszej części rozdziału), po kliknię-ciu przez użytkownika przycisku rozwijającego w celu określenia
dnia i miesiąca.
Ten rodzaj obiektu możemy zobaczyć w aplikacji poczty elektronicznej programu Microsoft
Outlook. Próbnik może nam posłużyć do pobierania zarówno daty, jak i godziny (przy użyciu dwóch
obiektów tego rodzaju). Próbnik pobierający datę ma zwykle wygląd listy kombinowanej i wyświetla w
polu edycji datę w skróconej formie. Gdy użytkownik kliknie przycisk rozwijania, pojawi się kalendarz
miesięczny (widoczny na rysunku 7.7), który pozwoli na wybór miesiąca i dnia. Próbnik godziny
natomiast (po prawej stronie, na rysunku 7.7) otwarty zostaje z podaną bieżącą godziną, którą można
edytować bezpośrednio w polu edycji lub poprzez użycie przycisków ze strzałkami.

Rysunek 7.7. Użycie próbników daty oraz godziny
PATRZ TAKŻE
Przykład kontrolki ActiveX, służącej do pobierania daty znajduje się w rozdziale 9.
Umieszczanie próbników daty i godziny w oknie dialogowym
Tak jak wszystkie obiekty sterujące, również próbniki daty czy godziny mogą być umieszczane na
szablonie okna dialogowego poprzez przeciągnięcie ich z paska narzędziowego Controls bezpośrednio
na szablon okna. Na szablonie mogą być przesuwane oraz wymiarowane. W ich wypadku również
powinniśmy ustalić identyfikatory, korzystając z karty Generał w oknie dialogowym Datę Time Picker
Properties (wywołujemy je z menu skrótów lub poprzez naciśnięcie klawiszy Alt+Enter), jak widać to
na rysunku 7.8.


170 Poznaj Visual C++ 6
M.illplellM.MiciOKilWiaMCc.lIdliKeltit.lc-IDD.DTPICKERJlIAUlGIOIllagll":1 !':::!::,-;::
.l,.i", s'?- ::,,,. HBQ

^f.ile EA1 V.sw InMft Pr0)ec Bi.tó Laiwl I wiś Window łje!p " {ffj x

iii B; V ^ X. ^ ^ . . '..; ' !r,y5%-' ^:^'^r~~''~~"'~'''''^] -^

' ' ^ -:"' ! ''S-i '/ j i-i-"P.'.:i.eiL^ 'Jit[/C.L',Ałt.ilMfcPil:rŁ.Hl ^J|D NJ.UKEUP J^J ^ - :
^ -^ '1 Y11!,!:. ^,. ;1:1:1;..,.'.,. ;.1,11:1,,..., ,;:';:"!!ll;iiBS'7''ylljgfiT:;fl"l!: ii ^ 11111:1 ^:'

., i dlpk.k.1
.nJ e,
Ł.atlMtc

-^

B^^IWilKi^^r^W"



: i-
gl.OO.Ml
:-BScii

l



BSS^flBB^I lit N A> "K



^5/4/33 TJII 1021 51 AM i
OK











:;; ,,":, ,

Q a [x r.

; a!Qv




SB B 88 ż





3 r& a a !





^C^.:
!;^:..(^^!:^?^|ll|||^<1^51iii;WlilllS:asf^lilll^^

ri {a H [ :





-tó f Gwiei^ S^M j E!
C 6fo^, """("l





fe'n"4i. p gighł Aligtł r Show[ion6







j^h.JłlL'-i!e '} r UseSpinContioł r AllowEi-
Si



icJagn IJF l







g :.. , '1-1 -:: lal s irfiiSMiSSIBiS^BBIBW^iiIiiIK

Cal.. . r., d.l tck tM :^;i|:^^S!:'^N^B|?^;ipi!,rtgsTy--"^|^

Rysunek 7.8. Umieszczanie próbników daty i godziny na szablonie okna dialogowego
Karta Styks w tym samym oknie dialogowym umożliwia dostosowanie sposobów wyświetlania
daty oraz godziny. Tryb pracy próbnika ustalamy wybierając spośród trzech dostępnych typów na liście
rozwijanej Format:
Short Datę. Próbnik będzie służył do pobierania daty i wyświetli ją w krótkim formacie (np. 5/4/98), a
po kliknięciu przez użytkownika przycisku rozwijającego, wyświetli kalendarz miesięczny, z
którego można będzie wybrać żądaną datę.
Long Datę. Próbnik wyświetli datę w rozszerzonym formacie (np. l styczeń 1998) i wyświetli również
kalendarz po kliknięciu przycisku rozwijającego.
Time. Próbnik pobierał będzie od użytkownika godzinę (np. 10:21:51), a jego pole wyposażone
będzie w przyciski przewijania zamiast przycisku rozwijającego. Przyciski te będą służyły do
ustawiania godzin, minut oraz sekund.
Na tej samej karcie dostępne są jeszcze cztery opcje stylu:
Right Align. Po wybraniu tej opcji, otwarte okno kalendarza będzie wyrównane do prawej strony pola
edycji próbnika daty. W przeciwnym razie, kalendarz zostanie wyświetlony po lewej stronie.
" Use Spin Control. Wybór tej opcji spowoduje zamianę przycisku rozwijania na przyciski
przewijania. Użytkownik będzie mógł wtedy ustalać datę za pomocą tych przycisków, zmieniając
dzień, miesiąc oraz rok. Kalendarz w tym wypadku nie jest wyświetlany.
Show None. Zastosowanie tej opcji umożliwia użytkownikowi zablokowanie wyboru daty, gdy pole
wyboru umieszczone w polu edycji próbnika pozbawione zostanie znacznika.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 171
Allow Edit. Jeśli zaznaczymy tę opcję, pozwoli to użytkownikowi na wprowadzenie daty zklawiatury
poprzez sprawdzenie wpisu za pomocą komunikatu ZDTN_USER-STRING wysłanego przez obiekt
próbnika.
PATRZ TAKŻE
Więcej szczegółów dotyczących edycji okien dialogowych oraz właściwości obiektów sterujących znajduje się w
rozdziale 3.
Przypisywanie zmiennych do obiektów próbników daty i godziny
Korzystając z narzędzia CIassWizard możemy przypisać próbnikom zmienne w sposób, w jaki
przypisaliśmy zmienną do wskaźnika postępu, co było opisane wcześniej w tym rozdziale.
Jeśli kategorię tej zmiennej ustalimy jako Value (krok 5), z listy Yariable Type będziemy mogli
dokonać wyboru obiektu pomiędzy CTime oraz COleDateTime. Wybór jednej z tych klas dostarcza nam
szybkiej i łatwej metody pobierania wartości z próbników dat i godzin poprzez wykorzystanie zmiennej
składowej, tak samo jak ma to miejsce w przypadku obiektów edycyjnych, przy wykorzystaniu klasy
cstring.
Jeżeli potrzebujemy bardziej rozbudowanej kontroli nad obiektami próbników, powinniśmy obrać
dla nich kategorię Control, co automatycznie spowoduje wybór klasy CDateTimeCtrl (obsługuje
próbniki w sposób omówiony w dalszej części rozdziału).
Możemy z powodzeniem przypisać dwie zmienne do obiektu (poprzez jego identyfikator), przez co
uzyskamy kontrolę nad nim dzięki klasie CDateTimeCtrl oraz szybki dostęp za pomocą COleDateTime.
Używanie obiektów COleDateTime oraz CTime
Stosowanie obiektów COleDateTime jest bardziej właściwe od CTime, ponieważ typ ten zapewnia
obsługę dat w zakresie od l stycznia 100 roku do 31 grudnia 9999. CTime natomiast pozwala
posługiwać się datami z przedziału l stycznia 1970 - 19 stycznia 2038. Oprócz tego, jak sama nazwa
wskazuje, obiekty COleDateTime mogą być łatwiej wykorzystywane przez programy stosujące
mechanizmy OLE oraz COM.
Kiedy dokonamy już wyboru typu zmiennej lub zmiennych, klikamy OK, co zamknie okno Add
Member Yariable i spowoduje wpisanie nowych zmiennych do wybranej klasy (zwykle będzie to klasa
naszego okna dialogowego).
W aplikacji będącej przykładem w niniejszym rozdziale umieścimy dwa obiekty próbników: jeden
do pobierania daty, drugi do pobierania godziny. Jest to pokazane na rysunku 7.8. Próbnik daty będzie
posiadał identyfikator IDC_MYDATE oraz przypisaną zmienną m_myDate,


172 Poznaj Visual C++ 6
próbnik godziny natomiast to IDC_MYTIME, a przydzielona mu zmienna m_myTime. Obie
zmienne należą do klasy CDateTimeCtri.
PATRZ TAKŻE
Więcej szczegółowych wyjaśnień na temat przypisywania zmiennych składowych zamieszczamy w rozdziale 10.
Inicjalizowanie próbników daty i godziny
Podobnie jak w przypadku poprzednio omawianych obiektów, próbnikom daty i godziny również
możemy nałożyć ograniczenia wskazań, określając zakres wskazywanych wartości. Ustalony on zostaje
poprzez podanie wartości minimalnej i maksymalnej, reprezentujących dostępne daty w przód oraz w tył.
To samo możemy uczynić w stosunku do próbnika godziny. Posłużyć się musimy funkcją SetRange (),
podając jej wskaźniki dwóch obiektów COleDaterime (lub crime) przechowujących wartości
najwcześniejszej oraz najpóźniejszej dostępnej daty lub godziny. Gdybyśmy przykładowo chcieli ograni-
czyć możliwość wyboru daty i godziny tylko do roku 1998, osiągnęlibyśmy ten cel wpisując poniższe
linie na końcu kodu implementującego funkcję OninitDialog ():
COleDateTime dtMin(1998, l, l. O, O, 0) ;
COleDateTime dtMax(1998, 12, 31, 23, 59, 59);
m_myDate.SetRange(SdtMin, &dtMax); // Ustalenie zakresu wyboru // dat l godzin
Pierwsze dwie linie służą do skonstruowania dwóch obiektów COleDateTime zawierających
parametry określające rok, miesiąc, dzień, godzinę, minuty oraz sekundy. Wskaźniki do tych dwóch
obiektów zostają następnie przekazane zmiennej m_myDate (typu CDateTimeCtri) poprzez funkcję
SetRange O. W czasie pracy programu uniemożliwi to użytkownikowi dokonanie wyboru daty spoza
roku 1998, a daty nie mieszczące się w tym zakresie, będą wyświetlane na kalendarzu w szarym kolorze.
Korespondująca funkcja GetRange () posłużyć może do ustalenia wartości obu obiektów COleDateTime
(lub CTi-me) zgodnie z obecnymi parametrami zakresu.
Poprawność daty w obiekcie COleDateTime
Jeśli data zawarta w obiekcie COleDateTime jest poprawna, obiekt zostanie oznaczony znacznikiem
ważności (COleDateTime: :valid). W przeciwnym wypadku znacznik będzie informował o
nieważności (COleDateTime:: invalid). Sprawdzenia aktualnego stanu dokonuje funkcja składowa
GetStatusO, zwracając wartość znacznika. Można także wymusić jego wartość za pomocą SetStatus ().


Stosowanie wskaźników postępu, pasków przewijania, suwaków... ___ 173
Wpływać możemy także na format wyświetlanych dat lub godzin. W tym celu podajemy funkcji
SetFormat () parametr w postaci łańcucha znakowego, określającego żądany format. Owe łańcuchy
formatujące przedstawione są w tabeli 7.3.
Tabela 7.3. Kody formatujące wyświetlanie dat i godzin przez ich próbniki


Kod
formatu
Opis






yyy
yy y
MMMM
MMM
MM
M
dddd
ddd
dd
d
HH
hh
H
tt
t
mm
m
Wyświetla rok w pełnej postaci (np. 1998)
Wyświetla rok skracając jego postać do dwóch ostatnich cyfr (np. 98)
Wyświetla ostatnią cyfrę roku (np. 8)
Nazwa miesiąca wyświetlana jest w pełnym brzmieniu (np. kwiecień)
Nazwa miesiąca wyświetlana jest przy użyciu trzech liter, stanowiących synonim pełnej
nazwy (np. kwi)
Miesiąc podawany jest za pomocą dwóch cyfr (np. 04)
Podaje miesiąc za pomocą jednej lub dwóch cyfr (np. 4 jako kwiecień lub 11 jako
listopad)
Podaje pełną nazwę dnia tygodnia (np. poniedziałek)
Ogranicza nazwę dnia tygodnia do trzyliterowego synonimu (np. pon)
Podaje dzień miesiąca za pomocą dwóch cyfr (np. 04)
Dzień miesiąca podawany jest przy użyciu jednej lub dwóch cyfr (np. 4 lub 11)
Wyświetlanie godziny w formacie 24-godzinnym (np. 16)
Podawanie godziny w formacie 12-godzinnym (np.04).
Godzina wyświetlana jest w formacie 24-godzinnym, przy użyciu jednej lub dwóch cyfr
(np. 4 dla czwartej rano lub 16 dla godziny czwartej po południu)
Jak wyżej, tylko w formacie 12-godzinnym np. 4 to czwarta rano oraz czwarta po
południu)
Obok godziny w formacie 12-godzinnym podaje część dnia, której godzina dotyczy (AM
- rano, PM - po południu)
Jak wyżej, lecz z wykorzystaniem jednej litery (A lub P)
Minuty podawane są za pomocą dwóch cyfr (np. 07 lub 59)
Minuty podane zostają przy użyciu jednej lub dwóch cyfr (np.7 lub 59)


174 Poznaj Visual C++ 6
Format danych wyjściowych z obiektu coleDateTime
W podobny sposób jak w wypadku próbników daty czy godziny, można określać format danych
wyjściowych z obiektu coleDateTime za pomocą jego funkcji Format (). Jako pierwszy parametr tej
funkcji podać należy kod formatu.
Istnieje cały zestaw kodów formatujących informacje dotyczące roku, miesiąca, dnia, godzin, minut i
sekund. Przykładowo, kod %c powoduje podanie daty i godziny w formacie: 04/04/98 18:05:01.
Zastosowanie kodu %#c natomiast zmienia format na dłuższy, np. Sobota, 04 kwietnia, 1998,
18:05:01.
Na tym jednak kwestia formatu wyświetlania nie kończy się. Możemy bowiem wstawiać
dodatkowe elementy do wyświetlenia, zamykając je pomiędzy apostrofami, co powoduje
rozszerzenie formatu. Dzięki temu, próbnik może wyświetlać datę oraz godzinę w jednym
oknie, na przykład 1998/05/04 12:22:23. Aby tak się stało, a użytkownik miał możliwość
edycji zarówno daty, jak i godziny, w implementacji funkcji OninitDialog () musimy umieścić
następujący kod:
m_myDate.SetFormat("yyy'/'MM'/'dd' 'HH':'mm':'ss");
Gdy uruchomimy aplikację, próbnik pozwoli nam na edycję daty i godziny w jednym
oknie, jak widać na rysunku 7.9.
January 1967
Rysunek 7.9. Próbnik wyświetla datę i godzinę w jednym oknie
Możliwe jest również ustalenie daty i godziny, pojawiających się po otwarciu okna. Mogą to być
wskazania odmienne od domyślnie przyjmowanych danych systemowych. Aby tak się stało, należy
przekazać funkcji setTime () wskaźnik obiektu coleDateTime przechowujący żądaną datę początkową.
Przykładowo, jeśli chcemy, aby próbnik po otwarciu okna dialogowego wskazywał godzinę 18:02
dnia 18 stycznia 1967 roku, musimy wpisać następujący kod:
m_myDate.SetTime(COleDateTime(l 967, l, 18, 18, 2, 0) ) ;
Bezpośrednio po uruchomieniu aplikacji w oknie próbnika ujrzymy wskazania jak na
rysunku 7.9.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 175
Datę początkową, która została ustalona już wcześniej, pobierać możemy poprzez funkcję
GetTimeO, przekazującą zmiennej obiektu COleDateTime pobrane wskazania. Tę zmienną możemy
wykorzystać do dalszych zadań.
Przykładem może być sytuacja, gdy dopisując poniższy kod spowodujemy wyświetlanie wybranej
daty i godziny, po kliknięciu przez użytkownika przycisku OK w oknie dialogowym (i po uprzednim
umieszczeniu funkcji OnOK ()):
void CDtpickerDlg::OnOK() {
COleDateTime dtChosenTime;
m_myDate.GetTime(dtChosenTime() ;
AfxMessageBox(dtChosenTime.Format("%#x")) ;
CDialog::OnOK() ;
)
Bieżąca data oraz godzina zostaje pobrana i zapisana w zmiennej dtChosenTime, która z kolei
zostaje sformatowana przez funkcję Format () obiektu COleDateTime, a następnie wyświetlona jako
komunikat.
Kalendarz miesięczny pozwala na zmianę atrybutów wyświetlania, takich jak kolor jego elementów
oraz rodzaj czcionki. Kolory ustalamy poprzez funkcję SetMonthCalCo-lor() podając jej parametry
informujące o numerze barwy oraz wskazujące element, którego kolor chcemy zmienić
(wyszczególnienie tych elementów znajduje się w tabeli 7.4). Czcionkę używaną do wyświetlania dat
ustalamy natomiast korzystając z funkcji SetMonthCalFont (), podając jej wskaźnik czcionki (HFONT).
Pobieranie wartości z COleDateTime
Kilka funkcji dostępowych zwraca częściowe informacje o dacie lub godzinie: GetY-
ear (), GetMonthO , GetDayO, GetHour (), GetMinute () oraz GetSecondO . Istnieją również inne użyteczne
funkcje: GetDayOfWeek () i GetDayOfYear ().
Pierwsza zwraca numer dnia w tygodniu, przy czym niedziela posiada indeks l. Druga natomiast
zwraca numer dnia w roku, w zakresie od l do 366, rozpoczynając od l stycznia.
PATRZ RÓWNIEŻ Informacji na temat obsługi czcionek należy szukać w
rozdziale 17.


176_____________________________________Poznaj Visual C++ 6
Powiadomienia o zmianie daty
Gdy użytkownik dokona zmiany daty w próbniku, próbnik wysyła do okna przodka
komunikat DTN_DATETIMECHANGE, który możemy przechwytywać i stosując odpowiednią
funkcję obsługi, wykorzystać do wywoływania określonych reakcji programu. Poniżej opisana
jest procedura dodania takiej funkcji.
Dodanie funkcji obsługi komunikatu o zmianie daty
1. W oknie dialogowym, którego szablon wyświetlony jest w edytorze zasobów, wybierz
właściwy próbnik i kliknij prawym klawiszem myszy.
2. Z rozwiniętego menu skrótów wybierz pozycję Events, po czym otwarte zostanie okno
dialogowe New Windows Message and Event Handlers.
3. Zaznacz komunikat DTNJDATETIMECHANGE widniejący na liście New Windows
Messages/Events.
4. Kliknij przycisk Add and Edit, co wywoła okno dialogowe Add Member Function
wyświetlające domyślnie przypisaną nowej funkcji nazwę.
5. Zmień tę .nazwę wedle życzenia i kliknij OK, by rozpocząć edycję funkcji. Po zakończeniu
edycji funkcja powinna mieć treść podobną do treści listingu 7.2.
Po dodaniu tej funkcji możemy powodować wywoływanie określonych działań programu
następujących po zmianie daty przez użytkownika. Pierwszy parametr funkcji jest
wskaźnikiem struktury NMHDR. Zwykle stosuje się osobne funkcje obsługi dla oddzielnych
próbników, jednakże dzięki możliwości sprawdzenia identyfikatora próbnika wysyłającego
komunikat (poprzez zmienną idFrom należącą do struktury NMHDR) możemy zastosować
jedną funkcję obsługi, współużytkowaną przez kilka próbników. Na listingu 7.2 zawarta jest
współużytkowana funkcja obsługi wraz z dwiema pozycjami ON_NOTIFY mapy komunikatów,
współużytkującymi tę funkcję. Kod poniższy powodować będzie zmianę napisu w pasku
tytułowym głównego okna dialogowego na napis podający aktualnie wybraną przez
użytkownika datę lub godzinę.
Listing 7.2. Funkcja obsługi powiadomienia DTN_DATETIMECHANGE,
współużytkowana przez dwa próbniki daty i godziny
1 BEGIN_MESSAGE_MAP(CDtpickerDlg, CDialog)
2 //{(AFX_MSG_MAP(CDtpickerDlg)
3 ON_WM_SYSCOMMAND()
4 ON_WM_PAINT()
5 ON_WM_QUERYDRAGICON()
6 ON_NOTIFY(DTN_DATETIMECHANGE, IDC_MYDATE,
OnDatetimechangeMydate)
7 //}}AFX_MSG_MAP O
8 ON_NOTIFY(DTN_DATETIMECHANGE, IDC_MYTIME,
OnDatetimechangeMydate)


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 177
9 END_MESSAGE_MAP()
10
11 void CDtpickerDlg::OnDatetimechangeMydate(
NMHDR* pNMHDR, LRESULT* pResult)
12 {
13 COleDateTime dtSel;
14 switch(pNMHDR->idFrom) @
15 (
16 case IDCJMYDATE: @
17 m_myDate.GetTime(dtSel);
18 SetWindowText("Datę:"+dtSel.Format("%#x")) ;
19 break;
20 case IDC_MYTIME: @
21 m_myTime.GetTime(dtSel);
22 SetWindowText("Time:"+dtSel.Format("%H:%M:%S")) ;
23 break;
24 }
25 *pResult = 0;
26 }
O Drugie odwołanie do mapy komunikatów należy wprowadzić samodzielnie.
W zależności od tego, jakiego rodzaju próbnik wysłał komunikat, czy był to próbnik daty (linia 16),
czy też godziny (linia 20) pasek tytułowy okna dialogowego wyświetli wybraną datę lub godzinę.
Pozycja mapy komunikatów wypisana w linii 6 jest pozycją standardową, wpisywaną przez
CIassWizard po umieszczeniu w programie funkcji obsługi powiadomienia o zmianie daty. Jednakże
drugą pozycję mapy, widoczną w linii 8, musimy wprowadzić samodzielnie, by mogła współużytkować
tę samą funkcję obsługi
(OnDatetimechangeMyDate()).
Implementacja powyższej funkcji odbywa się w liniach od 11 do 26. Zmienna obiektu
COleDateTime (dtSel) zostaje zadeklarowana w linii 13 i służy do przechowywania bieżącej daty i
godziny. Wyrażenie switch natomiast, widoczne w linii 14, musi określić próbnik, który wysłał
komunikat.
Jeśli próbnikiem tym będzie IDC_MYDATE, ze zmiennej przypisanej temu próbnikowi, m_myDate,
zostanie pobrana nowa data (linia 17) i wyświetlona w pasku tytułowym głównego okna dialogowego
(linia 18).
Jeżeli natomiast próbnik IDC_MYTIME będzie nadawcą komunikatu, z przypisanej mu zmiennej
m_myTime odczytana zostanie ustalona przez użytkownika godzina (w linii 21), a następnie
wyświetlona w pasku tytułowym okna dialogowego (linia 22).


178 Poznaj Yisuał C++ 6
Ręczne wpisanie pozycji mapy komunikatów
Podczas wpisywania z klawiatury pozycji mapy komunikatu należy uważać, aby nowy wpis
umieścić za komentarzem // { {AFX_MSG_MAP. Komentarz ten używany jest przez
CIassWizard, a gdy odnajdzie za nim nieoczekiwany kod, może powstać zamieszanie.
Najlepsze miejsce na wpisanie tego kodu znajduje się za drugim komentarzem // {
(AFX_MSG_MAP, lecz przed linią makro END_ME s SAGĘ MAP . :
PATRZ TAKŻE
Więcej o identyfikatorach obiektów sterujących oraz komunikatach powiadamiających
mówimy w rozdziale 4.
Stosowanie kalendarza miesięcznego
Kalendarz miesięczny możemy stosować także jako oddzielne okno dialogowe. Dotych-
czas zajmowaliśmy się tym obiektem w połączeniu z próbnikiem daty, gdy wyświetlany był
po kuknięciu przez użytkownika przycisku rozwijania. Próbnik pokazywał wtedy okno ka-
lendarza, z którego użytkownik mógł wybrać żądaną datę, zmieniając wyświetlany miesiąc i
rok. Kalendarz ten w normalnych sytuacjach zezwala na wybór tylko jednej daty, możliwe
jednak jest skonfigurowanie go w sposób umożliwiający wybór większego zakresu dat.
Umieszczenie kalendarza miesięcznego w oknie dialogowym
Kalendarz umieszczamy na szablonie okna dialogowego w znany nam już sposób, czyli
przeciągając jego ikonę z paska narzędziowego Controls, bezpośrednio na szablon. Po
wykonaniu tej czynności możemy przystąpić do edycji właściwości nowego obiektu. Okno
dialogowe Month Calendar Properties wywołujemy poprzez naciśnięcie Alt+Enter. Na
karcie Generał dokonujemy zmiany identyfikatora. Karta Styles (widoczna na rysunku 7.10)
pozwala na wybór opcji związanych ze sposobem działania i zachowania się kalendarza. Oto
możliwości wyboru:
Day States. Po zaznaczeniu tej opcji możemy określić datę, która będzie wyświetlana w
kalendarzu w negatywie (biała data na czarnym tle). W przeciwnym wypadku, w ten
sposób wyświetlana będzie bieżąca data systemowa.
" Multi Select. Zaznaczenie tej opcji sprawi, iż możliwe będzie oznaczanie pewnego zakresu
dat, zamiast pojedynczej daty, w przypadku niezaznaczenia.
No Today. W przypadku wyboru tej opcji bieżąca data systemowa nie będzie otaczana
czerwoną linią, jak ma to miejsce zazwyczaj.
Week Numbers. Gdy oznaczymy tę opcję jako aktywną, po lewej stronie każdej linii
reprezentującej tydzień umieszczony zostanie numer danego tygodnia w aktualnie wy-
świetlanym roku, w numeracji od l do 52.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 179
Znaczniki stylu kalendarza miesięcznego
Opcje stylu nadane kalendarzowi są równoznaczne ze znacznikami stylu: MCS_DAY-STATE,
MCS_MULTISELECT, MCS__NOTODAY, MCS_NOTODAYCIRCLE Oraz MCS_WEEK-
NUMBERS. Znaczników tych można użyć w trakcie dynamicznego tworzenia obiektu kalendarza,
zamiast w edytorze zasobów.
IDD MONTHCAL DIALOG (Diatogn


;3tile ŁAI YKW jraell Flopef Bu B)
lSS9[t aa. : a - . r, 13 %' CjhICMonIhCaioir
^ [**i ^ l ^ '^ !.jCMot'B^a!Lil.3^]; IDC_1''ON l h&LfcMDńftl_>J|MCU_l^ l
DAł'.' !A s Ł ^..^
~33-
-- ^ 'm..,,....,....,,...,,,.,,.........,.,.. :*

-; "-J Btonihcal
tetoucce* '
;-:"..:it Dialog : : ^|
iDDA60UTBOX ;

S^
.

,^^^^^B^riiBi::a



: ' ^itjD-
MgNTH.CAL^D.lAigC. ;'
!;S"Q] lccr. 1 : :S..^JSIhi-
.9Ttbte :;



l|^|B!FJ|iC^ 4^-1

p*"fflmHr^
It U AHM Q 0 K s !

H5-.(JV-riw :



:^ 3 40! S 6 7 6 9 ,

iB a as a l l







$ BCT -ł~ ^ i l



|| -

t9"''- 10 11 12 13 t4 15 f. ' 17 18 19
20 21 22 -K : 24 25 36 37 28 29 3CI
.

!ll. B Hi l





; 31 ; ': : i "-.

UL 9 Ęi'~ l |



l-
l^

..... . ..*. .


C 68 |S^c"h.i| :











- f Gweidl [Sty!es,J E^iwdedS^te;. |




1^

r E3;,Siate? F UoTctIdj.







r {-'utiSdeGi r Węch Nun-.be-s





1^
:^

"r MoIcriayC


'^aai,-sV>,.j^F!eMi".
t]FiteViw.|








:'S /. ' 7; ' lalE53
Cwales ai^twmoolhcateridaicwilioi.
Rysunek 7.10. Kalendarz miesięczny umieszczony w oknie dialogowym jako odrębny obiekt
PATRZ TAKŻE
t Więcej szczegółów dotyczących edycji okien dialogowych oraz właściwości obiektów sterujących
znajduje się w rozdziale 3.
Przypisanie zmiennej do obiektu kalendarza
Procedura przypisania zmiennej do obiektu jest w tym wypadku bardzo podobna do pozostałych,
opisanych już w tym rozdziale. Możemy przypisać zmienną typu CTime lub COleDateTime
bezpośrednio do obiektu kalendarza, gdy wybraną dla niego w oknie dialogowym Add Member
Yariable kategorią będzie Value. Jeżeli jednak zależy nam na pełniejszej kontroli obiektu, powinniśmy
jako jego kategońę wybrać Control, co automatycznie ustali typ zmiennej na CMonthCalCtrl jako
zmienną składową klasy obsługującej wybrane okno dialogowe.


Więcej słów wyjaśnienia na temat przypisywania zmiennych składowych znajduje się w rozdziale 10.
Inicjalizacja obiektu kalendarza
Obiekt ten można zainicjalizować w taki sposób, aby zezwalał na wybór daty z pewnego zakresu,
poprzez przekazanie funkcji SetRangeO klasy CMonthCalCtrl parametrów wskazujących
najwcześniejszą oraz najpóźniejszą dostępną datę w postaci wskaźników obiektów COleDateTime (lub
CTime), jakimi są na przykład próbniki daty. Funkcja korespondująca, GetRange (), posłużyć może do
zapisania we wskazanych obiektach dat granicznych.
Domyślnie przyjmowanym pierwszym dniem tygodnia jest niedziela. Możemy to jednak zmienić,
przekazując funkcji SetFirstDayOfWeek() numer dnia bazujący na numeracji rozpoczynającej się od
zera, w której poniedziałek będzie nosił indeks O, niedziela natomiast indeks 6. W tym celu na końcu
funkcji OninitDialog () powinniśmy umieścić następujący wpis (gdzie m_myMonthCal jest zmienną
klasy CMonthCalCtrl, przypisaną obiektowi kalendarza):
m_niyMonthCal. SetFirstDayOfWeek (0) ;
Możemy również dokonać zmiany daty wskazywanej jako "dziś" (otoczonej czerwoną kreską),
przekazując funkcji SetTodayO wskazanie obiektu COleDateTime, w którym zapisana jest żądana data.
Bieżąca data "dzisiejsza" pobierana jest poprzez przekazanie funkcji GetToday () zmiennej
COleDateTime. Owa data będzie zapisana w zmiennej.
Domyślne kolory użyte do wyświetlania kalendarza możemy zmienić, wywołując funkcję SetColor
(), której przekażemy jako pierwszy parametr znacznik spośród opisanych w tabeli 7.4 oraz kolor jako
drugi parametr.
Ustalenie kroku przewijania kalendarza
Gdy użytkownik naciśnie któryś z umieszczonych w oknie kalendarza przycisków przewijania,
przesunięcie "w czasie" równe będzie jednemu miesiącowi. Można zmienić wielkość tego kroku
wywołując funkcję SetMonthDelta () i podając jej w charakterze parametru liczbę miesięcy, o jaką ma
następować przesunięcie kalendarza po każdym użyciu przycisków przewijania. Powiązana z
powyższą funkcja GetMonthDelta () zwraca obecną wartość tego kroku.


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 181 Tabela 7.4.
Znaczniki zmian kolorystyki kalendarza miesięcznego
Znacznik Opis
MCSC_TEXT Zmiana koloru czcionki wyświetlającej daty
MCSC_TITLETEXT Zmiana koloru napisu w pasku tytułowym
MCSC_TITLENBK Zmiana koloru tła paska tytułowego
MCSC_TRAILINGTEXT Zmiana koloru dni zachodzących na bieżący miesiąc z miesiąca poprzedniego
oraz następnego
MCSCJBACKGROUND Zmiana koloru tła, na którym kalendarz jest wyświetlany
PATRZ TAKŻE
O wartościach kodowych kolorów mówimy w rozdziale 16.
Ustalanie zakresu dostępnych dat w kalendarzu
Umożliwienie użytkownikowi dokonywania wyboru kilku następujących po sobie dat
uwarunkowane jest zaznaczeniem opcji Multi Select na karcie Styles w oknie dialogowym
właściwości obiektu kalendarza.
Zakres dat wyświetlanych w kalendarzu
Zakres dat, jakie wyświetlić może kalendarz, można ograniczyć używając funkcji setRange (), podając
jej jako parametry wskaźniki do obiektów coleDateTime, jak miało to miejsce w przypadku obiektów
CDateTimeCtrI. Powiązana funkcja Get-Range () zwraca obecnie obowiązujący zakres.
Gdy kalendarz pracuje w trybie zezwalającym na wybór tylko jednej daty, możliwe jest wskazanie
początkowo wskazywanej daty poprzez przekazanie funkcji kalendarza SetCurSel () wskazania obiektu
COleDateTime, jak poniżej:
m_MyMonthCal.SetCur(C01eDateTime(1967, l, 18, 18, 2, 0) ) ;
Data wpisana lub wskazana przez użytkownika może zostać pobrana w każdym momencie, poprzez
przekazanie obiektu typu COleDateTime do funkcji kalendarza GetCur-Sel (), jak poniżej:
COleDateTime dtChosenTime;
m_MyDate.GetCur3el (dtChosenTime) ;
AfxMessageBox(dtChosenTime, Format("%#x")) ;
Ostatnia linia służy do wyświetlenia wybranej daty w oknie komunikatu.


182_____________________________________Poznaj Visual C++ 6
Jeżeli chcemy umożliwić dokonywanie wyboru kilku dat, powinniśmy użyć funkcji GetSeIRange ()
oraz SetSeIRange () w celu sprawdzenia aktualnie określonego i ustalenia nowego zakresu dostępnych
dat. Obie te funkcje wymagają przekazania im obiektów COleDateTime jako parametrów. Pierwszy z
nich określa najwcześniejszą możliwą do wyboru datę, drugi natomiast najpóźniejszą.
Domyślnie ustalona maksymalna liczba dni, które użytkownik może zaznaczyć, wynosi siedem.
Stan ten można zmienić, podając dowolną liczbę maksymalną poprzez podanie funkcji kalendarza
SetMaxSelCount () tej liczby w postaci wartości int.
Jeśli przykładowo, chcemy zaznaczyć pierwsze 14 dni stycznia 1998 oraz umożliwić dokonanie
wyboru maksymalnie 15 następujących po sobie dni wewnątrz tego zakresu, dodać musimy poniższy
kod:
m_MyMonthCal.SetMaxSelCount(15) ;
m_MyMonthCal.SetSeIRange(COleDateTime(l 998, l, l, O, O ,0), COleDateTime(1998, l, 14, O, O,
0)) ;
Po uruchomieniu programu na kalendarzu zaznaczone zostaną daty pomiędzy l a 14 stycznia i
użytkownik będzie mógł dokonać selekcji maksymalnie 15 spośród nich.
Po dokonaniu przez użytkownika wyboru, można sprawdzić liczbę wybranych dni, a także daty,
pomiędzy którymi nastąpiła selekcja. W tym celu dopisać należy kolejny kod:
COleDateTime dtMin, dtMax;
m_MyMonthCal.GetSeIRange(dtMin, dtMax) ;
COleDateTimeSpan dtSpan = dtMax - dtMin;
AfxMessageBox(dtSpan.Format("You Selected %D Days")) ;
Liczba wybranych dni obliczona zostaje poprzez odjęcie daty najpóźniejszej od najwcześniejszej i
zapisanie różnicy w obiekcie COleDateTimeSpan, dtSpan. Okno komunikatu wyświetli wtedy
otrzymaną różnicę, jako liczbę wyselekcjonowanych dni.
Manipulowanie obiektami COleDateTimeSpan
Wartość odstępów pomiędzy datami można ustalać przekazując funkcji SetDateTi-meSpanO
parametry w postaci liczb całkowitych, reprezentujących liczbę dni, godzin, minut oraz sekund.
Obecne wartości zapisane w obiekcie COleDateTimeSpan pobrać można za pomocą funkcji: GetDays
(), GetHours (), GetMinutes () oraz Get-SecondsO, które zwracają cząstkowe informacje zawarte w
obiekcie, w postaci liczb typu long. Chcąc uzyskać informacje całościowe, w postaci wartości typu do-
uble wywołać należy odpowiednie funkcje: GetTotalDays (), GetTotalHours (), GetTotalMinutes()
oraz GetTotalSeconds().


Stosowanie wskaźników postępu, pasków przewijania, suwaków... 183
Reakcje na powiadomienia o zmianie wyboru daty
Możemy dodać funkcję obsługi, która będzie wywoływana, gdy użytkownik dokona
zmiany wyboru zakresu dat. Przebiega to w ten sam sposób, jak w punkcie "Dodanie funkcji
obsługi komunikatu o zmianie daty". Jedyną różnicą jest wskazywany komunikat, którym w
tym przypadku jest MCD_SELCHANGE. Po umieszczeniu w programie funkcji obsługi tego
komunikatu, będzie ona miała następującą postać:
void CMonthcalDlg::OnSelchangeMonthCalendarl(NMHDR* pNMHDR,
LRESULT* pResult)
(
// TODO: ...
*pResult = 0;
}
Teraz należy dopisać właściwy kod funkcji, a następnie dokonać sprawdzenia struktury NMHDR, jak
na listingu 7.2 dla próbnika daty. Możemy również umieścić kod sprawdzający bieżący wybór,
wykorzystując funkcje GetCurSel () oraz GetSeiRange () opisane w poprzednim punkcie rozdziału.
PATRZ TAKŻE
Więcej o identyfikatorach obiektów sterujących oraz komunikatach powiadamiających mówimy w
rozdziale 4.


Wyszukiwarka

Podobne podstrony:
07 Stosowanie przepisów bezpieczeństwa i higieny pracy
07 Stosowanie podstawowych zasad toksykologii
instrukcja technologiczna postepowania z jajami stosowanymi do produkcji w zakladzie garmazeryjnym
5 Sprawozdanie o stosowaniu zasad ładu korporacyjnego w Banku BPH 07
1997 07 Wskaźnik wysterowania na matrycy 10×10LED
22 WSKAŹNIKI BIOTYCZNE STOSOWANE do oceny wody
Analiza wskaznikowa dochodow gminy przeglad stosowanyc metod
07 Wskaźniki i struktury
07 Charakteryzowanie budowy pojazdów samochodowych
9 01 07 drzewa binarne
02 07
str 04 07 maruszewski
07 GIMP od podstaw, cz 4 Przekształcenia

więcej podobnych podstron