26 Tworzenie kontrolek active x


CzęŚĆ VII
Zaawansowane zagadnienia
programowania


Rozdział 26
Tworzenie kontrolek ActiveX
Tworzenie kontrolek ActiveX________
Implementowanie kart właściwości kontrolki
Tworzenie plików rejestracji i dystrybucji dla kontrolki_______
Testowanie kontrolki za pomocą testowego kontenera
Tworzenie szkieletu kontrolki ActiveX za pomocą kreatora ActiveX
Control Wizard
Do tworzenia szkieletów kontrolek ActiveX służy specjalny wariant kreatora AppWi-zard,
ActiveX Control Wizard. Kreator ten pomaga przy tworzeniu kodu, licencjonowaniu i
tworzeniu pomocy dla nowej kontrolki. Przyzywamy go wywołując okno dialogowe New za
pomocą polecenia New menu File. Jeśli otworzymy kartę Projects zobaczymy opcję MFC
ActiveX ControlWizard. Za jego pomocą utworzymy nową kontrolkę ActiveX o nazwie
Rotary (wpisywanej w polu Project Name).
Kontrolki ActiveX biblioteki Active Template Library
W tym rozdziale opisujemy kontrolki ActiveX bazujące na bibliotece MFC (Microsoft Foundation
Ciasses). Możemy jednak również tworzyć kontrolki w oparciu o bibliotekę ATL (Active Template
Library). Kontrolki ActiveX budowane w oparciu o bibliotekę ATL są generalnie rzecz biorąc znacznie
szybsze i mniej pamięciożerne niż kontrolki ActiveX zbudowane w oparciu o bibliotekę MFC. Jednak
nie możemy swobodnie mieszać i łączyć ze sobą klas MFC i ATL. Biblioteka ATL jest bardzo
skomplikowanym i rozległym tematem, znacznie przekraczającym zakres tej książki. Jeśli potrzebna
nam będzie bardzo szybka, wymagająca niewielkich zasobów pamięci, ale skomplikowana kontrolka
ActiveX, powinniśmy sięgnąć do bibliotek ATL i kreatora ATL COM AppWizard.


