20 Tworzenie okien z wieloma widokami


Rozdział 20
Tworzenie okien z kilkoma widokami
Statyczne i dynamiczne okna dzielone Tworzenie interfejsu
aplikacji naśladującego Eksplorator Windows
Tworzenie i obsługa aplikacji z kilkoma widokami bez korzystania
z okien dzielonych
Jak działa okno z kilkoma widokami?
Architektura dokument/widok ma kilka istotnych zalet. Najważniejszą z nich są stan-
dardowe funkcje wbudowane w klasy MFC, znacznie ograniczające ilość pracy, którą
programista musi wykonać przy tworzeniu aplikacji. Tak jak to mówiliśmy we wcześniejszych
rozdziałach, klasy te obsługują tworzenie i działanie dokumentów, dokowanie pasków
narzędziowych, wyświetlanie paska narzędziowego i wiele innych rzeczy.
Dodatkowo oddzielenie kodu obsługującego dane (dokument) od kodu obsługującego
interfejs użytkownika (widok) czyni program bardzo plastycznym, pozwalając bez trudu
dostosowywać jego strukturę do naszych potrzeb. Dzięki temu można na przykład wyświetlać
te same dane w kilku widokach. W ten sposób można na przykład wyświetlać dwie różne
sekcje tego samego dokumentu lub schematu lub dane liczbowe w jednym widoku i oparty na
nich wykres w drugim. Nie jesteśmy przy tym ograniczeni do dwóch widoków i
pojedynczemu dokumentowi możemy przypisać dowolną liczbę widoków.
Okna z kilkoma widokami można utworzyć na kilka sposobów. Możemy w tym celu
wykorzystać okno dzielone (ang. splitter window) dzielące okno obramowujące na kilka
paneli, z których każdy zawiera osobny widok. Wiele aplikacji korzysta z tego sposobu.
Eksplorator Windows korzysta z okna dzielonego, dzieląc okno obramowujące na dwie części:
drzewo dysków i folderów po lewej stronie i listę plików po prawej. Niektóre typy kontrolek z
zakładkami również mogą być wykorzystywane do dzielenia okna na części umożliwiając
przełączanie się między poszczególnymi kartami. Z tego sposobu korzysta Excel.


512 Poznaj Visual C++ 6
Korzystanie z okna dzielonego
Wykorzystanie okien dzielonych (ang. splitter window) jest jednÄ… z najpowszechniejszych
metod prezentowania kilku widoków wewnątrz jednego okna obramowującego. Okno dzielone
osadzone jest w oknie obramowujÄ…cym i wykorzystuje siÄ™ je do tworzenia oddzielnych paneli.
Każdy panel zawiera własny widok. Widoki te mogą być tej samej klasy lub też zupełnie
różnych klas. Wewnątrz aplikacji MDI (wielodokumentowej) każdy widok umieszczony jest
w osobnym oknie obramowującym; w tym przypadku okna dzielone mogą być
implementowane osobno w każdym oknie potomnym.
Okno obramowujące może być dzielone zarówno w pionie, jak i w poziomie, także liczba
paneli nie jest niczym ograniczona. Użytkownik może dowolnie zmieniać wymiary paneli
przeciÄ…gajÄ…c pasek dzielÄ…cy (ang. splitter bar) za pomocÄ… myszy. IstniejÄ… dwa typy okien
dzielonych: statyczne i dynamiczne. Klasa csplitterWnd pozwala tworzyć oba rodzaje.
Tworzenie dynamicznych okien dzielonych
Okno obramowujące z dynamicznym oknem dzielonym wyświetla dodatkowe panele
dopiero wtedy, gdy użytkownik wybierze w pasku narzędziowym okna pole dzielące (ang.
splitter box). Początkowo cały obszar roboczy (ang. client area) jest zajęty przez pierwszy
widok (lewy górny panel). Po przeciągnięciu pola dzielącego w obręb tego widoku pojawia się
pasek dzielący i okno obramowujące dzielone jest na panele, z których każdy zawiera osobny
widok. Podzielenie okna obramowującego powoduje, że konstruowane są niezbędne,
wypełniające panele widoki. Panele mogą zostać usunięte poprzez przeciągnięcie paska
dzielącego do jednego z końców paska przewijania. Po usunięciu panelu, odpowiedni obiekt
widoku jest niszczony.
Panele dynamicznego okna dzielonego sÄ… zazwyczaj wykorzystywane do przedstawiania
dwóch różnych obszarów tego samego widoku i dlatego zazwyczaj przypisana jest im ta sama
klasa widoku. Przykładem może być okno edytora tekstu dostępne w Developer Studio, które
zawierać może okna dzielone zarówno w pionie, jak i w poziomie.
SÄ… trzy podstawowe sposoby dodawania do aplikacji dynamicznych okien dzielonych.
Jeśli chcemy od razu dołączyć okna dzielone do aplikacji, możemy je wprowadzić za pomocą
kreatora AppWizard. Aby natomiast dołączyć dynamiczne okna dzielone do istniejącej już
aplikacji można albo napisać odpowiedni kod ręcznie, albo dołączyć komponent Splitter Bar
dostępny w Components and Controls Gallery. Najprościej jest oczywiście skorzystać z
kreatora AppWizard. Rozwiązanie to ma tę przewagę, że w ten sposób automatycznie
dodajemy do menu ,View opcję Sfilit uaktywniającą pole dzielące, które pozwala później
użytkownikowi dowolnie regulować rozmiary dodawanych dynamicznie paneli widoków.


Tworzenie okien z kilkoma widokami 513
AppWizard i polecenie Split
Kiedy w kreatorze AppWizard wybierzemy opcjÄ™ Use Split Window, do menu Window aplikacji
dodawane jest polecenie Split (Podziel). Jeśli natomiast zamierzamy dodawać okna dzielone do już
istniejącej aplikacji, identyfikator (J_D) tego polecenia będzie miał postać: ID_WINDOW_SPLIT.
Teraz wykorzystamy kreator AppWizard do utworzenia nowego projektu DSplit. Na czwartej stronie
kreatora klikamy przycisk Advanced i wybieramy kartę Window Styles. Następnie, tak jak pokazaliśmy
na rysunku 20.1, zaznaczamy opcjÄ™ Use Split Window.
Wreszcie na stronie szóstej kreatora wybieramy jako klasę bazową widoku klasę CScrollview.




D ocument T emplate S trings Windom S
tyłeś |7 lOse split windom
1^ ;use splitwini •Mainframe styles 17
Ihickhame F? Mjnimize box F Mamase bo^
P' System menu
T Mirwnized
F Maymized


r 'n
r M:
r •^
r w r
M.