684 Poznaj Visual C++ 6
Definiowanie liczby kontrolek, obsługi licencjonowania i pomocy
Na pierwszej karcie kreatora MFC ActiveX ControlWizard (przedstawionej na rysunku
26.1) można zdefiniować kilka podstawowych opcji związanych z projektem nowej kontrolki
ActiveX.
MFC ActiveX ConIrolWiiard - Stąp l o(Z
Hoa/manycontrols would you tikeyour project to
have?




Would you iike the controls in this projeci
to have a runtime license?
<~ Yas. please ^ N3 nrntime
license
Would you Iike sourcefite eomwentstobe
geneisted?
^ Yes. please ("No
^orriments


Would you Iike he!p ft!as to begeneratsd? '" Yes,
please f7 No hełp flles
Emish
Rysunek 26.1. Pierwsza z dwóch kart kreatora MFC ActiveX ControlWizard
Pierwsze widoczne u góry karty pytanie brzmi: Ile kontrolek ma zawierać projekt? (How
many controls would you Iike your project to have?). Jeśli wpiszemy tu liczbę większą
niż domyślne l, kreator utworzy automatycznie klasę kontrolki i klasy kart właściwości dla
każdej dodatkowej kontrolki.
Następne pytanie brzmi: Czy chcesz, aby kontrolki tego projektu obsługiwały licen-
cjonowanie? (Would you Iike the controls in this project to have a runtime license?).
Jeśli odpowiemy, że tak (Yes, please), do klas dodane zostaną funkcje sprawdzające
licencję i utworzony zostanie domyślny plik licencji .lic. Utworzona kontrolka będzie
mogła być rozprowadzana tylko z ważnym plikiem licencji.
Następne pytanie: Czy tworzyć komentarze pliku źródłowego? (Would you Iike so-urce
file comments to be generated?), dotyczy komentarzy do kodu źródłowego dodawanych
do szkieletu aplikacji podobnie jak w kreatorze AppWizard.
Ostatnie pytanie na karcie pierwszej brzmi: Czy tworzyć pliki pomocy? (Would you Iike
hełp files to be generated?). Jeśli i na to pytanie odpowiemy tak, razem z projektem
utworzone zostaną odpowiednie pliki pomocy kontekstowej.
Definiowanie nazw klas i dodatkowych opcji
Karta druga pozwala zdefiniować wszystkie ustawienia odpowiedzialne za to, jak
kontrolka ma wyglądać i jak z niej korzystać (patrz rysunek 26.2).


Tworzenie kontrolek ActiveX 685
Selectthegonfroiwhose optionsyouwishtobrowse o r
edit. You moyedit Its dass and fits narnes flyou
wis.h
Rotsiy '] EdUNames...




Which featurss woutd you Sike ihis
confrot to ^a^e?
17 A.ctivates whenvisib!e
r" tnvistbl@ atluniime
r" Avaiiable m "lns9r!Qb(ect" dialog
F Has an "Aboul" box
r' AcTs as a simpfe tr:arne c'ontrol
Whichwindowdass,- ifany, should this :
controlsubciass'?
Wauldyou like edvanced
ActiveX enhancements?





Rysunek 26.2. Druga z dwóch kart kreatora MFC ActiveX ControlWizard
Pierwsza lista kombinowana i sąsiadujący z nią przycisk Ędit Names pozwalają zmienić domyślne
nazwy plików i klas dla kontrolki wybranej w liście. Po wciśnięciu przycisku Edit Names pojawi się lista
nazw plików i klas, które zostaną wygenerowane dla kontrolki przez kreator (rysunek 26.3).




Control
CIass Name'
jCF.otałyCtiI
HaadBfFile:
Jypa Nama
JRotały Controf






JRotatyCtl.cpp ROTARY Rolałyar11


Ptoparty Page
Ctass Narrte.
Hea^ef File:
Type yame:






RotaryFpg.h
^|Rotaiy Property Poge
Syaf!l0f-i9is
^Sj RotsiyPpg.cpp








Rysunek 26.3. Okno dialogowe Edit Names pozwala modyfikować standardowe nazwy plików i klas
szkieletu kontrolki
W oknie tym widoczna jest klasa kontrolki (CRotaryCtrl) i związana z nią klasa karty właściwości
(CRotarypropPage). Ponieważ kontrolki ActiveX są obiektami COM/OLE, po lewej karcie każdej z klas
znajdują się pola Type Name i Tvpe ID. Nazwy te będą wykorzystywane przez Visual Basie Scripting
lub inne języki, które będą korzy-


686 Poznaj Visual C++ 6
stać z kontrolki ActiveX. W oknie Edit Names można zmienić dowolną z przedstawionych tam nazw.
Jeśli zamkniemy to okno dialogowe i powrócimy do karty drugiej kreatora MFC ActiveX
ControlWizard (rysunek 26.2), pod przyciskiem pozwalającym edytować nazwy zobaczymy listę
różnych dodatkowych opcji kontrolki.
Activates when Visible. Opcja ta jest domyślnie zaznaczona i powoduje, że kontener goszczący
kontrolkę uaktywnia ją automatycznie, kiedy staje się widoczna.
Invisible at Runtime. Możemy napisać kontrolkę ActiveX, która tak naprawdę niczego nie wyświetla
(jest niewidzialna), ale może być załączona do pojemnika OLE umożliwiając mu dostęp do innych
funkcji.
Ayailable in "Insert Object" Dialog. Pole to zaznaczamy, jeśli chcemy by tworzona kontrolka
mogła być załączana do Worda, Excela lub pliku HTML.
Has an "About" Box. Dodaje do projektu okno dialogowe About (O programie).
Acts as a Simple Frame Control. Definiuje informacje o statusie pozwalające kon-trolce zawierać
wewnątrz inne kontrolki Windows.
Budowanie kontrolek ActiveX w oparciu o kontrolki już istniejące
Widoczna na dole karty lista kombinowana służy do wybierania kontrolki, której pod-klasą ma być
tworzona kontrolka (będzie ona bazą dla tworzonej kontrolki). Możemy w ten sposób rozszerzać
możliwości standardowych kontrolek Windows. Przykładowo jeśli chcemy rozszerzyć możliwości paska
przewijania, tworzymy podklasę (ang. subciassing) standardowego paska przewijania.
Zarządzanie odbitymi komunikatami kontrolki
Jednym z najważniejszych zadań związanych z tworzeniem podklasy istniejącej już kontrolki jest
obsługa komunikatów, które są przez tę kontrolkę wysyłane do jej okna rodzica. Aby komunikaty te
nie były wysyłane bezpośrednio do okna kontenera kontrolki, wywiedziona klasa kontrolki
(coleControl) tworzy fałszywe okno, działające tak jak rodzic kontrolki i przechwytuje komunikaty
przez nią wysyłane. Teraz należy przechwycić odpowiednie komunikaty kontrolki i w razie potrzeby
uruchomić w kon-trolce ActiveX odpowiednie zdarzenie.
Zaawansowane możliwości kontrolek ActiveX
Dodatkowe możliwości i funkcje kontrolek ActiveX możemy definiować po wciśnięciu przycisku
Adyanced. Będziemy mogli zdefiniować następujące opcje:


Tworzenie kontrolek ActiveX 687
Windowless Activation. Jeśli zaznaczymy tę opcję, kontrolka zamiast z własnego okna
będzie korzystać z okna kontenera. W ten sposób będzie działać znacznie szybciej, ale
będzie też trochę pracy z jej programowaniem.
" Unclipped Device Context. O ile zaprojektowana przez nas kontrolka jest dobrze
zaprogramowana i nie maluje się poza przeznaczonym jej obszarem, za pomocą tej opcji
można przyśpieszyć trochę jej działanie.
Flicker-Free Activation. Kontrolki są normalnie odmalowywane za każdym razem, gdy są
aktywowane lub dezaktywowane. Jeśli jednak wygląd kontrolki niczym się w obu stanach
nie różni, możemy zaznaczając tę opcję wyłączyć odmalowywanie kontrolki w tym
momencie.
Mouse Pointer NotiHcations When Inactive. Ustawienie tej opcji poleca interfejsowi
przetwarzać komunikaty informujące o poruszeniach myszy nawet wtedy, gdy kontrolka
pozostaje nieaktywna.
Optimized Drawing Code. Niektóre kontenery obsługują tryb, który pozwala na
zachowanie identyfikatorów obiektów GDI. wykorzystywanych w kontrolkach. Po
sprawdzeniu, czy tak jest w istocie, możemy napisać kod rysujący, korzystający z tych
przechowanych identyfikatorów.
Loads Properties Asynchronousły. Jeśli kontrolka jest osadzona na karcie sieciowej,
możemy zaimplementować do jej kodu możliwość asynchronicznego ładowania, dzięki
czemu interfejs użytkownika pojawi się tak szybko, jak to tylko możliwe. Pozostawiamy
w spokoju elementy graficzne i inne właściwości, które ładują się wolniej, dopóki nie
załadują się najważniejsze właściwości kontrolki.
PATRZ TAKŻE
ł Więcej informacji na temat korzystania z kontrolek ActiveX można znaleźć w rozdziale 9.
Tworzenie kodu kontrolki
Zadaniem kontrolki ActiveX jest umożliwienie programowi kontaktu z użytkownikiem. W
tym celu musi ona namalować na ekranie interfejs użytkownika, obsługiwać komunikaty
zdarzeń klawiatury, myszy i innych urządzeń zewnętrznych i być w stanie przekształcać te
zdarzenia do postaci takiej, którą użytkownik zrozumie, a aplikacja będzie mogła z tych
kontrolek korzystać i sięgać do nich w razie potrzeby. Zazwyczaj właściwości można
wykorzystać do tego, aby zmienić wygląd lub zachowanie kontrolki. Kontrolka jest swego
rodzaju miniaplikacją i może być prawie równie skomplikowana jak prawdziwa aplikacja.
Pisząc funkcje obsługujące komunikaty zauważymy, że do implementacji kontrolek ActiveX
wykorzystywana jest standardowa architektura MFC.


688 Poznaj Visual C++ 6
Klasy projektu kontrolki ActiveX
Tworząc kontrolkę ActiveX za pomocą kreatora w oparciu o biblioteki MFC można zauważyć, że
utworzonych zostało kilka klas implementujących szkielet kontrolki. Jedna z nich jest klasą pochodną
klasy COleControlModule i oferuje funkcje init-Instance () i Exitlnstance (). Kolejna klasa obsługuje
karty właściwości kontrolki i wywiedziona jest z klasy colepropertypage. Wreszcie główna klasa
kontrolki musi wywodzić się z klasy coieControl, która łączy poszczególne aspekty kontrolki ActiveX.
Jako że klasa coieControl wywodzi się z klasy cwnd, dostępne są w niej wszystkie funkcje dostępne
dla okna. Otrzymujemy w ten sposób znane już nam z okien dialogowych i widoków środowisko
funkcji składowych klasy cwnd.
Napiszemy teraz kontrolkę o formie pokrętła, działającą na podobnej zasadzie jak pokrętło
głośności w radiu. Wszystkim opcjom kreatora AppWizard powinniśmy w tym przykładzie
(Rotary) zostawić ich ustawienia domyślne.
Malowanie kontrolki na ekranie
Kod malujący kontrolkę na ekranie nie powinien być nam obcy, jako że stykaliśmy się z
nim przy okazji aplikacji SDI i MDI opartych na bibliotece MFC. Malowaniem kontrolki
zajmuje się funkcja OnDraw () głównej klasy kontrolki CRotaryCtrI. Jednakże parametry jej są
odrobinę inne niż zwykłej funkcji OnDraw (). Pierwszy parametr jest zwykłym wskaźnikiem
do kontekstu urządzenia, drugi odwołaniem do prostokąta przechowującego współrzędne
rogów kontrolki, a trzeci jest odwołaniem do prostokąta przechowującego współrzędne
unieważnionego obszaru kontrolki, który musi zostać odmalowany.
Aby namalować kontrolkę Rotary, musimy przekształcić komunikaty informujące o
kliknięciu myszą i jej przesunięciu na kąt nachylenia wektora poprowadzonego od środka
kontrolki do miejsca kliknięcia. Mniejsze kółko będzie rysowane, by symbolizować koniec
wektora, a większe reprezentować będzie samą kontrolkę. Linia przeprowadzona od środka
kontrolki w kierunku kliknięcia nada kontrolce wygląd zbliżony do pokrętła regulującego
głośność.
Listing 26.1. LST27_LCPP - kod funkcji OnDraw () kontrolki ActiveX
1 void CRotaryCtrI::OnDraw(CDC* pdc,
2 const CRectS rcBounds,const CRect& rclnvalid)
3 (
4 // ** Zdefiniuj pędzel tła i pędzel pokrętła
5 CBrush brForeGnd(RGB(O,255,0));
6 CBrush brBackGnd(TranslateColor(AmbientBackColor())); O
7
8 // ** Namaluj tło kontrolki


Tworzenie kontrolek ActiveX 689
pdc->FillRect(rcBounds, SbrBackGnd) ;
CBrush* pOldBrush = pdc->SelectObject(SbrForeGnd);
// ** Calculate the relative positions and midpoint CPoint ptRelative = m_ptClicked -
rcBounds.TopLeft ();
CPoint ptMid(rcBounds.Width()/2,rcBounds.Height()/2);
// ** Find offset from the middłe double dRelX = ptRelative.x -
ptMid.x;
double dRelY = ptRelative.y - ptMid.y;
// ** Ustal kąt nachylenia wektora double dAngle =
atan2(dRelY,dRelX); @ double dRadX = (double)ptMid.x * 0.9;
double dRadY = (double)ptMid.y * 0.9;
// ** Znajdź punkt końca wektora na obwodzie pokrętła int nXPos = ptMid.x + (int)(cos(dAngle)
* dRadX);
int nYPos = ptMid.y + (int)(sin(dAngle) * dRadY);
// ** Zdefiniuj środek kółka będącego uchwytem pokrętła CPoint
ptKnob=CPoint(nXPos,nYPos)+rcBounds.TopLeft() ;
// ** Zdefiniuj odmalowywany prostokąt i namaluj uchwyt CRect rcPoint(ptKnob-
CSize(4,4),CSize(8,8)) ;
pdc->Ellipse(rcPoint);
// ** Namaluj wielkie koło pokrętła pdc->Ellipse(ptMid.x-(int)dRadX,ptMid.y-
(int)dRadY,
ptMid.x+(int)dRadX,ptMid.y+(int)dRadY) ;
// ** Namaluj linię od środka pokrętła do uchwytu pdc->MoveTo(ptMid) ;
pdc->LineTo(ptKnob) ;
pdc->3elect0bject(pOldBrush) ;
O Wykorzystujemy kolor otaczającego kontrolkę kontenera, tak aby tło kontrolki nie odcinało się od
tła okna kontenera.


690 Poznaj Visual C++ 6
@ Do wyliczania odpowiedniego kąta nachylenia wektora wykorzystujemy funkcje trygonometryczne.
Funkcja rysująca elipsę jest wykorzystywana do namalowania dużego koła symbolizującego
pokrętło i małego kółka symbolizującego uchwyt na końcu wektora.
Definiowanie właściwości otoczenia
Istnieje pewien zestaw właściwości definiujących parametry otoczenia kontrolki (ang. ambient
properties) wspólnych dla wszystkich kontrolek ActiveX. Właściwości te pozwalają kontrolce lepiej
wtopić się w swoją aplikację rodzica. Ponieważ nie wiemy w jakich aplikacjach zaprojektowana
kontrolka będzie używana, najlepiej zakodować w niej tyle właściwości definiujących parametry
otoczenia, ile to tylko możliwe.
Jak widać, kod z listingu 26. l wykonuje właśnie taką operację odmalowania kontrolki. W liniach 5 i
6 definiowane są pędzle malujące kontrolkę - RGB (0,255,0), kolor zielony - oraz jej tło (funkcja
AmbientBackColorf), nadająca mu taki sam kolor jak kolor'"kontenera). Istnieje również bliźniacza
funkcja AmbientForeColor(). Funkcje te zwracają dwie właściwości definiujące parametry otoczenia
wspólne dla wszystkich kontrolek. Użyte wewnątrz kontenera pobiorą swoje wartości od kontenera,
możemy je jednak ręcznie zaprogramować wewnątrz aplikacji kontenera lub umieścić je w
towarzyszącym kontrolce arkuszu właściwości. Kolor samej kontrolki zaprogramujemy ręcznie jako
zielony, ponieważ funkcja AmbientForeColor () nie zawsze jest obsługiwana przez aplikację. Kolor tła
jest używany w linii 9 do odmalowania tła kontrolki. Możemy poprawić kontrolkę tak, aby obszar pod
głównym kołem kontrolki nie był odmalowywany dwukrotnie, co pozwoli ograniczyć zbędne mignięcia
obrazu.
Ponieważ używany do odmalowywania prostokąt przesyła współrzędne rogów kontrolki wewnątrz
kontenera, należy przeliczyć współrzędne kliknięcia myszą na relatywne współrzędne kontrolki,
odejmując od współrzędnych kliknięcia współrzędne lewego górnego rogu kontrolki w linii 14. W linii
15 w podobny sposób wyliczamy współrzędne środka kontrolki.
W liniach 17-28 wyliczamy za pomocą funkcji trygonometrycznych kąt nachylenia wektora
definiującego ustawienie pokrętła, a następnie w oparciu o uzyskaną wartość kąta wyliczamy
współrzędne uchwytu pokrętła (rysowanego w linii 35). Aby móc korzystać z funkcji
trygonometrycznych, należy załączyć plik z deklaracjami funkcji matematycznych po innych
dyrektywach łinclude na początku pliku RotaryCtri.cpp:
łinclude "math.h"


Tworzenie kontrolek ActiveX_________________________ ____ 691
W linii 38 malowane jest główne koło reprezentujące pokrętło kontrolki. Zachodzi ono częściowo na
koło uchwytu tak, że to wygląda teraz jak wybrzuszenie na powierzchni dużego koła.
Korzystanie z pliku nagłówka math.h
Mimo iż wszystkie funkcje matematyczne są dołączone do kodu aplikacji za pośrednictwem
standardowej biblioteki czasu wykonania C^, musimy załączyć plik nagłówka math.h, aby dostarczyć
kompilatorowi prototypów funkcji. Funkcje tu zadeklarowane obsługują szeroki zakres funkcji
matematycznych, począwszy od funkcji trygonometrycznych, przez logarytmy i funkcje zaokrąglające,
po funkcje obsługujące konwersję między różnymi typami definiującymi sposób przedstawiania liczb.
W liniach 42 i 43 rysujemy linię od środka koła do uchwytu, reprezentującą bieżącą pozycję
pokrętła.
Musimy tutaj również dodać zmienną definiującą pozycję kliknięcia m_ptClicked jako zmienną
składową typu cpoint klasy CRotaryCtri. Możemy to zrobić korzystając z okna dialogowego
AddMemberVariable, które można wywołać za pomocą polecenia menu skrótów panelu ClassView
(uzupełniamy klasę CRotaryClass). W ten sposób dodamy do definicji klasy CRotaryCtri zmienną
składową:
CPoint m_ptClicked;
PATRZ TAKŻE
Więcej na temat rysowania linii i okręgów pisaliśmy w rozdziale 16.
Jak dodać zmienną składową m_ptClicked typu CPoint pisaliśmy w rozdziale 8.
Zarządzanie zdarzeniami wywołanymi przez użytkownika i obsługa
wykonywanych przez niego operacji
Zmienna m_ptdicked wykorzystywana jest na listingu 26.1 do przekształcania współrzędnych
wprowadzanych przez użytkownika podczas kliknięcia myszą w kąt reprezentujący nachylenie wektora
definiującego pozycję pokrętła. Musimy załączyć kod przypisujący tej zmiennej nową wartość za
każdym razem, gdy użytkownik kuknie kontrolkę lub poruszy mysz wciskając jednocześnie jej lewy
klawisz. Załączamy funkcję obsługi komunikatów Windows, aby przechwycić komunikat
WM_LBUTTONDOWN, przechować współrzędne punktu, w którym nastąpiło kliknięcie i rozpocząć tryb
przechwycenia myszy (ang. mouse capture), tak jak to pokazaliśmy na listingu 26.2.


692 Poznaj Visual C++ 6
Listing 26.2. LST27_2.CPP - funkcja obsługi OnLButtonDown () notująca pozycję myszy i
uruchamiająca tryb przechwycenia myszy
1 void CRotaryCtrl::OnLButtonDown(UINT nFlags, CPoint point)
2 {
3 // ** Przywołaj funkcję klasy bazowej
4 COleControl::OnLButtonDown(nFlags, point);
5
6 // ** Uruchom tryb przechwycenia myszy 1 SetCapture() ;
8
9 // ** Zachowa-} punkt kliknięcia
10 m_ptClicked = point; O
11
12 // ** Odmaluj kontrolkę
13 InvalidateControl();
14 )
O Punkt, w którym nastąpiło kliknięcie, zachowywany jest w zmiennej wykorzystywanej później w
funkcji OnDraw ().
Na listingu 26.2 w linii 7 za pomocą funkcji SetCapture () uruchamiany jest tryb przechwycenia
myszy. Nowa zmienna składowa m_ptClicked wykorzystywana jest w linii 10 do przechowywania
współrzędnych punktu, w którym nastąpiło kliknięcie myszą. Przyzywana na końcu funkcja
InvalidateControl () działa tak samo jak używana w normalnym oknie funkcja lnvalidate () informująca,
że cały obszar okna, a w tym wypadku kontrolki, musi zostać ponownie odmalowany. Możemy również
przesłać funkcji InvalidateControl () prostokąt informujący, że tylko część kontrolki leżąca wewnątrz
niego powinna zostać odmalowana.
Po wciśnięciu przez użytkownika przycisku myszy kontrolka pokrętła powinna obracać się razem z
poruszeniami myszy. W tym celu musimy dodać funkcję obsługi komunikatu WM_MOUSEMOVE. Za
pomocą kreatora dodajemy funkcję obsługi OnMouseMove () przedstawioną na listingu 26.3.
Listing 26.3. LST27_3.CPP - funkcja obsługi komunikatu OnMouseMove () przechowująca i
zmieniająca ustawienie kontrolki
1 void CRotaryCtrl::OnMouseMove(UINT nFlags, CPoint point)
2 (
3 // ** Sprawdź, czy lewy przycisk myszy jest wciśnięty
4 if (nFlags & MK_LBUTTON.)


Tworzenie kontrolek ActiveX 693
5 (
6 // ** Zachowaj nowa pozycję 1 m
ptCIicked = point;
8
9 // ** Odmaluj kontrolkę
10 InvalidateControl (); O
11 )
12
13 // ** Przywołaj funkcję klasy bazowej
14 COleControl::OnMouseMove(nFlags, point);
15 }
O Jeśli lewy przycisk myszy jest wciśnięty, pozycja kontrolki jest uaktualniana i odmalowywana w
miarę poruszeń myszy.
W linii 4 sprawdzamy, czy lewy przycisk myszy jest wciśnięty, testując zmienną nFlags
pod kątem obecności znacznika MK LBUTTON. Jeśli znacznik ten zostanie wykryty, pozycja
myszy jest uaktualniana i kontrolka jest odmalowana, aby odwzorować poruszenia pokrętła.
Na koniec musimy przechwycić komunikat WM_LBUTTONUP za pomocą utworzonej przez
kreator funkcji obsługi OnLButtonUp (), aby wyłączyć tryb przechwycenia myszy. W funkcji
obsługi musimy przed odwołaniem do funkcji z klasy bazowej wpisać tylko odwołanie do
funkcji zwalniającej mysz:
RelaseCapture() ;
PATRZ TAKŻE
Szczegółowy opis zdarzeń myszy i operacji przechwycenia myszy znaleźć można w rozdziale
8.
Szybki sposób testowania kontrolki
W tym momencie mamy już kod wystarczający do zbudowania działającej kontrolki. Jeśli teraz
zbudujemy kontrolkę, zobaczymy nowy dodatkowy krok budowy:
Registering ActiveX Control...
W tym kroku kontrolka jest rejestrowana za pomocą programu regsrvr32.exe, który przyzywa tylko
w kontrolce globalną funkcję DlIRegisterSerwer (void), a dopiero ta funkcja dokonuje właściwej
rejestracji kontrolki. Funkcję DlIRegisterSerwer (void), jak i przeciwną do niej funkcję
DllUnegisterSerwer (void), znaleźć można w pliku Rotary.cpp.


694 Poznaj Visual C++ 6
Nie możemy jednak już teraz uruchomić zbudowanej kontrolki, ponieważ przeznaczona jest ona do
działania wewnątrz aplikacji kontenera. Jak jednak pamiętamy z rozdziału 9, możemy bez większych
trudności dodać kontrolkę ActiveX do okna dialogowego. Teraz, gdy nowa kontrolka jest już
zarejestrowana, możemy za pomocą edytora zasobów dodać kontrolkę do jej własnego okna About
(IDD_ABOUT_ROTARY). W tym celu zaznaczamy najpierw w oknie dialogowym edytora zasobów
identyfikator IDD_ABOUT_ KOTARY, aby rozpocząć edycję zasobu (klikamy dwukrotnie
IDD_ABOUT_ROTARY w oknie dialogowym zasobów kompilatora Project Workspace). Następnie
dodajemy kontrolkę do okna dialogowego About, klikając je prawym klawiszem myszy i wybierając w
menu skrótów polecenie Insert ActiveX Control.
Za pomocą kombinacji klawiszy Ctri+T lub polecenia Test z menu Layout możemy przetestować
zaprojektowaną kontrolkę (patrz rysunek 26.4). W oknie testującym okna dialogowe (ang. dialog tester)
edytora zasobów będziemy mogli kliknięciem myszy dowolnie zmieniać ustawienia kontrolki pokrętła.
About Hotary Control
Rotaty Control, Yersion 1,0 OK


T



Rysunek 26.4. Najprostszy sposób testowania kontrolki za pomocą jej własnego okna dialogowego
About
Po zakończeniu testowania należy pamiętać, żeby usunąć kontrolkę z okna dialogowego About,
ponieważ nie jest to jej właściwe miejsce - pozostawienie jej tutaj może być w przyszłości źródłem
pewnych nieprzyjemnych komplikacji.







Zachowywanie projektu przed testowaniem kontrolki ActiveX
Testowanie kontrolek ActiveX za pośrednictwem edytora zasobów jest bardzo wygodne, ale należy
pamiętać, aby przedtem zachować wszystkie pliki projektu, ponieważ ewentualne błędy w kodzie
kontrolki mogą spowodować nieprzyjemne komplikacje lub problemy z korzystaniem z zasobów.
Szczęśliwie kompilator Visual C++ zachowuje pliki zanim przystąpi do kompilacji, dlatego zaraz
po kompilacji można z nich względnie bezpiecznie korzystać.





ff\\KŁ IAlU.t
Jak dodawać kontrolkę ActiveX do okna dialogowego pisaliśmy w rozdziale 9.
Uruchamianie zdarzeń
Kontrolka musi w jakiś sposób informować swoją aplikację, że użytkownik zmienił jej
status. Kontrolki ActiveX nie są tutaj wyjątkiem, dlatego powinniśmy do kontrolki Rotary
dodać funkcję obsługi informującą aplikację o tym, kiedy pokrętło zostanie poruszone. Proces
ten nazywany jest uruchamianiem lub odpalaniem zdarzeń (ang. eventfiring). Odpowiednie
zdarzenie możemy dodać do kontrolki za pomocą kreatora CIassWizard.
Dodawanie zdarzeń kontrolki ActiveX za pomocą kreatora CIassWizard
1. Aby uruchomić kreator CIassWizard, wciśnij klawisze CtrI+W lub kliknij polecenie
CIassWizard w menu yiew.
2. Wybierz kartę ActiveX Events.
3. Aby dodać nowe zdarzenie, kliknij przycisk Add Event.
4. Wpisz zewnętrzną nazwę zdarzenia przeznaczoną dla aplikacji właściciela na liście
kombinowanej Ęxtemal Name, tak jak widać na rysunku 26.5 (tutaj Repositioned).


Bdernal name;
OK



positioned
Internal name:
Cancel



FireRepositioned
, ImplementatiDn" - l (" : : .
<~
Paramster list:
dNewPosition
Rysunek 26.5. Dodawanie zdarzenia kontrolki ActiveX za pomocą okna dialogowego Add Event
5. W polu Intemal Name poniżej powinna pojawić się nazwa (uruchamiającej zdarzenie) wewnętrznej
funkcji kontrolki. Nazwę tę można zmienić, zazwyczaj jednak pozostawia się nazwę wpisaną
domyślnie przez kreator.


696 Poznaj Visual C++ 6
6. Na liście Parameter List wpisz nazwę parametru (tutaj dNewPosition), który będzie
przesyłany przez zdarzenie aplikacji kontrolki.
7. Obok w kolumnie Type wprowadź typ zmiennej.
8. Powtarzaj kroki 6 i 7 dla każdego parametru przesyłanego przez zdarzenie do aplikacji
będącej właścicielem kontrolki.
9. Aby dodać nowe zdarzenie, kliknij OK. Zdarzenie powinno się teraz pojawić na liście
Extemal name karty ActiveX Eyents (patrz rysunek 26.6).


Atld ClBEli,
&dd Evenl..
Selete
Sli.* ;;łK.'Mv.?.i'-A-A"i
MessageMaps | MemhBrV%riob!es l Aulomalion Actr\'eXEvents |
aassirlo | Eroject; Ctass QSrne:
Rotaiy
E:',."\Rotaty\FtoiaryCll h.
E'\...\Rofsry\PioiatyOl,cpp ^"tsrnal nowe:


Selsct e dąsa that implemenis' an AdiveX
ControianddickAdd Eventto sddsupportfor
control avenls.
YDU can useAdd Eventto addfao)ti slockand
custom eyenis-
Did RreReposróoned(doubfe dNff^Position);
Rysunek 26.6. Karta Active Eyents kreatora CIassWizard wyświetla listę zdarzeń kontrolki
Po wykonaniu opisanych wyżej czynności w panelu ClasView w klasie CRotaryCtrl pojawi się
nowa funkcja FireRepositionedO . Funkcja ta będzie uruchamiać zewnętrzne (ang. extemal) zdarzenie
Repositioned, czyli takie zdarzenie, które będzie docierać do goszczącej kontrolkę aplikacji.
Teraz należy wpisać kod, który będzie uruchamiał wspomniane zdarzenie, gdy użytkownik zwolni
lewy klawisz myszy (co jest równoważne z obróceniem pokrętła). Wcześniej trzeba jednak zachować
aktualną pozycję pokrętła w klasie kontrolki. W tym celu należy do klasy kontrolki dodać nową zmienną
składową albo za pośrednictwem okna dialogowego New Member Yariable, albo po prostu wpisując w
definicji klasy:
double m_dCurrentPosition;
Wpisana tutaj zmienna typu double przechowywać będzie wartości z przedziału od 0 do 360,
definiujące pozycję uchwytu kontrolki. Przy czym wartość kąta rośnie odwrotnie do kierunku ruchu
wskazówek zegara i tak (odwołując się do analogii geograficznych) 0 przypisane jest kierunkowi
wschodniemu, 90 północy, 180 zachodowi, a 270 kierunkowi południowemu. Wartość zmiennej
ustalamy w oparciu o kąt wyliczony w funkcji OnDraw () w następujący sposób:


Tworzenie kontrolek ActiveX 697
m_dCurrentPosition = dAngle * 57.2978 + 180.0;
W ten sposób przeliczymy kąt z radianów na stopnie, zachowując jego wartość w zmiennej
składowej m_dCurrentPosition.
Teraz należy wewnątrz funkcji onLButtonUpt) uruchomić zdarzenie, które poinformuje aplikację, że
użytkownik zmienił pozycję kontrolki. W tym celu należy przywołać uruchamiającą zdarzenie funkcję
Fire RepositionedO. Należy ją wpisać zaraz po funkcji RelaseCapture (), przesyłając jej zmienną
definiującą bieżącą pozycję kontrolki:
FireRepositioned(m dCurrentPosition) ;
Po tych poprawkach aplikacja będzie otrzymywać od kontrolki zdarzenie Repositio-ned za każdym
razem, gdy użytkownik zmieni położenie pokrętła i zwolni przycisk myszy. Samo zdarzenie można
załączyć do kontrolki za pomocą kreatora CIassWizard, tak jak to opisywaliśmy w rozdziale 9.
PATRZ TAKŻE
Więcej informacji o zdarzeniach i komunikatach Windows znaleźć można w rozdziale 4.
* Jak dodawać funkcje obsługi zdarzeń do kontrolek ActiveX pisaliśmy w rozdziale 9.
Tworzenie interfejsu właściwości
Tworzona przez nas kontrolka ActiveX powinna posiadać zestaw właściwości (ang.
properties), które my albo inni programiści wykorzystujący naszą kontrolkę będą mogli
zmieniać w zależności od bieżących potrzeb tworzonego programu. Właściwości te powinny
dawać się modyfikować zarówno w momencie tworzenia programu, jak i w trakcie działania
aplikacji z poziomu kodu programu.
Trzy kategorie właściwości
Właściwości kontrolek ActiveX można podzielić na trzy podstawowe kategorie. Właściwości otoczenia
(ang. ambient properties) to takie właściwości, które wartości swoje wywodzą z kontenera kontrolki,
dzięki czemu pozwalają jej upodobnić się do otaczających ją elementów okna. Właściwości
wyposażenia (ang. stock properties) to te, które występują we wszystkich kontrolkach i definiują kolor,
czcionkę czy bieżący status kontrolki. Właściwości przez nas definiowane (ang. custom properties)
będą natomiast specyficzne dla danej, konkretnej kontrolki.
Właściwości te powiązane są z funkcjami automatyzacji OLE, dzięki czemu kontrolka
może być wykorzystywana i modyfikowana w aplikacjach Yisuał C^, Visual Basica,
przeglądarkach sieciowych i dowolnym innym programie potrafiącym komunikować się z
interfejsem przesyłającym.