Rysunek 20. l. Okno dialogowe Advanced Options kreatora AppWizard
Aby dodać do gotowej aplikacji SDI lub MDI dynamiczne okna dzielone, należy wykonać czynności
opisane w przedstawionym niżej algorytmie. Algorytm ten zamieszczony został tylko w celach
poglądowych i nie jest częścią przykładu DSplit.
Dodawanie do programu komponentu Splitter Bar
1. W kompilatorze Developer Studio otwórz projekt, do którego chcesz dołączyć dynamiczne paski
dzielÄ…ce.
2. W menu Project wybierz polecenie Add to Project, a w odpowiednim podmenu Comnpnents and
Controls. Pojawi siÄ™ okno dialogowe Components and Controls Gallery.
3. Kliknij dwukrotnie folder Visual C^ Components.


514 Poznaj Visual C++ 6
4. Tak jak to pokazano na rysunku 20.2, z listy komponentów wybierz Splitter Bar. Klikając
w tym momencie przycisk Morę Info wyświetlisz dodatkowe informacje na temat
dodawanego komponentu.
5. Kliknij przycisk Insert. W oknie dialogowym Insert the Splitter Bar Component
kliknij OK. Pojawi się okno dialogowe Splitter Bar pozwalające wybrać odpowiednie
opcje paska dzielÄ…cego (rysunek 20.3).
6. Wybierz pożądany typ paska dzielącego i kliknij OK.
7. Zamknij okno dialogowe Components and Controls Gallery.
PATRZ TAKŻE
• Algorytm opisujÄ…cy tworzenie aplikacji SDI znaleźć można w rozdziale 12.
• Szczegółowe informacje na temat klasy cscroliview znaleźć można w rozdziale 18.
• Op/s galerii Components and Controls znaleźć można w rozdziale 9.

Rysunek 20.2. Okno dialogowe Components and Controls Gallery
iliKei Bal

^^^HHx]

W sptttar bar to:




OK

o--- J
Å‚ype of split
bar: <"
Honzonta! F
yertical P-
gotK

Cance)


Hełp




Rysunek 20.3. Okno dialogowe opcji komponentu Splitter Bar


Tworzenie okien z kilkoma widokami 515
Inicjalizacja dynamicznych okien dzielonych
Niezależnie od tego, czy dodajemy dynamiczne okno dzielone do aplikacji za pomocą kreatora
AppWizard, czy galerii Components and Controls, dołączony do programu kod będzie identyczny. Obiekt
klasy csplitterWnd jest wbudowywany jako element składowy do klasy CMainFrame (w aplikacji MDI
cchildFrame). Obiekt okna dzielonego pokrywa cały obszar roboczy okna obramowującego i zarządza
tworzeniem i niszczeniem odpowiednich okien widoków. W przykładzie DSplit znajduje się następująca
chroniona zmienna składowa klasy CMainFrame:
CSplitterWnd m_wndSplitter;
Okno dzielone jest tworzone w pokrywanej funkcji CMainFrame: :OnCreateClient, tak jak to
pokazaliśmy na listingu 20.1. Funkcja ta jest przyzywana w procesie tworzenia okna wewnątrz funkcji
CFrameWnd: :OnCreate. Domyślnie, wpisywany przez kompilator kod funkcji tworzy obiekt widoku
dopasowując jego rozmiary tak, aby pokrył cały obszar roboczy okna obramowującego. Funkcja
pokrywająca najpierw tworzy okno dzielone, a następnie inicjalizuje je tworząc obiekt View. Następne
widoki tworzone będą wówczas, kiedy użytkownik zdecyduje się podzielić okno obramowujące.
Listing 20.1. LST21_1.CPP - tworzenie dynamicznego okna dzielonego wewnÄ…trz funkcji
_________OnCreateClient_________________________________________
1 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
2 CCreateContext* pContext)
3 (
4 return m wndSplitter.Create(this,
5 2,2, II TODO: Ustalamy liczbę kolumn i rzędów
6 CSize(10, 10), // TODO: Ustalamy minimalny rozmiar panelu
7 pContext) ;
8 }
O Pokrywamy funkcję OnCreateClient, aby utworzyć okna dzielone. @ Tworzymy
okno dzielone podając pożądaną liczbę rzędów i kolumn.
Funkcji Create okna dzielonego (linia 4) można przypisać nawet do siedmiu parametrów. Pierwszy
parametr this jest wskaźnikiem do okna rodzica. Drugi i trzeci definiują odpowiednio maksymalną liczbę
rzędów i kolumn, na które można będzie podzielić okno (Unia 5). Klasa CSplitterWnd pozwala na tylko
jeden pionowy i jeden poziomy pasek dzielący, dlatego podana tutaj liczba rzędów oraz kolumn może
wynosić tylko l lub 2. Przykładowo, jeden rząd i dwie kolumny oznaczają pojedynczy, pionowy pasek
dzielÄ…cy.