ffMKŁ IAtV.t:
^ O automatyzacji OLE pisaliśmy w rozdziale 25.
Właściwości wyposażenia
Dodając do kontrolki nową właściwość tak naprawdę dodajemy nowe hasło do interfejsu
przesyłającego. Każde z tych haseł powiązane jest z jednym ściśle określonym słowem, co
pozwala innym językom programowania odnaleźć powiązaną z tym słowem właściwość w
interfejsie przesyłającym kontrolki. Właściwości wyposażenia przedstawione w tabeli 26. l są
wspólne dla wszystkich kontrolek ActiveX. Należą do nich przykładowo właściwości
BackColor i ForeColor definiujące odpowiednio kolor tła i kolor powierzchni kontrolki.
Właściwości wyposażenia można dodać do kontrolki posługując się kreatorem CIassWizard.
Poniższa instrukcja pokazuje jak dołączyć do kontrolki właściwość ForeColor, pozwalającą
zmieniać kolor pokrętła kontrolki Rotary.
Dodawanie właściwości wyposażenia do kontrolki ActiveX za pomocą kreatora CIass-
Wizard
1. Aby przywołać kreator CIassWizard, wciśnij CtrI+W lub w menu View wybierz
polecenie CIassWizard.
2. Wybierz kartę Automation.
3. Kliknij przycisk Add Property, aby wyświetlić okno dialogowe Add Property.
4. Z listy kombinowanej Extemal Name wybierz odpowiednią nazwę właściwości. W
naszym przykładzie nazwę ForeColor. Po wybraniu nazwy właściwości pozostałe pola
okna zostaną wyłączone (patrz rysunek 26.7).
5. Aby dodać właściwość, kliknij OK. Dodana właściwość powinna się teraz pojawić na liście
Extemal Names na karcie Automation kreatora CIassWizard.


E^temal name:
Of.
Cancet



Impiemenlałion R
Stocjs, <" Memberswiatilt
<~ Gel/Setmelhtdt




Rysunek 26.7. Dodawanie do kontrolki właściwości wyposażenia za pomocą okna dialogowego Add
Property kreatora CIassWizard


Tworzenie kontrolek ActiveX 699
Tabela 26.1. Właściwości wyposażenia kontrolek ActiveX


Właściwość
BackColorGet
Fore Color Font
Caption
Text
BorderStyle
Apperance
Zmieniana poprzez
GetBackColor()
SetBackColorO
GetForeColor()
SetForeColor()
GetFont() SetFontO
InternalGetFont()
InternalGetText ()
InternalGetText() m
sBorderStyle
m sApperance
Opis
Definiuje kolor tła kontrolki
Definiuje kolor kontrolki Definiuje czcionkę
tekstu kontrolki
Definiuje tekst tytułu kontrolki Podobna do
właściwości Caption
Dostępne są dwie wartości właściwości ccNone (bez
obramowania) lub ccFixed3ingle (z obramowaniem)
Przypisujemy jej wartość l dla kontrolki trój-
wymiarowej i O dla kontrolki płaskiej






Po dodaniu właściwości ForeColor powinna się ona pojawić w panelu CIassYiew pod hasłem
JDRotary interfejsu kontrolki. Teraz w oparciu o wartość tej właściwości będzie można za pomocą
funkcji GetForeColor () definiować kolor kontrolki (w funkcji On-
Draw()):
CBrush brForeGnd(TranslateColor(getForeColor( ))) ;
Typ OLE_COLOR i funkcja TranslateColor ()
Funkcja TransiateColor () pozwala konwertować typ OLE_COLOR definiujący kolor w funkcjach
związanych z OLE na typ COLORREF wykorzystywany przez standardowe funkcje Windows. Typ
OLE_COLOR rozszerza typ COLORREF o kilka znaczników informujących o alternatywnych sposobach
przechowywania informacji o kolorze. Jednym z takich alternatywnych sposobów jest
przechowywanie w zmiennej indeksów do standardowych kolorów systemowych, które mogą być
wykorzystywane przez funkcję GetSysColor () do pobierania ustawień kolorów typowych dla danego
komputera. Inny sposób polega na definiowaniu wartości kolorów za pomocą liczb dziesiętnych, a nie
tak jak w typie COLORREF za pomocą 24-bitowej zmiennej True-Color.


700_____________________________________Poznaj Visual C++ 6 l __I
Dodawanie karty właściwości definiujących kolory
Aby pomóc programistom, którzy będą korzystać z zaprojektowanej przez nas kontrolki, możemy dodać do niej kartę
właściwości wyposażenia definiujących kolory. Karta ta jest opatrzona identyfikatorem CLSID_CColorPropPage. Osobna
karta CLSID_CCFont-PropPage definiuje właściwości czcionki kontrolki. W pliku RotaryCtri.cpp zawierającym kod klasy
kontrolki znajduje się sekcja // Property Pages (karty właściwości). Przechowywana jest tam tablica kart właściwości
powiązanych z kontrolka. Dodając kontrolkę do okna dialogowego za pomocą edytora zasobów programista może po
kliknięciu kontrolki prawym klawiszem myszy zmieniać jej właściwości. Kliknięcie prawym klawiszem myszy wyświetli
karty przechowywane we wspomnianej tablicy oraz opisane w rozdziale dziewiątym karty Generał i Ali. W omawianym
przykładzie kontrolka Rotary posiada jak dotąd tylko jedną, utworzoną przez kreator CIassWizard kartę właściwości:
Ryi


Do
BEGINJPROPPAGEIDS(CRotaryCtrl, l)
PROPPAGEID(CRotaryPropPage::guid)
END_PROPPAGEIDS(CRotaryCtrl)





czo
łaja
WO!
Liczba kart właściwości
Należy pamiętać, aby po dodaniu nowej karty właściwości odpowiednio zmodyfikować liczbę kart
właściwości, inaczej przy próbie wyświetlenia kart właściwości w edytorze zasobów kompilator
Developer Studio zawiesi się.





wp
rac
jem
nao]
m_t
Zań
prze
w pi
Kartę właściwości wyposażenia definiujących kolory dodajemy zaraz po pierwszej karcie
(CRotaryPropPage:: guid), zwiększając odpowiednio liczbę kart właściwości w makroinstrukcji
BEGIN_PROPPAGEIDS:
BEGIN_PROPPAGEIDS(CRotaryCtrl, 2)
PROPPAGEID(CRotaryPropPage::guid)
PROPPAGEID(CLSID_CColorPropPage)
END_PROPPAGEIDS(CRotaryCtrl)
Jeśli w tym momencie zbudujemy kontrolkę i uruchomimy ją umieszczając za pomocą edytora
zasobów w oknie dialogowym IDD_ABOUTBOX_ROTARY, kontrolka pojawi się ale całkowicie
czarna, ponieważ właściwości reprezentującej kolorowi kontrolki została domyślnie przypisana wartość
zero. Jeśli teraz wciśniemy Alt+Enter, aby zmienić właściwości kontrolki, na karcie Ali znajdziemy
właściwość ForeColor z wyświetloną obok wartością typu OLECOLOR definiującą kolor kontrolki
(rysunek 26.8). Po kliknięciu przycisku ... będziemy mogli za pomocą karty Colors wybrać
odpowiadający nam kolor (rysunek 26.9). Po wybraniu nowego koloru i zamknięciu okna dialogowego
Kotary Con-trol Properties kontrolka będzie wyświetlana w nowym, wybranym przez nas kolorze.


Tworzenie kontrolek ActiveX 701
Kotary Control Properties


d






Rysunek 26.8. Karta Ali z widoczną właściwością ForeColor
Dodawanie własnych właściwości
Możemy dodać do kontrolki własne właściwości i osobną kartę właściwości przeznaczoną
dla nich. Przykładowo, możemy naokoło kontrolki dodać kreski podziałki pozwalające
użytkownikowi lepiej zorientować się w pozycji kontrolki. Odpowiednia właściwość pozwoli
korzystającemu z kontrolki programiście zdefiniować liczbę kresek.

Rysunek 26.9. Karta Colors okna Kotary Control Properties
Za pomocą karty Automation kreatora CIassWizard dodamy dwie nowe właściwości w
podobny sposób, w jaki dodawaliśmy właściwości wyposażenia. Zamiast jednak wybierać
jedną ze standardowych właściwości w liście kombinowanej External Names, wpisujemy
własną nazwę (TicksEnable) właściwości pozwalającej wyświetlać kreski skali naokoło
pokrętła. W polu VariableName wpisana zostanie automatycznie nazwa zmiennej
m_ticksEnable, a w polu Notification Function nazwa funkcji OnTicksEnableChanged.
Zamiast korzystać ze zmiennej składowej, lepiej zdefiniować metody Get i Set klikając
przełącznik Get/Set Methods. W ten sposób wygenerujemy nazwy odpowiednich funkcji w
polach Get Function i Set Function (odpowiednio GetTicksEnable i SetTicksEnable).


702 Poznaj Visual C++ 6
W polu Type należy wybrać BOOL, aby zdefiniować zmienną właściwości jako zmienną typu
logicznego. Okno Add Property przedstawione zostało na rysunku 26.10.
Add Property