516 Poznaj Visual C++ 6
Tworzenie okien w trakcie działania programu
Najprościej jest tworzyć okno dodając kontrolki do szablonu w trakcie projektowania programu, jeśli
jednak chcemy dodać kontrolkę w trakcie działania programu, należy skorzystać z funkcji CEdit:
:Create. Funkcja Create pozwala dynamicznie przywołać do życia okno dowolnego typu. Tworzenie
okna w trakcie działania programu zawsze przebiega w dwóch etapach. Najpierw konstruujemy
odpowiedni obiekt klasy okna (przykładowo CEdit, CComboBox), a następnie przywołujemy jego
funkcję Create przesyłając jej styl okna, wymiary, jego okno rodzica i numer identyfikacyjny
kontrolki.
Czwarty parametr c s iż e definiuje minimalną wysokość rzędu i minimalną szerokość kolumny
(linia 6). Nowy widok jest tworzony tylko wtedy, gdy użytkownik zaznaczy większy panel niż
zdefiniowane tu minimalne rozmiary. Usuwany jest natomiast wtedy, kiedy panel zostanie zmniejszony
poniżej tych minimalnych wymiarów. Odpowiednie ustawienia mogą być zmieniane w trakcie działania
programu za pośrednictwem funkcji SetRowinfo i SetColumninfo. Piąty parametr jest wskaźnikiem do
obiektu CCre-ateContext. Obiekt ten zawiera bieżące informacje o klasach dokumentu, widoku i okna
obramowującego. Struktura pContext została już wcześniej inicjalizowana i jest przesyłana do funkcji
Create w linii 7.
Ostatnie dwa parametry są opcjonalne. Szósty definiuje styl okna. Standardowe style to WS_CHILD l
WS_HSCROLL | WS_VSCROLL | SPLS_DYNAMIC_SPLIT. Ostatni parametr jest identyfikatorem okna
potomnego. O ile nie zamierzamy wbudowywać w okno dzielone kolejnych okien dzielonych, najlepiej
pozostać przy domyślnej wartości AFX_IDW_ PANE_FIRST. Aby uruchomić w programie dynamiczne okna
dzielone, należy dokonać edycji dwóch funkcji CDSplitView tak jak to pokazaliśmy na listingu 20.2.
Listing 20.2. LST21_2.CPP - dynamiczne okna dzielone
1 void CDSplitView::OnDraw(CDC* pDC)
2 {
3 CDSplitDoc* pDoc = GetDocument();
4 ASSERT_VALID(pDoc) ;
5
6 // TODO: Tutaj dodaj kod wyświetlający własne dane
7 TEXTMETRIC tm;
8 int nLineHeight;
9
10 // ** Pobierz bieżące rozmiary czcionki i wylicz wysokość linii
11 pDC->GetTextMetrics(&tm);
12 nLineHeight = tm.tmHeight + tm.tmExternalLeading; O


13
14 // ** Wyświetl 50 linii tekstu
15 CString str;
16 for(int nLine = l; nLine < 51; nLine++)
17 {
18 str .Format ("LinÄ™ %d - I must NOT feed my homework. to my
Åšdog.", nLine) ;
19 pDC->TextOut(5, nLine * nLineHeight, str); @
20 }
21 }
22
23 void CDSplitView::OnInitialUpdate()
24 {
25 CScrollView::OnInitialUpdate() ;
26
27 CSize sizeTotal;
28 // TODO: Wylicz całkowite wymiary widoku
29
30 • // ** Zdefiniuj caÅ‚kowity rozmiar przewijanego obszaru jako 1000x1000
31 sizeTotal.ex = sizeTotal.cy = 1000;
32 SetScrollSizes(MM_TEXT, sizeTotal); ®
33 )
O Wyliczamy wysokość linii tekstu w oparciu o rozmiary bieżącej czcionki. @
Wyświetlamy tekst na ekranie.
© Zdefiniowanie rozmiarów przewijanego obszaru jako 1000x1000 pikseli wymusza
wyświetlenie pasków przewijania.
Ręczna edycja jest jedynie potrzebna, gdy w linii 31 zmieniamy rozmiary przewijanego obszaru z
100 na 1000 pikseli. W ten sposób logiczny (całkowity) rozmiar widoku jest większy niż rozmiar
fizyczny (wyświetlany na ekranie), co powoduje wyświetlenie pasków przewijania. Funkcja pokrywająca
OnDraw wyświetla 50 linii tekstu. Aby obliczyć rozmiar bieżącej czcionki wybranej w obiekcie
kontekstu urzÄ…dzenia (ang. deyice context), w linii 7 deklarujemy, a w linii 11 inicjalizujemy za pomocÄ…
funkcji CDC :: GetTextMetrics strukturÄ™ TEXTMETRIC.
Po zbudowaniu i uruchomieniu aplikacji możemy wybrać jedno z pól dzielących i przewinąć
wyświetlony w nim fragment widoku. Warto zauważyć, że paski przewijania ob-


518 Poznaj Visual C++ 6
sługują zarówno przewijanie widoków w pionie, jak i w poziomie. Na rysunku 20.4 można
zobaczyć przykładowe okno programu DSplit.
Wistv* y"«

iap'B F' ^v. s ? r11111111'11111 -' : - 11111

LInc 1
-

must NOT fecd my homework to my
dog.

Li
n
Ä™

1 -

must NOT leed my ho^nework 10 my
dog. -'J

LinÄ™ 2
-

must NOT feed my homework to my
dog.

Li
n
Ä™

2-

must NOT feed my homework to my
dog.j

Li
n

3-

must NOT feed my homework to my
dog.

Li
n
Ä™

3-

must NOT teed my homework to my
dog.

Li
n

4-

must NOT leed my homework to my
dog. ::

Li
n
Ä™

4-

musi NOT feed my homework to my
dog.

Li
n

5-

musi NOT feed my homework to my
dog.

U
n
e

5-

must NOT feed my homework to my
dog.

Li
n

6-

must NOT feed my homework lo my
dog.

LI
n
c

6-

must NOT feed my homework to my
dog.

Li
n

7-

must NOT feed my homework to my
dog.

Li
n
Ä™

7-

musi NOT feed my homework to my
dog.

Li
n

8-

musi NOT feed my homework to my
dog. i:

U
n
e

8-

must NOT fecd my homework to my
dog.

Li
n

9-

must NOT feed my homework to my
dog. j

U
n
e

9-

must NOT feed my homework to my
dog.

Li
n

10-1 must NOT feed my homework to my
dog. :

U
n
e

10-1 musi NOT feed my homework to my
dog. -r |

Li
n

40
-

must NOT feed my homework to my
dog.

U
n
e

48
-

must NOT feed my homework to my
dog. ti

Li
n

41
-

musi NOT leed my homework to my
dog. ::

U
n
e

41
-

must NOT (eed my homework to my
dog.

Li
n

42
-

must NOT feed my homework to my
dog.

U
n
e

42
-

must NOT feed my homework to my
dog.

Li
n

43
-

must NOT feed my homework lo my
dog.

Li
n
Ä™

43
-

musi NOT feed my homework to my
dog.

Li
n

44
-

must NOT leed my homework to my
dog.

U
n
e

44
-

must NOT feed my homework to my
dog.

Li
n

45
-

must NOT feed my homework to my
dog.

U
n
e

45
-

must NOT feed my homework to my
dog. :

Li
n

46
-

must NOT feed my homework (o my
dog. ii

U
n
e

4
G-

must NOT feed my homework to my
dog. •'••:.

Li
n

47
-

must NOT fecd my homework to my
dog. :

Li
n
Ä™

47
-

musi NOT feed my homework to my
dog. i

Li
n

46
-

must NOT leed my homework to my
dog. ::

U
n
e

c4
a-

must NOT feed my homework to my
dog. : i j

Li
n

49
-

must NOT feed my homework to my
dog.

Une
49 -

must NOT feed my homework to my
dog. '"J

Li
n

50
-

must NOT feed my homework to my
dog. :

Une
50 -

musi NOT fecd my homework to my
dog.

<Å‚ l >\

.Å‚teN- ;afl":l:;li:s1 . ,, . :r

:s*/ ! ! ' 11/;, ^"^..Wiy1^- .^^^p^M^^sssiSĘiS'ys:^

Rysunek 20.4, Program DSplit
PATRZ TAKŻE
* Więcej na temat klas MDI znaleźć można w rozdziale 21.
* Więcej informacji na temat kontekstu urządzenia znaleźć można w rozdziale 15.
Tworzenie statycznych okien dzielonych
Okno obramowujące zawierające statyczne okno dzielone już na starcie podzieleń jest na
dwa panele. Liczba paneli, ich wstępne ustawienie i klasy widoków definiowane s w momencie
tworzenia okna obramowującego. Również w tym momencie tworzone s;i obiekty widoków.
Inaczej niż w dynamicznych oknach dzielonych, użytkownik nie mo/.e usuwać wyświetlonych
w oknie paneli. Obiekty widoków są wbudowane na stałe i nie są konstruowane ani niszczone
na bieżąco. Pasek dzielący jest zawsze widoczny na ekranie, a przeciągany zatrzymuje się,
kiedy próbujemy zmniejszyć panel poniżej minimalnych dopuszczalnych rozmiarów.
Żeby utworzyć aplikację podobną z wyglądu do Eksploratora Windows, który wyko-
rzystuje pasek dzielÄ…cy do odseparowania lewego panelu z widokiem Tree od prawego z
widokiem List, należy skorzystać z pomocy kreatora AppWizard. Więcej na ten temai
powiemy za chwilÄ™ w podrozdziale "Tworzenie aplikacji podobnej do Eksploratora Win
dows". Drugim sposobem na dodanie statycznego okna dzielonego jest ręczne wpisaniu
odpowiedniego kodu. Aby obejrzeć odpowiedni kod statycznego okna dzielonego, należ\ za
pomocą kreatora AppWizard utworzyć nowy projekt SDI o nazwie SSplit. Na szóstej stronie
kreatora należy jako bazową klasę widoku wybrać klasę CEditview.


Tworzenie okien z kilkoma widokami____________________________519
Inicjalizacja statycznego okna dzielonego
W zależności od aplikacji, panele statycznego okna dzielonego wyświetlają różne rodzaje widoków i
mogą być przypisane różnym klasom widoków. Za pomocą kreatora AppWizard utworzymy nowy
projekt aplikacji SDI, SSplit. W kroku szóstym wybieramy jako klasę bazową klasę CEditview.
Modyfikowanie wyglądu pasków dzielących
Aby zmodyfikować wygląd pasków dzielących, należy wywieść z klasy csplit-terWnd własną podklasę
i pokryć w tej podklasie wirtualną funkcję OnDrawSplit-ter (). Funkcji należy przesłać parametr
porządkowy informujący, który element okna dzielonego ma zostać malowany. Do wyboru mamy
splitBox, splitBar, splitln-
tersection i splitBorder.
W tym projekcie dodamy fragmenty kodu implementujÄ…ce statyczne okno dzielone i drugÄ… klasÄ™
widoku. Statyczny pasek będzie dzielił okno w pionie na lewy panel, w którym umieścimy widok
wywiedziony z klasy CEditview i prawy, goszczący widok wywiedziony z klasy cview. Gdy już
utworzymy odpowiedni projekt, należy wykonać poniższe czynności.
Wywodzenie własnej klasy za pomocą kreatora CIassWizard
1. Aby uruchomić kreator CIassWizard, wciśnij Ctri+W lub w menu yiew wybierz polecenie
CIassWizard.
2. Kliknij przycisk Add Ciass, a następnie w liście, która się pojawi wybierz New. Wyświetlone zostanie
okno dialogowe The New Ciass.
3. W polu Name wpisz nazwę nowej klasy. W tym przykładzie CArtView.
4. W liście kombinowanej Base Ciass wybierz klasę bazową CView. Teraz kliknij OK, żeby dodać
nowÄ… klasÄ™.
5. Aby zamknąć okno dialogowe CIassWizard kliknij OK.
Teraz, gdy już utworzyliśmy nową klasę widoku, możemy dołączyć do programu kod statycznego
okna dzielonego. W tym celu najpierw dodajemy do klasy CMainFrame chronioną zmienną składową
typu CSplitterWnd. Zmiennej składowej nadajemy nazwę m_wndSplitter. Teraz należy dołączyć do
programu statyczne okno dzielone, tak jak to pokazaliśmy w instrukcji, a następnie przeedytować funkcję
CMainFrame: OnCreateClient, tak jak to widać na listingu 20.3.
Dołączanie do programu statycznego okna dzielonego
l. Aby uruchomić kreator CIassWizard, wciśnij Ctri+W lub w menu Yiew wybierz polecenie
CIassWizard.


520_____________________________________Poznaj Visual C++ 6
2. Wybierz kartÄ™ Message Maps.
3. Z listy kombinowanej Ciass Name wybierz klasÄ™ CMainFrame.
4. Z listy Object IDs wybierz CMainFrame.
5. Z listy Messages wybierz OnCreateClient i kliknij przycisk ^dd Function.
6. Wciśnij przycisk Ędit Code.
Listing 20.3. LST21_3.CPP - tworzenie statycznego okna dzielonego w funkcji OnCreateClient
1 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT Ipcs, ÅšCCreateContext* pContext)
2 {
3 // TODO: Tu dodaj własny kod i/lub przywołaj funkcję klasy bazowej
4 // ** Utwórz statyczne okno dzielone V
5 if (!m_wndSplitter.CreateStatic(this, l, 2))
6 • return FALSE;
7
8 // ** Utwórz dwa widoki i dodaj je do paneli okna
9 if (!m_wndSplitter.CreateView(0, O, RUNTIME_
CLASS(CSSplitView), CSize(150, 100), pContext) II
10 !m_wndSplitter.CreateView(0, l, RUNTIME_CLASS(CArtYiew), @ ÅšCSize(100, 100), pContext))
11 {
12 m_wndSplitter.DestroyWindow();©
13 return FALSE;
14 }
15
16 // ** Poinformuj, że operacja zakończyła się sukcesem
17 return TRUE;
18 }
O Tworzymy statyczne okno dzielone o jednym rzędzie i dwóch kolumnach (dzielimy okno w
pionie).
© Tworzymy widok dla każdego z dwóch paneli okna. © JeÅ›li proces tworzenia okna nie
zakończył się sukcesem, usuwamy okno.


Tworzenie okien z kilkoma widokami 521
Należy pamiętać, aby na początku pliku MainFrm.cpp dodać następujące dyrektywy
Å‚include:
Å‚include "SSplitView.h" Å‚include
"Artview.h"
Należy również do pliku SSplitView.h przed linią zawierającą definicję klasy dodać
wstępną deklarację dokumentu. Ten zabieg jest niezbędny z powodu porządku, w jakim
załączane będą pliki nagłówka. Dodajemy następującą linię:
ciass CSSplitDoc;
ponad liniÄ…:
ciass CSSplitView : public CEditView
Aby utworzyć statyczne okno dzielone, zamiast wzywanej przy dynamicznym oknie
dzielonym funkcji Create, korzystamy z funkcji CreateStatic.
Funkcja tworząca statyczne okno dzielone CreateStatic może posiadać do pięciu
parametrów. Pierwszy parametr this jest wskaźnikiem do okna rodzica. Drugi i trzeci definiują
odpowiednio liczbę rzędów i kolumn. W linii 5 zdefiniowaliśmy jeden rząd i dwie kolumny,
co spowoduje, że okno zostanie przedzielone na pół pionowym paskiem. Ostatnie dwa
parametry są opcjonalne. W czwartym parametrze można zdefiniować styl okna. Ostatni, piąty
parametr, jest identyfikatorem okna potomnego. O ile nie chcemy umieszczać w oknie
dzielonym kolejnych okien dzielonych, należy skorzystać z domyślnego parametru
AFX_IDW_PANE_FIRST.
Liczba rzędów i kolumn statycznego okna dzielonego
W odróżnieniu od dynamicznych okien dzielonych, które są ograniczone do maksimum
dwóch rzędów i dwóch kolumn, statyczne okna dzielone mogą mieć nawet szesnaście
rzędów i kolumn. Niemniej zbyt duża liczba rzędów i kolumn uczyni interfejs aplikacji zbyt
niewygodnym dla użytkownika.
Obiekt widoku dla każdego z paneli jest tworzony za pomocą funkcji CreateView, którą wzywamy
w linii 9 i w linii 10. Pierwsze dwa parametry funkcji to numer rzędu i kolumny, w której widok jest
umieszczany. Trzeci parametr jest wskaźnikiem do klasy bieżących informacji o klasie widoku
(informacji czasu wykonania, ang. runtime informa-tion). Klasa ta musi wywodzić się koniec końców z
klasy cwnd, jednak najczęściej wywodzona jest z klasy cview. Czwarty parametr klasy csize definiuje
minimalną wysokość rzędu i szerokość kolumny. Wartości te można zmieniać w trakcie działania
programu za pomocą funkcji SetRowinfo i SetColumninfo. Piąty parametr jest wskaźnikiem do obiektu
CCreateContext. Obiekt ten zawiera bieżące informacje o klasach okna obra-mowującego i dokumentu.
Struktura pContext została już inicjalizowana w funkcji CFra-mewnd: :OnCreateClient, dlatego można ją
bez żadnych dodatkowych zabiegów przesłać do funkcji CreateView.




522 Poznaj Visual C++ 6
Na końcu funkcji okno zostaje albo usunięte, albo jeśli tworzenie okna zakończyło się sukcesem,
funkcja zwraca po prostu (w linii 17) wartość TRUE.
Aby obejrzeć działanie statycznego okna dzielonego z panelami wyświetlającymi dwa różne widoki,
należy przeedytować funkcję CArWiew: OnDraw tak jak to widać na listingu 20.4.
Listing 20.4. LST21_4.CPP - pokryta funkcja OnDraw
1 void CArtView::OnDraw(CDC* pDC)
2 (
3 CDocument* pDoc = GetDocument(); O
4
5 // TODO: Tutaj dodaj własny kod malujący okno
6 l / ** Zachowaj bieżący pędzel
7 CBrush* pOldBrush = pDC->GetCurrentBrush(); @
8
9 // ** Utwórz niebieski pędzel
10 CBrush br;
11 br.CreateSolidBrush(RGB(0,0,255)); ®
12
13 // ** Wybierz niebieski pędzel w kontekście urządzenia
14 pDC->SelectObject(&br); O
15 pDC->Ellipse(l, l, 300, 300); ©
16 br.DetachO; ©
17
18 br.CreateHatchBrush(HS_FDIAGONAL, RGB(255,255,0)); Q
19 pDC->SelectObject(&br);
20 pDC->Ellipse(50, 50, 200, 200); ©
21
22 // ** Przywróć dawny pędzel
23 pDC->SelectObject(p01dBrush); ©
24 }
O Wywołujemy funkcję GetDocument (), aby wydobyć wskaźnik do klasy dokumentu aplikacji
@ Pobieramy wskaźnik do pędzla aktualnie przechowywanego w kontekście urządzenia p DC
© Tworzymy pÄ™dzel malujÄ…cy na niebiesko
O Przypisujemy nowy pędzel kontekstowi urządzenia
© Rysujemy dużą elipsÄ™


Tworzenie okien z kilkoma widokami 523
© Separujemy pÄ™dzel od kontekstu urzÄ…dzenia
Q Tworzymy żółty pędzel, który będzie malował ukośne linie pod kątem 45 stopni
© Malujemy maÅ‚Ä… elipsÄ™
© Przywracamy oryginalny pÄ™dzel kontekstu urzÄ…dzenia
Funkcja CArtView: :OnDraw wzywana jest, gdy trzeba odmalować prawy panel. Funkcja rysuje
dwa okręgi (w oparciu o funkcję rysującą elipsę), jeden wypełniony kolorem niebieskim, a drugi
ukośnymi żółtymi liniami. Parametry pozycyjne przesyłane w liniach 15 i 20 do funkcji rysujących,
takich jak CDC: :Ellipse są definiowane w odniesieniu do panelu, w którym rysujemy.
Po zbudowaniu i uruchomieniu aplikacji będziemy mogli obejrzeć okno programu SSplit takie jak
na rysunku 20.5.

Rysunek 20.5. Program SSplit
Tworzenie aplikacji podobnej do Eksploratora Windows
Bardzo dobrym przykładem aplikacji z wieloma widokami jest Eksplorator Windows. Pionowy
statyczny pasek dzielÄ…cy oddziela obydwa panele: lewy zawierajÄ…cy widok Tree i prawy goszczÄ…cy
widok List. W naszym przykładzie utworzyliśmy podobnie wyglądającą aplikację opisującą schemat
produkcji w fabryce. Widok drzewa przedstawia hierarchię pracowników i maszyn, a lista po prawej
zadania do wykonania. Kreator AppWizard pozwala w prosty sposób utworzyć aplikację tego typu.
Poniżej zamieszczamy opcje, które trzeba włączyć, aby uzyskać pożądany efekt.


524 Poznaj Visual C++ 6
Tworzenie projektu podobnego do Eksploratora Windows
1. Utwórz nowy projekt kreatora AppWizard (exe).
2. Na pierwszej stronie kreatora wybierz jeden z dwu przełączników Single Document albo Multiple
Documents.
3. Upewnij się, że została zaznaczona opcja Document/yiew Architecture Support?.
4. Na stronie czwartej kreatora wciśnij przełącznik Windows Ęxplorer.
Wybranie w kreatorze AppWizard opcji Windows Ęxplorer Style spowoduje utworzenie szkieletowej
aplikacji z dwoma klasami widoku: wywiedzionÄ… z klasy CTeeView klasÄ… CLeftView i klasÄ… widoku
wywiedzionÄ… z klasy CListYiew. Statyczny pasek rozdzielajÄ…cy jest automatycznie wbudowywany w okno
obramowujÄ…ce, a odpowiedni kod tworzÄ…cy widok jest dodawany do pokrywajÄ…cej odpowiedniÄ… funkcjÄ™
wirtualnÄ… funkcji OnCreateClient. Obie klasy widoku powiÄ…zane sÄ… z tym samym dokumentem i posiadajÄ…
odpowiednie funkcje GetDocument.
Kreator AppWizard dodaje również do paska narzędziowego cztery przyciski pozwalające zmieniać
styl wyświetlania w widoku List wybierając pomiędzy listą klasyczną, małymi ikonami, dużymi ikonami i
listą szczegółową. Pod paskiem narzędziowym umieszczany jest dodatkowo pasek dialogowy. Eksplorator
Windows wykorzystuje opcjonalnie dodawany pasek dialogowy do wyświetlania ponad oboma widokami
ich tytułów, my jednak możemy wykorzystać go w dowolnym celu. Aby usunąć pasek dialogowy, należy z
klasy CMainFrame usunąć zmienną składową m_wndDlgBar i tę część funkcji CMain-Frame:: OnCreate,
która odnosi się do tejże zmiennej.







Sercem widoku Tree jest kontrolka Tree
Klasa CTreeView tak naprawdÄ™ jest obudowaniem dla wykorzystywanej w oknach dialogowych
klasy CTreeCtrI. Wersja drzewa wykorzystywana w widoku jest automatycznie dopasowywana do
rozmiarów obszaru roboczego okna i jest automatycznie rozciągana, gdy zmienia się wymiary
okna obramowującego. Można również dodać do niej odpowiednie funkcje obsługi komunikatów,
pozwalające jej obsługiwać polecenia menu i paska narzędziowego. Do ukrytej wewnątrz widoku
kontrolki można sięgać za pomocą funkcji GetTreeCtrl ().







Klasa lewego panelu CLeftView jest zawsze wywodzona z klasy CTreeView i jej klasy bazowej nie
można zmienić za pomocą kreatora AppWizard. Można natomiast zmienić klasę bazową prawego panelu.
Na stronie szóstej kreatora AppWizard można w liście kombinowanej Base Ciass wybrać klasę dla
prawego panelu. Kreator tworzy szkielet aplikacji, my natomiast jesteśmy odpowiedzialni za wypełnienie
odpowiednimi danymi widoku Tree i za kod widoku z prawego panelu.


Tworzenie okien z kilkoma widokami 525
PATRZ TAKŻE
• WiÄ™cej na temat klasy CTreeView znaleźć można w rozdziale 19.
• WiÄ™cej na temat klasy CListView znaleźć można w rozdziale 19.
Inne sposoby tworzenia okien z wieloma widokami
Architektura dokument/widok daje wielkie możliwości różnorodnego przedstawiania
danych. Pokazaliśmy właśnie jak korzystać z okien dzielonych, ale należy zaznaczyć, że nie
zawsze są one najlepszym rozwiązaniem, szczególnie gdy dane należy zaprezentować na wiele
różnych sposobów. Biblioteka MFC oferuje możliwość łączenia dynamicznie utworzonego
widoku z już istniejącym dokumentem. Po takim połączeniu widok będzie współdziałał z
dokumentem nie gorzej niż widok zbudowany w oparciu o szablon dokumentu.
Dodawanie i usuwanie widoków
Nowe widoki mogą być konstruowane praktycznie w dowolnym momencie. Dokument z
nowym widokiem można połączyć przesyłając wskaźnik widoku funkcji CDocu-ment:
:Addview. Widok od dokumentu odłączamy za pomocą funkcji CDocu-ment: :RemoveView,
tak jak poprzednio przesyłając jako parametr wskaźnik widoku. Funkcje te jednak nie tworzą,
ani nie niszczą obiektu widoku. Widok musi już istnieć zanim wezwiemy funkcję Addview i
musi zostać zniszczony po wezwaniu funkcji Re-moveView. Dokument posiada listę
odwołujących się do niego widoków, a te dwie funkcje po prostu zarządzają wspomnianą listą.
Widok może być powiązany tylko z jednym dokumentem
Widok może być jednorazowo powiązany z tylko jednym dokumentem. Próba wywołania po
raz drugi funkcji Addview z tym samym wskaźnikiem widoku zostanie przez program
oprotestowana.
Funkcje Addview i RemoveView są również przyzywane odpowiednio w funkcjach CView:
:OnCreate i cview: :~cview, gdy widoki są budowane w oparciu o szablony dokumentów. Obie funkcje
po wykonaniu swoich zadań przyzywają wirtualną funkcję OnChangeViewList. Funkcja CDocument:
:OnchangeViewList sprawdza, czy przechowywana w dokumencie lista widoków jest pusta i jeśli tak,
zamyka dokument przyzywając funkcję OndoseDocument. Jeśli zależy nam, żeby dokument pozostał
otwarty, mimo likwidacji ostatniego związanego z nim widoku, możemy odpowiednio pokryć funkcję
OnChangeViewList.


526_____________________________________Poznaj Visual C++ 6
ZarzÄ…dzanie tworzeniem i aktywacjÄ… widoku
Modyfikowanie tego kiedy i które widoki zostaną wyświetlone użytkownikowi, jest dość
proste, wystarczy sięgnąć do odpowiednich funkcji obsługujących działanie architektury
dokument/widok. Funkcje te pozwalają modyfikować interfejs użytkownika dodając lub
usuwając odpowiednie widoki w zależności od akcji podjętych przez użytkownika. Zbudujemy
teraz aplikację, która pozwoli użytkownikowi przełączać między różnymi widokami
zajmującymi cały obszar roboczy okna obramowującego. Najpierw za pomocą kreatora
AppWizard tworzymy projekt VPick wybierając na stronie szóstej jako klasę bazową klasę
CEditYiew. Program VPick bazuje na wcześniejszym programie SSplit, demonstruje jednak
podejście, które nie wymaga korzystania z okien dzielonych. Po utworzeniu projektu należy
wykonać czynności opisane w przedstawionym wcześniej w tym rozdziale algorytmie
"Wywodzenie własnej klasy za pomocą kreatora CIassWizard".
Użytkownik może w menu wybrać widok, który go interesuje. Dwa nowe elementy
dodajemy do menu definiujÄ…c odpowiednie identyfikatory ID_SHOW_ART_VIEW i SHOW
EDIT_VIEW oraz przypisując elementom menu odpowiednie tytuły (ang. caption). Następnie
dodajemy odpowiednie funkcje obsługi nowych poleceń menu. Funkcje obsługi w tym
przykładzie są implementowane w klasie CMainFrame, natomiast w aplikacji MDI dołą-
czalibyśmy je do klasy CChildFrame.
Dodawanie funkcji obsługi poleceń menu
1. Po uruchomieniu kreatora CIassWizard za pomocÄ… klawiszy Ctri+W lub polecenia
CIassWizard menu yiew, wybierz kartÄ™ Message Maps.
2. Z listy kombinowanej CIass Name wybierz klasÄ™ CMainFrame.
3. Z listy Object IDs wybierz identyfikator ID_SHOW_EDIT.
4. Z listy Messages wybierz COMMAND, a następnie kliknij przycisk Add Function. W oknie
dialogowym Add Member Function kliknij OK.
5. Z listy Messages wybierz UPDATE_COMNAND_UI i kliknij przycisk A.dd Function. W oknie
dialogowym Add Member Function kliknij OK.
6. Z listy Object IDs wybierz identyfikator ID_SHOW_ART.
7. Z listy Messages wybierz COMMMAND i kliknij przycisk Add Function. W oknie dia-
logowym Add Member Function kliknij OK.
8. Z listy Messages wybierz UPDATE_COMNAMD_UI i kliknij przycisk Add Function. W oknie
dialogowym Add Member Function kliknij OK.
9. Aby zamknąć okno dialogowe CIassWizard, kliknij OK.
Znaczna część kodu wykorzystywanego w funkcjach OnShowEdit i OnShowArt jest
identyczna. Zamiast więc powielać go niepotrzebnie, lepiej utworzyć pomocniczą funkcję,
która będzie przywoływana w obu wspomnianych funkcjach. Odpowiedni algorytm znajduje
się poniżej, a parametry funkcji opisane zostały dalej.


Tworzenie okien z kilkoma widokami 527
Tworzenie funkcji pomocniczej
1. W panelu ClassView wybierz klasę CMainFrame, a następnie w menu skrótów polecenie Add
Member Function.
2. W pole Function Type wpisz void.
3. W polu Function Declaration wpisz CreateActivateView (CRuntimeClass *pNew-View, UINT
nID).
4. Wciśnij przełącznik Priyate Acces i kliknij OK.
Pozostało nam teraz napisać odpowiedni kod funkcji. Aplikacja powinna działać w ten sposób, aby
użytkownik mógł wybierać pomiędzy widokiem Edit a widokiem Art za pomocą odpowiedniej opcji
menu. Wybrany widok zajmuje cały obszar roboczy okna podczas, gdy drugi pozostaje ukryty. W
zależności od tego, który z widoków jest w danym momencie aktywny, uaktywniane są lub wyłączane
odpowiednie opcje menu. FunkcjÄ™ pokrywajÄ…cÄ… CArtView:: OnDraw edytujemy tak jak na listingu 20.4.
Ta część kodu została zaczerpnięta z programu SSplit i służy tylko do wyświetlania dwóch różnych klas
widoku. Funkcje składowe klasy CMainFrame należy przeedytować, tak jak to pokazaliśmy na listingu
20.5.
Należy pamiętać, aby na początku pliku MainFrm.cpp dodać następujące dyrektywy
Å‚include:
Å‚inciude "VPickView.h" finclude
"ArtView.h"
Przed linią zawierająca definicję klasy należy dodać do pliku VPickView.h wstępną deklaracje
dokumentu. Ten zabieg jest niezbędny z powodu porządku, w jakim załączane będą pliki nagłówka.
Dodajemy następującą linię:
ciass CVPickDoc;
ponad liniÄ…:
ciass CVPickView : public CEditView
Listing 20.5. LST21_5.CPP - implementacja opcji menu pozwalających tworzyć i aktywować widoki
1 void CMainFrame::OnShowEdit() O
2 (
3 // ** Wezwij funkcję pomocniczą przesyłając jej wskaźnik
4 // ** do bieżącej klasy widoku i unikalny identyfikator
5 CreateActivateView(RUNTIME_CLASS(CEditView), l);
6 }
7
8 void CMainFrame::OnUpdateShowEdit(CCmdUl* pCmdUl)
9 (
10 // ** Włącz lub wyłącz opcję menu w zależności
11 // ** od tego, która klasa widoku jest aktywna


528 Poznaj Visual C++ 6
12 pCmdUI->Enable (
13 !GetActiveView()->IsKindOf(RUNTIME_CLASS(CEditView))); @
14 }
15
16 void CMainFrame::OnShowArt() ©
17 {
18 // ** Wezwij funkcje pomocniczą przesyłając jej wskaźnik
19 // ** do bieżącej klasy widoku i odpowiedni identyfikator
20 CreateActivateView(RUNTIME_CLASS(CArtView), 2) ;
21 }
22
23 void CMainFrame::OnUpdateShowArt(CCmdUl* pCmdUl)
24 (
25 // ** Włącz lub wyłącz opcję menu w zależności od
26 // ** tego, która klasa widoku jest aktywna
27 pCmdUI->Enable(
28 !GetActiveView()->IsKindOf(RUNTIME_CLASS(CArtView))); O
29 }
30
31 void 'CMainFrame: : CreateActivateView (
32 CRuntimeClass *pNewViewClass,
33 UINT nID)
34 {
35 // ** Zachowaj wskaźnik do aktywnego widoku
36 CView* p01dView = GetActiveView();
37 CView* pNewView = NULL;
38
39 // ** Zachowaj wskaźnik do aktywnego dokumentu, następnie
40 // ** przeszukaj widoki dokumentu poszukujÄ…c obiektu
41 // ** widoku o tej samej klasie bieżącej co przesłana
42 // ** do funkcji
43 CDocument* pDoc = GetActiveDocument();
44 POSITION pos = pDoc->GetFirstViewPosition();
45 while(pos && !pNewView)
46 (
47 CView* pView = pDoc->GetNextView(pos); @
48 if(pView->IsKindOf(pNewViewClass))
49 pNewView = pView;
50 }
51 // ** Sprawdź, czy widok został znaleziony.
52 // ** Jeśli nie, skonstruuj, utwórz i inicjalizuj widok.
53 if(pNewView == NULL)
54 (
55 // ** Inicjalizuj zmiennÄ… klasy CCrea.teCon.text zawierajÄ…cÄ…
56 // ** wskaźnik do dokumentu


Tworzenie okien z kilkoma widokami 529





57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 }
CCreateContext context;
context.m_pCurrentDoc = pDoc;
// ** Skonstruuj obiekt widoku korzystając z bieżącej
II ** klasy i utwórz okno widoku, w
pNewView = (CView*) pNewViewdass->CreateObject () ;
pNewView->Create(NULL, NULL, O,
CFrameWnd::rectDefault, O this, nID,
&context) ;
pNewView->On!nitialUpdate() ;
}
// ** Zdefiniuj nowy widok jako widok aktywny i wyświetl II ** jego okno. Ukryj okno starego
widoku. SetActiveView(pNewView) ;
pNewView->ShowWindow(SW_SHOW) ;
p01dView->ShowWindow(SW_HIDE); ©
// ** Zamień identyfikatory, gdyż identyfikator aktywnego .// ** okna widoku powinien być
AFX_IDV_PANE_FIRST. p01dView->SetDlgCtrlID(pNewView->GetDlgCtrlID() ) ; ©
pNewView->SetDlgCtrlID(AFX_IDW_PANE_FIRST) ;
// ** Rozmieść paski kontrolne i rozciągnij okno. RecalcLayout() ;





O Funkcja obsługi polecenia menu.
@ Wyłączamy polecenie menu, gdy aktywna jest klasa CEditView, jeśli nie, uaktywniamy polecenie.
© Funkcja obsÅ‚ugi polecenia menu.
O Wyłączamy polecenie menu, gdy aktywna jest klas CArtView, jeśli nie, uaktywniamy polecenie.
© Przeszukujemy listÄ™ widoków dokumentu w poszukiwaniu odpowiedniej klasy widoku.
© Dynamicznie konstruujemy obiekt widoku.
Q Tworzymy widok i przyzywamy funkcjÄ™ OninitialUpdate.
© WyÅ›wietlamy nowy widok i ukrywamy stary.
@ Wymieniamy identyfikatory okien.


530_____________________________________Poznaj Visual C++ 6
Jak łatwo zauważyć, obydwie funkcje obsługi poleceń menu, OnShowEdit (linia l) i On-ShowArt
(linia 16), natychmiast odwołują się do pomocniczej funkcji CreateActiva-teView (zaczynającej się w
linii 31). Przesyłają jej dwa parametry: wskaźnik do bieżących informacji o klasie widoku i identyfikator.
Pierwszy parametr, m_pNewViewdass definiuje, jakiego rodzaju widok został wybrany. Drugi parametr
służy do identyfikowania okna widoku.
Funkcje OnUpdateShowEdit (linia 8) i OnUpdateShowArt, (linia 23) są przyzywane, każdorazowo,
gdy element menu jest odmalowywany. Sprawdzają one za pomocą funkcji cobject: : isKindOf, który z
widoków jest aktywny. W momencie, gdy klasa aktywnego widoku jest taka sama jak przesłana funkcji
klasa bieżąca, funkcja IsKindOf zwraca wartość FALSE polecając funkcji CCmdUl: :Enable wyłączyć
opcję. W ten sposób opcja związana z widokiem aktywnym będzie zawsze wyłączona, a ta związana z
widokiem nieaktywnym zawsze włączona.
Funkcja CreateActivateView (linia 31) najpierw przyzywa funkcjÄ™ GetActiveView i przechowuje
wskaźnik do widoku w zmiennej p0ldview, ponieważ poprzedni widok jest tutaj usuwany. Kolejnym
zadaniem funkcji jest sprawdzenie, czy istnieje powiÄ…zany z aktywnym dokumentem widok zapisany w
zmiennej (wskaźniku) pNewViewdass. Za pomocą funkcji GetFirstViewPosition i GetNextView (w
liniach 44-50) przeszukujemy listę widoków dokumentu. Jeśli zostanie odnaleziony widok typu
pNewViewdass, w linii 49 przypisujemy wartość wskaźnika do niego zmiennej pNewView. Warunek i f
w linii 53 sprawdza, czy widok został znaleziony, jeśli tak, musi zostać ponownie uaktywniony, jeśli nie,
musi zostać skonstruowany i aktywowany.
Makroinstrukcja ASSERTJKINDOF ()
Zamiast korzystać z funkcji IsKindOf (), dowolny obiekt dowolnej klasy wywodzącej się z klasy
cobject można przesłać do makroinstrukcji ASSERT_KINDOF() . Parametrami makroinstrukcji są nazwa
klasy i wskaźnik do obiektu klasy. Makroinstrukcja sprawdza, czy klasa obiektu jest właściwa. Jeśli
nie, wyświetlone zostaje okno dialogowe MFC Assert. Makroinstrukcja wykonywana jest tylko w
wersji projektu testowanej w debugerze, a w normalnie wykonywanym programie jest ignorowana.
W liniach 57-67 nowy obiekt jest konstruowany i tworzony. Zmienna context klasy CCreateContext
jest strukturą, której przypisywany jest wskaźnik do dokumentu. Struktura ta jest następnie w linii 62
przesyłana do funkcji Create, aby utworzyć powiązanie pomiędzy dokumentem a widokiem. Obiekt
widoku jest tworzony w linii 62. Zmienna pNewViewdass może w tym miejscu przyjmować wartość
CEditView lub CArtView. Ponieważ obie klasy pozwalają tworzyć obiekty dynamicznie, funkcja
CreateObject po prostu przyzywa odpowiedni konstruktor i zwraca wskaźnik do nowego obiektu. W linii
63 funkcja Create tworzy okno widoku i przypisuje je do obiektu wywiedzionego z klasy cview. Kiedy
już proces tworzenia widoku zostanie zakończony, przyzywana jest wirtualna funkcja OninitialUpdate ()
dokonujÄ…ca inicjalizacji widoku.


Tworzenie okien z kilkoma widokami 531
Niezależnie, czy zachodzi potrzeba skonstruowania widoku, czy nie, wybrany obiekt przesyłany jest
w linii 70 do funkcji SetActiveView, która aktywuje widok i definiuje go jako aktualnie pobierający dane
(ang. input focus). Za każdym razem, gdy widok jest aktywowany lub wyłączany, otrzymuje komunikat
OnActivateView z parametrem logicznym (BOOL) BActivate, który informuje o jego statusie. W linii 71
wyświetlamy wybrany widok, a w linii 72 ukrywamy widok zastępowany.
Aktywny widok musi być zawsze opatrzony identyfikatorem AFX_IDVPANE_FIRST, ponieważ tak
zostało to zaprogramowane wewnątrz funkcji RecalcLayout, niemniej z racji tego, że tylko jeden widok
może być aktywny, tylko jedno okno opatrzone jest tym identyfikatorem. Dlatego w linii 76 zastępujemy
identyfikator zapisany w zmiennej poi-dView identyfikatorem przechowywanym w zmiennej
pNewView, a następnie w linii 77 przypisujemy zmiennej pNewView identyfikator
AFX_IDW_PANE_FIRST. Przyzywana w linii 80 funkcja RecalcLayout odpowiada za odpowiednie
dopasowanie okna widoku i zmiany w paskach narzędziowych oraz paskach kontroli okna
obramowujÄ…cego.
Po zbudowaniu i uruchomieniu aplikacji VPick będziemy mogli wybierać jeden z dwu widoków
przedstawionych na rysunku 20.6.

Rysunek 20.6. Program VPick
ZOBACZ TAKŻE
f Menu opisane zostało dokładniej w rozdziale 13.
• WiÄ™cej informacji na temat klas MDI znaleźć można w rozdziale 21.
* Więcej na temat informacji czasu wykonania o klasie znaleźć można w rozdziale 23.


Wyszukiwarka

Podobne podstrony:
03 Projektowanie i tworzenie okien dialogowych
10 Tworzenie własnych okien dialogowych i ich klas
Brand Equity czyli rynkowe efekty tworzenia marki
tworzenie marki
tworzenie aplikacji w jezyku java na platforme android
20 Organizacja usług dodatkowych w zakładzie hotelarskim
20 rad jak inwestowac w zloto
20 3SH~1

więcej podobnych podstron