OK.
E.xt@mo! name- TIcksEnable
łype
(^etfunction:
Setlufiction:
SetTicksEnable
Implementetion


C Membarwiable P Gel/Setmelhods
Parameler iist

Rysunek 26.10. Dodawanie własnej właściwości za pomocą okna dialogowego Add Property
Wciśnięcie przycisku OK doda do kontrolki właściwość i związane z nią metody. Teraz musimy
dodać nową właściwość, NumTicks, definiującą liczbę kresek podziałki. Ponownie wybieramy
przełącznik Get/Set Methods, a w polu Type definiującym typ zmiennej wpisujemy short.
Aby dołączyć do programu kod odpowiednich funkcji Get i Set, należy wybrać odpowiednią nazwę
zewnętrzną (w polu Extemal Name) i kliknąć przycisk Ędit Code (na karcie Automation kreatora
CIassWizard). Metoda Set służy do zapisywania nowej wartości właściwości, a Get do jej pobierania.
Kod wszystkich czterech metod przedstawiony został na listingu 26.4.
Zewnętrzne nazwy właściwości
Zewnętrzne nazwy właściwości są wykorzystywane w automatyzacji OLE. Przechowywane są w
tablicy przeglądowej (ang. lookup tobie} interfejsu iDispatch, aby program klient (taki jak kontener
kontrolki) mógł w czasie działania ustalić, które właściwości kontrolki są dostępne.
Listing 26.4. LST27_4.CPP - funkcje Get/Set dla właściwości tworzonych przez nas
BOOL CRotaryCtrl::GetTicksEnable()
// TODO: Tutaj dodaj własny kod obsługi właściwości return m
bTicks;


5 }
6
7 void CRotaryCtrl::SetTicksEnable(BOOL bNewValue)
8 (
9 // TODO: Tutaj dodaj własny kod obsługi właściwości
10 m_bTicks = bNewValue;
11
12 SetModifiedFIagO;
13 )
14
15 short CRotaryCtrl::GetNumTicks()
16 {
17 // TODO: Tutaj dodaj własny kod obsługi właściwości
18
19 return m sNumTicks;
20 }
21
22 void CRotaryCtrl::SetNumTicks(short nNewYalue)
23 (
24 // TODO: Tutaj dodaj własny kod obsługi właściwości
25
26 m_sNumTicks = nNewYalue;
27
28 SetModifiedFIagO;
29 }
Dwie nowe wprowadzone na listingu 26.4 zmienne składowe (m_bTicks i m_sNum-Ticks)
wykorzystywane są odpowiednio do definiowania, czy kreski podziałki mają być wyświetlone i ile ich
ma być. Funkcje Get/Set z linii 1-13 obsługują pierwszą, funkcje Get/Set z linii 15-29 drugą właściwość,
informując nas o przechowywanych w nich wartościach lub odpowiednio je modyfikując. Należy dodać
definicje odpowiednich zmiennych składowych do definicji klasy albo za pomocą okna dialogowego
Add Mem-ber Yariable, albo wpisując je tam ręcznie:
short m sNumTicks;
BOOL m_bTicks;
Następnie w funkcji konstruktora CRotaryCtrl: :RotaryCtrl () klasy CRotaryCtrl należy
zdefiniować ich początkowe wartości:
// TODO: Tutaj inicjuj zmienne kontrolki.
m_bTicks = TRUE;
m sNumTicks = 20;
Jeśli teraz otworzymy w panelu ClassView hasło _DRotary, powinniśmy zobaczyć tam nazwy
dwóch nowych właściwości.


704 Poznaj Yisuał C++ 6
Dodawanie kontrolek kart właściwości dla własnych właściwości
Metody Get i Set umożliwiają modyfikowanie właściwości z poziomu programu, warto jednak
również dodać interfejs, który pomagać będzie zmieniać właściwości kon-trolki z poziomu edytora
zasobów podczas projektowania aplikacji. &
Właściwości karty właściwości.
Projektując kartę właściwości dla tworzonych przez nas właściwości kontrolki dodajemy kod
implementujący odpowiedni interfejs użytkownika, który wykorzystywany będzie podczas
projektowania kontrolki. Gdy teraz korzystający z kontrolki programista po dodaniu jej do programu
wciśnie Alt+Enter, wśród kart właściwości pomiędzy zakładkami kart Generał i Stock pojawi się
zakładka nowej karty pozwalającej zmieniać specyficzne dla tej kontrolki właściwości.
W tym celu należy w kompilatorze Project Workspace wybrać panel ResourceYiew i
odnaleźć okno dialogowe IDD_PROPPAGE_ROTARY. Do okna dialogowego dodamy
kontrolki reprezentujące nowe właściwości. Właściwość TicksEnabIe będzie można zmieniać
klikając pole wyboru Show Tick Marks (identyfikator IDC_TICKS_ENABLED). Natomiast
liczbę kresek podziałki będzie można zmieniać za pomocą pola edycji No. of Tick Marks
(identyfikator IDC_NUM_TICKS). Dwie strzałki (kontrolka Spin) korzystające ze znaczników
wiążących je z polem edycji (opcje ^uto Buddy i Set Buddy Integer na karcie Styles okna
dialogowego Spin Properties) ułatwiać będą zmienianie liczby kresek skali. Ten moment
tworzenia karty właściwości przedstawiony został na rysunku 26.11.


"ii
1~ Show Tick Marks
No, of Tick Marks Edit


^a ? Generał Stylas j Extended Stylas


)7 ^uto buddy
17 Set buddy
integer
r" No thousands


F Wrap T"'
Arrowkeys






Rysunek 26.11. Dodawanie kontrolek do karty właściwości kontrolki ActiveX
Za pomocą kreatora CIassWizard można w bardzo prosty sposób powiązać wartości definiowane w
kontrolkach z odpowiednimi właściwościami. Poniższa instrukcja pokazuje jak powiązać pole wyboru
Show Tick Marks z właściwością TicksEnabIe.


Tworzenie kontrolek ActiveX 705
Wiązanie właściwości z kontrolkami karty właściwości za pomocą kreatora CIassWizard
1. Wybierz kontrolkę, którą chcesz powiązać z właściwością (tutaj pole wyboru Show Tick
Marks w oknie dialogowym IDD_PROPPAGE_ROTARY) i wciśnij CtrI+W, aby przywołać
kreatora CIassWizard, w którym należy wybrać kartę Member Variables.
2. Z listy Control IDs wybierz identyfikator IDC_TICKS_ENABLED.
3. Aby dodać przypisaną kontrolce właściwość, kliknij przycisk Add Variable. Pojawi się
widoczne na rysunku 26.12 okno dialogowe Add Member Variable.
4. W polu Member Variable Name wpisz m_bTicksEnabled.
5. Na liście kombinowanej Optional Property Name wpisz TicksEnabled.
6. Aby dodać nazwę zmiennej, kliknij OK.
Add Member VariablB


Member vari obie name.
ni bTicksEnabled
Cale g o r/




Value Variable type:
BOOL Optional property name:
JTicksEnabled|]]
Description;
simple BOOLtransfer
Rysunek 26.12. Wiązanie kontrolki karty właściwości z właściwością za pomocą okna dialo-
gowego Add Member Variable
Te same czynności powtarzamy łącząc kontrolkę IDC_NUM_TICKS ze zmienną składową
m_sNumTicks typu short (do wpisania w polu Variable Type). W przypadku tej właściwości
(NumTicks) opcjonalna nazwa zmiennej wpisywana w polu Optional Property Name
powinna brzmieć NumTicks. CIassWizard automatycznie utworzy odpowiedni kod, a
odpowiednie zmienne pojawią się na karcie Member Variables.
Możemy zdefiniować dopuszczalny zakres zmiennej całkowitej, z którego użytkownik
będzie mógł definiować liczby (na przykład od l do 100). W tym celu należy na karcie
Member Variables wybrać odpowiednią zmienną (tutaj m_sNomTicks). Na dole karty
Automation pojawią się dwa pola edycji pozwalające zdefiniować minimalną i maksymalną
wartość zmiennej. W polu Minimum Value wpisujemy l, a w polu Maximum Value
wpisujemy 100 (rysunek 26.13).


706 Poznaj Visual C++ 6
Kreator CIassWizard wiąże odpowiednie właściwości z interfejsami OLE dodając specjalne
odwołania do makroinstrukcji DDP w funkcji DoDataExchange () klasy CRota-ryPropPage:
DDP_Check(pDX, IDC_TICKS_ENABLED, m_bTicksEnabled, _T("TicksEnable")
);
DDP_Text(pDX, IDC_NUM_TICKS, m_sNumTicks, _T("NumTicks") );
Po wprowadzonych zmianach funkcje Get i Set zmieniać będą początkowe wartości właściwości
kontrolki ActiveX na życzenie korzystającego z niej programisty.
MessageMaps
MemberYariables

AutomatiOR | ActiveX Ev8n(s j
Ciass

irrto l

^ojecf'



Ciass Darrie-

AddClass,,. -'

Potarv

,|

CRotełyPiopPage

j



AddYotiabte...

Contfol !Ds:

Type Member

SsiBteYariabte

IDC NUMTICKS : - ::

f-hntt ' ' m^NurnTirfr'';' : : : ^^^^^^^H^^^^^^^f

(DC^SPINI







IDCTICKSENABLED

BOOL mbTlck8Enable

d







:.il:





..... . . .. ......

. ... i^^^^^''/^ '^Ht^i^^?::"''

3sscriptian, shortwith rangę
VB||l;lBl





^ll^^l^^^^^

^lnirriuinValue' |1







^eximum Va[ue: |100







'^.lll:^:';:': . . . CiK | Cancel

Rysunek 26.13. Definiowanie maksymalnej i minimalnej wartości zmiennej składowej
m sNumTicks
Utrwalanie ustawień właściwości
Kiedy zdefiniujemy właściwości kontrolki za pomocą edytora zasobów, wartości tych właściwości
pozostaną niezmienione nawet, wówczas gdy wykorzystamy w programie lub przeprojektujemy
kontrolkę. Właściwości te są serializowane i zachowywane dla każdego egzemplarza kontrolki, dzięki
czemu właściwości zdefiniowane podczas dodawania kontrolki do okna dialogowego pozostaną
niezmienione, gdy będziemy to okno dialogowe edytować następnym razem.
Umożliwia to funkcja DoPropExchange () kontrolki przyzywana zawsze, gdy kon-trolka jest
zachowywana lub ładowana. Serializację dodanych przez nas kontrolek umożliwiają makroinstrukcje
px_ przedstawione na listingu 26.5.


Tworzenie kontrolek ActiveX 707
Listing 26.5. LST27_5.CPP - utrwalanie właściwości kontrolki w funkcji DoPropExchange () za pomocą
makroinstrukcji PX
i l /i 111111111111111111111111 ni 11/1111 ni 1111/11 i/i mii
2 11 CRotaryCtrl::DoPropExchange - utrwalanie właściwości
3
4 void CRotaryCtrl::DoPropExchange(CPropExchange* pPX)
5 (
6 ExchangeVersion(pPX, MAKELONG(_wVerMinor,_wVerMajor));
7 COleControl::DoPropExchange(pPX) ;
8
9 // TODO: Dla każdej właściwości przyzwij makroinstrukcję PX
10
11 // ** Serializuj właściwość uaktywniającą kreski
12 PX_Bool(pPX,_T("TicksEnable"),m_bTicks,TRUE); O
13
14 // ** Seriaiizuj właściwość definiująca, liczbę kresek
15 PX_Short(pPX,_T("NumTicks"),m_sNumTicks,20) ;
16 }
O Makroinstrukcje PX_ są wykorzystywane do wiązania właściwości interfejsu ze zmiennymi
składowymi klasy kontrolki.
W linii 12 za pomocą makroinstrukcji PX_Bool utrwalana jest właściwość m_bTicks. W
linii 15 za pomocą makroinstrukcji px_short utrwalana jest właściwość m_sNum-Ticks.
Pierwszy parametr przyzywanych makroinstrukcji ppx jest wskaźnikiem do obiektu
CPropExchange. Drugi parametr jest nazwą właściwości w konwencji OLE. Trzeci parametr
jest nazwą wewnętrznej zmiennej składowej reprezentującej właściwość. Ostatni parametr
definiuje zachowywaną wartość właściwości. Odpowiednie makroinstrukcje PX_ zdefiniowane
są praktycznie dla każdego typu danych, przykładowo:
PX_Double, PX_Color czy PX_String.
W linii 6 zachowywany jest za pomocą funkcji ExchangeVersion () numer wersji. Wypuszczając na
rynek kolejną wersję kontrolki z nowymi właściwościami mamy możliwość sprawdzenia wersji
kontrolki. W ten sposób będziemy musieli wymienić w kodzie kontrolki tylko te właściwości, które
zostały zmienione w nowej wersji, zachowując zgodność z właściwościami stosowanymi w poprzedniej
wersji kontrolki.
Kod malujący kreski skali dodamy na końcu przedstawionej na listingu 26.6 funkcji OnDrawO .


708_____________________________________Poznaj Visual C++ 6
Listing 26.6. LST27_6.CPP - koniec funkcji OnDraw () klasy CRotary malujący na okoto kontrolki
kreski skali





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Sprawdź, czy skala została uaktywniona
if (m_bTicks)
{
// Powtarzaj zmieniając kąt od -2*PI do +2*PI const
double dPi = 3.14185;
double r = -2.0 * dPi;
for(int i=0;i// Wyjdź poza główny okrąg kontrolki nXPos = ptMid.x
+ (int)(cos(r) * dRadX * 1.05);
nYPos = ptMid.y + (int) (sin (r) * dRadY * 1.05);
pdc->MoveTo(CPoint(nXPos,nYPos)) ;
// Narysuj promień od tego punktu na zewnątrz nXPos =
ptMid.x + (int) (cos(r) * dRadX * 1.15);
nYPos = ptMid.y + (int) (sin (r) * dRadY * 1.15);
pdc->LineTo(CPoint(nXPos,nYPos)); O
// Zmień kąt r += dPi / (m_sNumTicks /
2.0);





O Kreski skali rysowane są na zewnątrz głównego okręgu pokrętła i rozchodzą się
promieniście na zewnątrz.
Na listingu 26.6 najpierw w linii 2 testowana jest zmienna składowa m_bTicks, aby
sprawdzić, czy kreski skali zostały aktywowane. Następnie definiowana w linii 7 pętla po-
wtarzana jest tyle razy, ile ma być kresek (zmienna m_SNumTicks). W liniach 10-12 defi-
niowany jest początek kreski w zależności od kata przechowywanego w zmiennej r (kąt
zmieniany jest w każdym kolejnym nawrocie pętli (linia 20), począwszy od wartości -2PI, a
skończywszy na 2PI (kąt definiowany jest w radianach i taki zapis odpowiada matema-
tycznemu zapisowi 2n). W uniach 14-17 z tego punktu rysowana jest na zewnątrz kreska skali,
co w efekcie po wykonaniu pętli do końca daje otaczające kontrolkę kreski podziałki.
PATRZ TAKŻE
^ Więcej na temat rysowania linii i okręgów można znaleźć w rozdziale 16. * O
automatyzacji OLE pisaliśmy w rozdziale 25.


Tworzenie kontrolek ActiveX 709
Kompilowanie i rejestrowanie kontrolki
Pliki tworzone i wykorzystywane w procesie kompilacji kontrolki ActiveX różnią się nieco od
plików aplikacji bazującej na oknie dialogowym lub aplikacji SDI czy MDI, głównie z powodu interfejsu
COM/OLE. Kod kontrolki generowany jest w pliku .ocx, który różni się od pliku .dli tylko i wyłącznie
nazwą. Tak więc kod źródłowy zawiera typowe dla pliku .dli funkcje rejestracji i pliki definicji. Możemy
umieścić kilka sprzedawanych kontrolek w jednym pliku .dli, co znacznie ułatwi ich dystrybucję.
Mimo iż budowanie kontrolki automatycznie obsługuje proces kompilacji, dobrze wiedzieć, jakie
pliki są w tym momencie wykorzystywane, a które tworzone, abyśmy zdawali sobie sprawę z tego, które
z nich powinniśmy rozprowadzać sprzedając kontrolkę.
Różne pliki źródłowe
W panelu FileView kompilatora Project Workspace w folderze Source Files projektu kontrolki
Rotary znaleźć można następujące pliki:
Rotary.cpp. Plik ten przechowuje numer wersji i globalny identyfikator kontrolki. W pliku tym
znajduje się również implementacja funkcji DllRegisterServer (), Dll-UnregisterServer(),
Initinstance() i Exitlnstance() niezbędnych do rejestracji i uruchomienia kontrolki.
Rotary.def. Ten plik przechowuje definicje funkcji Export biblioteki DLL.
Rotary.odl. Ten plik przechowuje hasła języka ODL definiujące interfejs COM/OLE wykorzystywany
przez kontrolkę, służące do tworzenia pliku biblioteki typów umożliwiającego korzystanie z
kontrolki aplikacjom napisanym w innych językach.
Rotary .rc. Plik zasobów przechowujący karty zdefiniowanych przez nas właściwości i inne zasoby
projektu.
RotaryCtl.cpp. Plik źródłowy języka C" zawierający kod kontrolki.
RotaryPpg.cpp. Plik źródłowy języka C^ przechowujący kod kart właściwości kontrolki.
Rejestrowanie kontrolki w czasie kompilacji
Odbywająca się przy okazji kompilacji rejestracja kontrolki za pomocą programu regsrvr32.exe
zapisuje w Rejestrze komputera identyfikatory CLSID niezbędne dla tworzonej kontrolki. Krok ten jest
standardowo dołączany do kompilacji, ponieważ najczęściej po zbudowaniu kontrolki będziemy chcieli
uruchomić ją na naszym komputerze, aby wykonać niezbędne testy. Należy również pamiętać, że
podobna rejestracja powinna się odbyć na komputerze końcowego użytkownika kontrolki i dlatego
powinna być załączona do skryptu instalacji/konfiguracji (ang. instalationisetup script).


710_____________________________________Poznaj Visual C++ 6
Pierwszy krok kompilacji wykorzystuje kompilator MIDL (Microsoft Interface Defini-tion
Language) do kompilacji pliku .odl. Jak wcześniej pisaliśmy, w efekcie tej operacji powstają definicje
interfejsu i odpowiednia biblioteka typów. Następnie wykonywana jest normalna kompilacja pliku
źródłowego. Na koniec uruchamiany jest program regsrvr32.exe tworzący odpowiednie hasła dla
kontrolki i jej interfejsu w Rejestrze systemu.
Tworzenie biblioteki typów i plików licencji
Po kompilacji w katalogu Rotary/Debug pojawi się plik Rotary.tłb. Ten wygenerowany przez
kompilator plik wykorzystywany będzie do tworzenia klas sterownika przesyłania i interfejsu w
momencie, gdy kontrolka zostanie włączona do projektu aplikacji. Sprzedając kontrolkę powinniśmy
rozprowadzać plik .tlb razem z przechowującym kod kontrolki plikiem .ocx. Możemy tutaj również
załączyć pliki definicji biblioteki DLL .lib i .exp oraz plik .lic, jeśli zdecydujemy się na licencjonowanie
kontrolki.
Licencjonowanie kontrolek ActiveX
Kiedy posiadający naszą licencję producent oprogramowania dodaje zaprojektowaną przez nas
kontrolkę do swojej aplikacji, generowany jest specjalny numer licencyjny, wbudowywany następnie
w kod kontrolki i przechowywany razem z programem aplikacji. Aby wygenerować ten numer
licencyjny (ang. license key) i związane z nim komunikaty o autorach programu, producent
oprogramowania musi posiadać odpowiedni plik licencji .lic. Po wygenerowaniu numeru licencji
producent oprogramowania może rozprowadzać aplikację wśród klientów. Kiedy końcowy
użytkownik uruchamia aplikację, kontener kontrolki musi przywołać funkcję Ceateinstance-Lic ()
tworzącą egzemplarz licencji. Aplikacja wysyła swój własny numer licencji, który porównywany jest
z numerem licencji kontrolki. Jeśli oba numery się zgadzają, aplikacja będzie działać normalnie.
PATRZ TAKŻE
Więcej informacji na temat bibliotek typów można znaleźć w rozdziale 25.
Rejestrowanie kontrolki
Sprzedając kontrolkę musimy wysłać nabywcom jedynie plik .ocx i program regsvr32.exe, który
można swobodnie rozprowadzać za zgodą Microsoftu. Następnie należy zarejestrować kontrolkę na
komputerze użytkownika uruchamiając program regsvr32.exe (w tym przypadku rejestrujemy kontrolkę
Rotary):
regsvr32.exe /s Rotary.ocx


Tworzenie kontrolek ActiveX________________________________711
Opcja / s specyfikuje, że operacja ma być wykonana w tle. Bez tej opcji na ekranie pojawiłoby się
okno komunikatu informujące, że operacja została zakończona sukcesem.
Program testujący ActiveX Control Test Container
Mimo iż możemy w dość prosty sposób przetestować zaprojektowaną kontrolkę za pomocą okna
About, znacznie lepszym rozwiązaniem jest skorzystanie z załączonego do kompilatora programu
ActiveX Control Test Container. Program oferuje dość spore możliwości testowania, pozwala między
innymi zdefiniować wartości wszystkich właściwości związanych z kontrolką, umożliwia też śledzenie
zdarzeń kontrolki i przetestowanie interfejsu użytkownika kart właściwości.
Program ActiveX Control Test Container przywołujemy klikając menu Tools i wybierając w nim
opcję ActiveX Control Test Container.
Wybieranie testowanej kontrolki
Kontrolkę ActiveX dodajemy do testowego kontenera klikając w menu Ędit polecenie Insert OLE
Control albo po prostu kilkając pierwszy przycisk paska narzędziowego programu. W tym momencie
wyświetlone zostanie okno dialogowe OLE Control, w którym będziemy mogli wybrać kontrolkę
przeznaczoną do testowania. Ze znajdującej się tam listy wybieramy kontrolkę Kotary i klikamy OK.
Problemy z odmalowywaniem kontrolki
Program ActiveX Control Test Container nie wykonuje żadnych operacji przycinania obrazu (ang.
clipping operations) wykonywanych przez niektóre kontenery kontrolek, które naprawiałyby
ewentualne błędy w wyświetlaniu kontrolki. Dzięki temu możemy łatwo stwierdzić, kiedy kontrolką
zachowuje się niewłaściwie i przykładowo maluje się częściowo na zewnątrz kontenera. Powinniśmy
usunąć wszelkie błędy, które zobaczymy w tym momencie, szczególnie jeśli zamierzamy korzystać z
opcji Unclipped Device Context, dostępnej w kreatorze pod przyciskiem Advanced.
W tym momencie kontrolką zostanie wyświetlona w kolorze czarnym (z powodu domyślnego
przypisania właściwości ForeColor wartości zero). Możemy teraz dowolnie zmieniać rozmiary i
położenie kontrolki wewnątrz widoku kontenera.
Testowanie właściwości kontrolki
Jeśli po dodaniu kontrolki do kontenera klikniemy menu Ędit, zobaczymy, że pojawiła się tam nowa
opcja: Properties-.Rotary Control Object. Polecenie to pozwala wyświetlać karty właściwości
kontrolki. Możemy w tym momencie obejrzeć i zmienić do-


712 Poznaj Visual C++ 6
wolną ze zdefiniowanych wcześniej właściwości. W ten sposób będziemy mogli przetestować
różne ustawienia właściwości, jak to widać na rysunku 26.14.
Możemy również za pomocą lewego klawisza myszy obracać pokrętło, sprawdzając jak
kontrolka będzie działać wewnątrz rzeczywistej aplikacji.

Rysunek 26.14. Testowanie właściwości kontrolki Rotary w oknie programu ActiveX Control Test
Container
Testowanie właściwości otoczenia
Możemy również definiować właściwości otoczenia kontrolki wybierając w menu Edit
polecenie Set Ambient Properties. Wywołamy w ten sposób przedstawione na rysunku 26.15
okno dialogowe Ambient Properties. Z listy kombinowanej wybieramy właściwość
otoczenia, którą chcemy zmienić. Następnie za pomocą kontrolek z prawej karty okna
możemy zmienić ustawienia właściwości. Jeśli przykładowo, wybierzemy występującą w
kontrolce Rotary właściwość BackColor, a następnie wciśniemy przycisk doose, wyświetlona
zostanie lista kolorów, z której będziemy mogli wybrać kolor nam odpowiadający. Po
zdefiniowaniu właściwości zamykamy okno przyciskiem CIose. Kontrolka powinna mieć
teraz nowy kolor tła (aby to zobaczyć, będziemy musieli prawdopodobnie umieścić nad
testowym kontenerem inne okno, a potem usunąć je, by w ten sposób wymusić odmalowanie
kontrolki).


Tworzenie kontrolek ActiveX 713
iisir






"^P^ Close


^
.

Ifln-Standnrd
Property;

Color - YaluB . . . . ^"e6!




! ł~ No Property :
l C "' i:.-:1 C h:l-i- ' . i '
\ r ,::':;:l!-"i,, ' \








J
^..."^r--^,-1,1.1--^





, J;




!<~''^




j











Rysunek 26.15. Definiowanie właściwości otoczenia kontrolki ActiveX w testowym kontenerze.
Obserwowanie umchomionych zdarzeń
Możemy również sprawdzić, czy zdarzenia kontrolki są uruchamiane prawidłowo,
otwierając za pomocą polecenia Event Log menu View okno dialogowe Event Log. Okno to
wyświetla'listę uruchamianych zdarzeń. Jeśli teraz zmienimy położenie pokrętła, w oknie
dialogowym pojawia się informacja, że uruchomione zostało zdarzenie Repositioned i
dodatkowo podawany jest nowy kąt wektora kontrolki (patrz rysunek 26.16).





Clear
Close
03_Rotaiy_Control: Repositioned(dNewPosition-92.1 f)
03_Rotaiy_Control:Repositioned(dNewPosition-69.90)
03_Rotaiy_Control:Repositioned(dNewPosition-5490)
03_Rotaiy_Control:Repositioned(dNBwPosition-2.79)
03_Rotafy_Control:Repositioned(dNewPosition-3'l5.B6)
03_Rolaiy_Control: Repositioned(dNewPosition-213.00)


Jąi
Rysunek 26.16. Rejestr kolejnych uruchomionych zdarzeń w oknie Event Log


Wyszukiwarka

Podobne podstrony:
6 31 Wprowadzenie do ActiveX i projektowania kontrolek ActiveX (2)
Cw 26 Elementy kontrolne
Ćwiczenia Active Directory jednostki organizacyjne tworzenie
Active Directory tworzenie własnej struktury organizacyjnej na potrzeby szkoły
26$1102 specjalista do spraw kontrolingu
Kontrola tworzenia i stosowania prawa podatkowego pod rządami Konstytucji RP
6 32 Tworzenie serwerów automatyzacji ActiveX z użyciem MFC (2)
Brand Equity czyli rynkowe efekty tworzenia marki
tworzenie marki
ZARZĄDZANIE WARTOŚCIĄ PRZEDSIĘBIORSTWA Z DNIA 26 MARZEC 2011 WYKŁAD NR 3
tworzenie aplikacji w jezyku java na platforme android
Automatyka okrętowa – praca kontrolna 2

więcej podobnych podstron