144 5 35MB
Polish Pages 284 Year 2008
Chet Haase Romain Guy
i animowane
TIWI
Tworzenie atrakcyjnych programów.
Poznaj tajniki tworzenia efektownych, a jednocześnie funkcjonalnych aplikacji, które przyciągają rzesze klientów. -t
11 Jak sterować działaniem animacji?
mJak korzystać z grafiki pulpitu dla języka Java? jH Jak tworzyć obrazy r wykorzystywać je w aplikacjach?
Helion
t :
Spis treści
S ło w o w s tę p n e ..................................................................................................................................1 3 P rzed m o w a ......................................................................................................................................... 1 5 P o d z ię k o w a n ia ...................................................................................
21
O a u t o r a c h .......................................................................................................................................... 2 3 W s tę p ...........................................................................................................
25
CZĘŚĆ I
PODSTAWY GRAFIKI I INTERFEJSÓW GUI ............. 33
R o zd ział 1.
B ib lio tek i g ra fik i pulpitu d la ję z y k a Ja v a — S w in g, A W T o ra z J a v a 2 D
................................................................... 3 5
Abstract Window Toolkit (A W T )...................................................................... 36 Java 2 D ........................................................................................................................ 37 Sw in g ............................................................................................................................37 R o zd ział 2 .
P o d staw y re n d e rin g u w S w i n g .......................
39
Z d arzenia....................................................................................................................40 Rysowanie w S w in g .................................................................................................41 Asynchroniczne żądania odrysowania.................................................................... 42 Synchroniczne żądania odrysowania....................................................................... 43
Renderowanie w S w in g ..........................................................................................44 paintComponent() ...................................................................................................... 46 p a in t().............................................................................................................................48 setOpaque() .................................................................................................................. 51
Podwójne b uforow anie..........................................................................................52
\
6
S pis
S pis
tr eśc i
W ątk i............................................................................................................................ 55 Model wątków.............................................................................................................. 57 Stopery a wątek rozsyłania zdarzeń ......................................................................... 62 Bezbolesna obsługa wątków poprzez SwingWorlcer.............................................63 Podsumowanie wątków ........................ 66
Rozdział 3.
CZĘŚĆ II R o zd ział
6.
Podstawy grafiki ................................................................... 67 ............................................................................................................. 69
Stan grafiki.....................................................................................................................72 Elementarne operacje graficzne.................................................................................97
Obrazy ................................................................................ 115 Typy o b razó w ..........................................................................................................116 Bufferedlm age........................................................................................................ 119 Skalowanie obrazów .............................................................................................. 122
W ydajność
Typowe zastosowania A lphaC om p osite........................................................ 187 Zastosowanie reguły Clear .................................................................................. 187 Zastosowanie reguły SrcOver ............................................................................. 188 Zastosowanie reguły S rc ln .................................................................................. 189 Problemy z użyciem A lphaCom posite............................................................191
137 _
Zastosowanie obcinania....................................................................................... 137 Obrazy zapewniające zgodn ość.......................................................
P rz e z ro c z y sto ś ć ............................................................................................... 1 7 5
Tworzenie i konfigurowanie obiektu AlphaComposite ........................... 186
Jakość kontra wydajność.................................................................... 125 Metoda getFasterScaled!nstance() — narzędzie do szybszego i lepszego skalowania obrazów ............................... 134
Rozdział 5.
173
Obiekt AlphaComposite. 12 reguł .......................................... 177 Clear....................................................................................................................... 179 D st.......................................................................................................................... 179 DstAtop..................................................................................................................179 D stln...................................................................................................................... 180 DstOut................................................................................................................... 180 DstOver..................................................................................................................181 S rc........................................................................................................................... 182 SrcAtop.................................................................................................................. 183 Srcln....................................................................................................................... 183 SrcOut.................................................................................................................... 183 SrcOver.................................................................................................................. 184 Xor ......................................................................................................................... 185
Pobieranie obiektu Graphics......................................................................................70
Rozdział 4.
RENDEROWANIE ZAAWANSOWANEJ GRAFIKI
Obiekt A lphaC om posite......................................................................................175
J a v a 2 D .........................................................................................................................67 R en d erin g
tr eści
143
Dlaczego powinniśmy się nimi zajmować?........................................................... 143 Co można powiedzieć o obrazach zarządzanych?...............................................145 Zapewnianie zgodności................................................................................ 146
Tworzenie własnej klasy C o m p o site............................................................... 193 Tryb mieszania A dd ................................................................................ 193 Implementowanie CompositeContext...............................................................197 Łączenie pikseli.....................................................................................................198
Obrazy zarządzane................................................................................................ 148
Podsum ow anie.......................................................................................................200
Odczytywanie danych z DataBuffer....................................................................... 152 Częste renderowanie obrazu....................................................................................154
R o zd ział 7 .
G ra d ie n ty .......................................................................................................... 2 0 1
Obrazy pośred nie...................................................................................................156
Dwuelementowy gradient lin io w y .................................................................. 202
Zasada ogólna.......................................... 157 Jak to jest realizowane? ............................................................................................. 157 Uwagi............................................................................................................................ 163 Podsumowanie............................................................................................................165
Efekty specjalne korzystające ze zwykłych gradientów ............................. 204
Optymalne rysowanie figur
Wieloelementowy gradient lin io w y ................................................................ 208 Gradient kołow y .....................................................................................................211 Optymalizacja gradientów .................................................... 214 Buforowanie gradientu........................................................................................215 Sprytniejsze buforowanie ..................................................... 216 Optymalizacja z użyciem gradientów cyklicznych........................................... 217
............................................................................ 165
Testowanie wydajności ........................................................................................ 167 Opcje wiersza poleceń .......................................................................................... 167 Renderowanie.......................................... 169 Debugowanie wydajności.........................................................................................171
R o zd ział 8 .
P rz e tw a rz a n ie o b ra z u .................................................................................2 1 9 Filtry o b ra z ó w ........................................................................................................ 219 Przetwarzanie obrazu za pomocą BufferedlmageOp ............................... 221 A ffineTransform O p..............................................................................................223 ColorConvertOp .........................................................................................
224
,,'łł
S pis
S pis
tr eśc i
C onvolveO p.............................................................................................................226
Mierzenie czasu (oraz narzędzia pomiaru czasu platform y).................. 293
Tworzenie jądra ......................................................................................................... 228 Praca na krawędzi...................................................................................................... 229
„Która godzina?” ........................................................................................................293 „Czy mogę zamówić budzenie?” ............................................................................ 296 „Zadzwoń do mnie ponownie. I ponownie. I ponownie” .................................298
L ookupO p................................................................................................................ 231
R o zd ział 9 .
9
t r e śc i
RescaleOp ................................................................................................................ 232 W łasna klasa Bufferedlm ageO p....................................................................... 234
Rozdzielczość s to p e ra ..........................................................................................305
Klasa bazowa filtra.....................................................................................................234 Filtr barwiący.............................................................................................................. 236
Rozdzielczość usypiania........................................... 310 Rozdzielczość stopera................................................................................................315
Rozdzielczość System.currentTimeMillis() oraz System.nanoTime() ........... 308
Uwaga na tem at wydajności .............................................................................. 241
Rozwiązanie problemu rozdzielczości................................................................... 317
Podsum ow anie................................................................................................... ...242
Animacje w aplikacjach S w in g......................................................................... 318
243
Grafika animowana...................................................................................................319 Animowany interfejs użytkownika........................................................................ 321
Rysowanie na szklanym p a n e lu ........................................................................ 246
Podsum ow anie.......................................................................................................331
S z k la n y p a n e l .........................................................
Optymalizacja rysowania na szklanym panelu ................................................... 247
Blokowanie zdarzeń wejściowych ....................................................................250 Problemy ze zdarzeniami m yszy............................................................................ 251
R ozdział 13. Płynne p rzesu n ięcia ................................................................................... 333 Podstawy. Dlaczego moja animacja źle wygląda? ..................................... 333 Co powoduje „szarpanie” animacji i jak można ją wygładzić?
334
R o zd ział 1 0 . P a n e le w arstw o w e .........................................................................................2 5 5
Synchronizacja jest (niemal) wszystkim................................................................335
Wykorzystanie paneli w arstw ow ych...............................................................256 Porządkowanie komponentów wewnątrz jednej w arstw y....................... 260
Kolor — co za różnica? .............................................................................................338 Pionowy powrót plamki — poczucie synchronizacji......................................... 348
Panele warstwowe i w arstw y.............................................................................. 261
SmoothMoves — program dem onstracyjny.................................................353
Alternatywa dla JLayeredPane w postaci obiektów L a y o u t.....................262
Tworzenie obiektów graficznych............................................................................ 353 Uruchamianie stopera........................................ 354
R o zd ział 1 1 . Z a r z ą d c a ry so w an ia .......
267
Renderowanie............................................................................................................. 355
Gdy Swing staje się zbyt sprytny ...................................................................... 267
Opcje renderowania..................................................................................................356
Poznajemy RepaintManager ............................................................................. 269
Podsum ow anie.......................................................................................................360
Zarządzanie obiektami RepaintManager.............................................................. 270
Odbicia i RepaintManager
.............................................................................. 271
R ozdział 14. B iblioteka Tim ing Fram ew o rk . P o d staw y .................................... 361
Zapewnienie miejsca na odbicie..............................................................................272 Rysowanie od bicia..................................................................................................... 275 Prostszy, przez co sprytniejszy RepaintManager.................................................277
W s tę p .........................................................................................................................361
Podsum ow anie............................................................. ........................................ 280
Wywołania zwrotne ..................................................................................................366
Podstawowe koncepcje ........................................................................................363 A nim ator..................................................................................................................... 364 Czas trw ania........................
368
Powtarzanie................................................................................................................ 369
CZĘŚĆ III ANIMACJA...................................................... 281
Rozdzielczość.............................................................................................................. 370 Operacje startow e...................................................................................................... 370
Rozdział 12. Podstawy anim acji...........
283
Interpolacja..............................................................................................................377
Wszystko o c z a sie ........................
.283
Przyspieszenia i opóźnienia .....................................................................................378
Podstawowe koncepcje .............
.284 ..284 ..286 ..286
Interpolator................................................................................................................. 383
Animacja bazująca na ramkach Częstotliwość k latek .................. Ruch bazujący na czasie............
Podsum ow anie.......................................................................................................395
w,ąi
pikselu, aby mógł być skopiowany do bufora tylnego
o 24-bitowym formacie RGB.
Swing. Nawet jeżeli Java 2D w koięjęu zacznie zarządzać tym-obrazem, pierwszych kilka
W Java 2D obliczenia są faktycznie nieco bardziej skomplikowane; wykonywana jest operacja 011 na
kopii, zanim rozpocznie się zarządź|łiie obrazem, będzie niezwykle kosztownych.
bitach src i najniższych bitach docelowych zamiast pozostawiania pustych bitów, jak jest to pokazane na rysunku. Jednak podstawowa zasada jest taka sama. Obliczenia są tu uproszczone, aby rysunek był łatwiejszy do zrozumienia.
R o z d z ia ł 5 .
Ob r a z y z a p e w n ia ją c e z g o d n o ś ć
W y d a jn o ś ć
private sta tic GraphicsConfiguration getConfiguration() { return GraphicsEnvironment.getLocalGraphicsEnvironmentQ. getDefaultScreenDevi ce( ) . getDefaul tConfi guration( ) ;
Zapew nianie zgodności M echanizm wykorzystywany do ładowania obrazu może utworzyć obraz, który nie jest
}
zgodny z urządzeniem graficznym. Na przykład biblioteka Image I/O dostępna w bieżących // Tworzy obraz zapewniający zgodność o takich samych wymiarach // i przezroczystości, co przekazany obraz
wersjach Java SE ładuje niektóre pliki JPEG w form acie, który nie odpowiada większości formatów graficznych. Choć obrazy BMP oraz PNG mogą być ładowane za pomocą Image I/o w rozsądnych formatach, to jednak nie powinniśmy zakładać, że format obrazu będzie zgod-
public sta tic Bufferedlmage createCompatibleImage(BufferedImage image) { return createCompatibleImage(image, image.getWidth() , image.getHeight());
ny z urządzeniem graficznym. Dodatkowo obrazy typu Toolkit, ładowane za pomocą star
}
szych API z JD K 1.0, po załadowaniu nie są w optymalnym formacie. Prawdopodobnie // Tworzy obraz zapewniający zgodność o podanej szerokości // i wysokości, posiadający taką sam ą przezroczystość, j a k podany obraz
łatwiej i lepiej jest skopiować załadowany obraz do innego obrazu o takim typie, o którym wiem y, że może zapewnić zgodność.
public sta tic Bufferedlmage createCompatibleImage( Bufferedlmage image, int width, int height) { return getConfiguration( ) .createCompatiblelmage(width, height, image.getTransparencyQ);
Czasami nie jesteśmy w stanie zmienić formatu obrazu łub nie musimy się przejmować wydajnością w określonej sytuacji. Jednak najczęściej, jeżeli istnieje sposób na uzyskanie obrazu zapewniającego zgodność, to zamiast pozostawiania go w mniej optymalnym forma
•
}
cie zwykle warto jest wykonać taką konwersję. // Tworzy nieprzezroczysty obraz zapewniający zgodność, I /
Wskazówka Konwertowanie obrazu z bieżącego formatu do lepszego sprowadza się do utworzenia obrazu zapewniającego zgodność i skopiowanie do niego starego obrazu7:
// Zakładamy, że mamy ¡component, do którego możemy // skopiować obraz; je g o obiekt G raphicsConfiguration p ozw ala na / ! utworzenie obrazu zapew niającego zgodność
G raphicsC onfiguration gc = g e tG ra p h icsC o n figu ra tio n (); Bufferedlmage compatiblelmage = gc.createCompatibleImage( suboptim alIm age.getW idth(), suboptim allm age.getH eightO ); . Graphics g = com patiblelm age.getG raphics(); g.drawImage(suboptimalImage, 0, 0, n u li) ;
W arto rozszerzyć ten pomysł i napisać klasę narzędziową, która wykona za nas odpowied nią konwersję. Zamieszczona tu przykładowa klasa posiada kilka przydatnych metod po zwalających tworzyć i ładować obrazy zapewniające zgodność8: public class MakeMineCompatible { // M etoda zwraca obraz zgodny z podstawowym I I urządzeniem graficznym. Jeżeli użytkownik ma wiele ekranów // z różną głębią kolorów, może to nie być optymalne rozwiązanie, // ale powinno działać w większości przypadków
7 Należy pamiętać, że zamieszczony tu fragment odnosi się do obrazów nieprzezroczystych. Klasa narzędziowa MakeMi neCompati bl e zapewnia konwersję pozostałych przypadków. 8 Jeżeli Czytelnik chciałby użyć tej klasy, ale nie ma ochoty przepisywać jej z książki, to można skorzystać z jej wersji dostępnej w klasie Graphi csUti 1i ti es z projektu SwingLabs, pod adresem h ttp ://s w in g x .d e v .ja v a .n et.
¡ I o podanej szerokości i wysokości public static Bufferedlmage createCompatibleImage( int width, int height) { return getConfiguration( ) .createCompatiblelmage(width, height); } , , f: // Tworzy przezroczysty obraz zapewniający zgodność,
I I o podan ej szerokości i wysokości public sta tic Bufferedlmage createCompatibleTranslucentImage( int width, ł-Hnt height) { return getConfiguration( ) .createCompatibleImage(width, height, Transparency.TRANSLUCENT); } // Tworzy obraz zapewniający zgodność na podstaw ie zawartości ..,. • // definiowanej przez zasób
public sta tic Bufferedlmage loadCompatibleImage(URL resource) throws '-►IOException { Bufferedlmage image = ImagelO.read(resource); return toCompatiblelmage(image); } // Tworzy i zwraca nowy obraz zapewniający zgodność,
I I do którego jest kopiowany obraz źródłowy I I Jeżeli obraz źródłowy już zapewnia zgodność, I I to zwracany jest obraz źródłowy // Wersja ta korzysta z Bufferedlmage, ale może być rozszerzona, // aby korzystała z obiektów Image
R o z d z ia ł 5 .
W y d a jn o ś ć
Ob r a z y z a r z ą d z a n e
— 1 ‘
public sta tic Bufferedlmage toCompatibleImage(BufferedImage image) { GraphicsConfiguration gc = getConfigurationQ; i f (image.getColorModei( ) .equais(gc.getColorModel( ) ) ) { return image; } Bufferedlmage compatiblelmage = gc.createCompatibleImage( image.getWidth( ) , image.getHeightQ, image.getTransparencyQ) ; Graphics g = compatibleImage.getGraphics(); g.drawlmage(image, 0, 0, nul 1); g.disposeO ; return compatiblelmage; } }
«
Załóżmy, że w Windows utworzyliśmy obraz zapewniający zgodność, którego zawartość mmmU
i
jest tworzona raz i później nie jest zmieniana. Zawartość obrazu znajduje się w pamięci systemu. Obraz ten nie może być przechowywany w pamięci wideo w Windows, ponieważ pamięć ta może zostać w każdej chwili utracona i zawartość obrazu zostanie zniszczona (więcej na ten temat znajduje się w opisie klasy Vol a ti 1 elmage, w punkcie „Typy obrazów”, w rozdziale 4., „Obrazy”). Teraz załóżmy, że obraz ten jest kilkukrotnie kopiowany do bufo ra tylnego Swing, który może znajdować się w VRAM.
i? ■ lljll
java 2D „zauważy”, że wielokrotnie występuje żądanie skopiowania tej samej zawartości obrazu z pamięci systemowej do bufora tylnego w VRAM . Nie jest to niezwykle powolna operacja, ale istnieją lepsze sposoby zajmowania czasu komputera niż przenoszenie obrazów
nm i g M Il
■SSWil
J p jB ™ Teraz mamy już kod pozwalający na stosowanie wszędzie obrazów zapewniających zgod- i ność. Koniec wymówek!
piksel po pikselu z głównej pamięci poprzez magistralę do pamięci wideo. Z tego powodu Java 2D może utworzyć drugą kopię tego obrazu w pamięci VRAM , bliżej bufora tylnego Swing. Przy następnym zażądaniu skopiowania obrazu do bufora tylnego Swing lub innego obrazu w VRAM Java 2D „zauważy”, że posiada odpowiednią kopię w VRAM. Będzie można wykonać operację kopiowania wersji buforowanej w VRAM. Sposób działania tego systemu jest przedstawiony na rysunkach 5.4 oraz 5.5. W końcu jest to książka o grafice.
Pamięć systemowa Nazwa obrazy zarządzan e nie odnosi się do typu obrazów, ale raczej do mechanizmu przy spieszania operacji renderowania dla dowolnych typów obrazów. Jest ona konsekwencją ; założenia, że programista powinien zajmować się wyłącznie tworzeniem i wykorzystywa- Ir niem obrazów, a mechanizmy Java 2D powinny automatycznie „zarządzać” wydajnością9. [ , Zadaniem zarządzanych obrazów jest zapewnienie, że obraz utworzony za pomocą dowol- j nego mechanizmu jest odpowiedni — przez załadowanie z dysku, utworzenie Buf feredImage J od podstaw lub utworzenie obrazu zapewniającego zgodność. W międzyczasie Java 2D bufo ruje zawartość obrazu w lokalizacji, która jest najbardziej odpowiednia z punktu widzenia wydajności.
__________________________
v
9 Pierwszą nazwą, jakiej użyliśmy do przedstawienia tego mechanizmu akceleracji, była „akceleracja pod maską”, ale była nieco przydługa i na szczęście nie uzyskała większej popularności. Bardziej zwięzłe „obrazy automatyczne” powstały później, ale opisywały ten sam mechanizm. Ta druga nazwa uzyskała pewne poparcie w środowisku programistów..., ale dla mnie i tak nie miała sensu. Nigdy nie uznałem „obrazów automatycznych” za odpowiednią nazwę, ponieważ nie występowały tu żadne automatyczne mechanizmy. Nazwa ta po prostu nie pasowała. Na końcu zaczęliśmy rozważać nazwę „obrazy zarządzane”, która była bardziej sensowna, ponieważ dosyć jasne było, że odwołuje się do zarządzania za nas obrazami i ich akce- . leracją przez Java 2D. Jest ona zwięzła i prosta, jak również odwołuje się do podobnych mechanizmów w innych bibliotekach. Trzecie podejście do opracowania nowej nazwy okazało się udane.
......... •.....- — ..-^ip— —i
* ........ .....
Ekran
Pamięć wideo Rysunek 5.4. Niezarządzane kopiowanie obrazu z pamięci systemowej do pamięci wideo
R o z d z ia ł 5 .
Ob r a z y zar zą d za n e
W y d a jn o ś ć
Svstem taki m a kilka zalet:
Pamięć system owa
• Szybkość — jasne jest, że kopiowanie danych pikseli z VRAM do VRAM jest szybsze. Procesor, magistrala oraz główna pamięć nie biorą udziału w tym procesie, a tempo kopiowania VRA M -VRA M jest znacznie większe niż w przypadku przesyłania danych przez magistralę. Dodatkowo układ graficzny jest zoptymalizowany pod kątem tego typu operacji i może działać znacznie szybciej niż CPU, nawet biorąc pod uwagę problemy z pamięcią i magistralą.
,
-
o P rzetw arzanie rów noległe — operacja kopiowania obrazu zarządzanego korzysta z możliwości przetwarzania równoległego w komputerze. Układ graficzny jest osobnym procesorem, więc rozpoczęcie kopiowania VRA M -VRA M przez ten procesor jest podobne do utworzenia nowego wątku na innym procesorze. Pozwala to na wykonywanie innych zadań przez CPU. Zaleta ta jest jasno widoczna w niektórych testach, w których zastosowanie obrazów niezarządzanych może zablokować procesor, natomiast ta sama aplikacja korzystająca z obrazów zarządzanych w znacznie mniejszym stopniu korzysta z CPU. Umożliwienie procesorowi wykonywania innych zadań daje znaczne korzyści, nie tylko w testach.
Ekran •"
v;i:w;
;
; , ■ 1
Pamięć wideo Rysunek 5.5. Zarządzane kopiowanie obrazu z wersji buforowanej w VRAM do innej lokalizacji w pamięci wideo
Zwykle aplikacja wymaga wykonania innych operacji, które zajmują procesor, więc jeżeli nie traci on czasu na proste operacje na pikselach, aplikacja i cały system operacyjny mogą działać szybciej. o Łatw ość prog ram ow an ia — zalety te są duże dla operacji zarówno na obrazach Vol a ti 1 elmage, ja k i na obrazach zarządzanych. Największą zaletą stosowania obrazów zarządzanych jest to, że programista nie musi zajmować się zarządzaniem
Na rysunku 5.4 przedstawiony jest proces kopiowania obrazu na ekran komputera bez zasto
różnymi aspektami akceleracji. Java 2D obsługuje problemy z utratą zawartości
sowania obrazów zarządzanych. Obraz jest przechowywany w pamięci systemowej, a opera
związane z wykorzystywaniem VRAM, jak również decyduje, kiedy, jak i czy należy
cja kopiowania przenosi zawartość obrazu z pamięci systemowej, poprzez magistralę systemu,
akcełerować określone obrazy i operacje na nich.
do ekranu znajdującego się w pamięci wideo. Warto przedstawić, niektóre z ukrytych szczegółów obrazów zarządzanych. Obrazy nie Na rysunku 5.5 zamieszczony jest ten sam proces z użyciem obrazów zarządzanych. Ory
zawsze są alccelerowane i dla programistów może być zagadką, dlaczego dzieje się to w da
ginalny obraz tak jak wcześniej nadal znajduje się w pamięci systemowej. Jednak na tym ry
nych sytuacjach. Zwykłe system podejmuje dobre decyzje, bazując na informacjach na temat
sunku mamy również akcelerowaną wersję tego obrazu, przechowywaną w pamięci wideo.
obrazów i operacji, a programista powinien znać decyzje podejmowane przez system. Jeżeli
Gdy zostanie zażądane wykonanie operacji kopiowania, oznaczonej przerywaną linią uko
jednak system nie przyspiesza pewnych operacji, które mogłyby skorzystać z przyspieszania,
śną, faktyczne kopiowanie będzie wykonywane w pamięci wideo, co zostanie oznaczone
dobrze wiedzieć, co może stanowić tego przyczynę.
ciągłą linią poziomą. Jeżeli zawartość oryginalnej wersji różni się od wersji buforowanej, na przykład tak jak po utworzeniu obrazu, to wykonywana jest dodatkowa operacja ko
Wskazówka
piowania z pam ięci systemowej do pamięci wideo, pozwalająca na zsynchronizowanie
Istnieją dwa rodzaje operacji na obrazach, które powodują wyłączenie akceleracji przez Java 2D
zawartości; jest ona tu oznaczona ciągłą linią pionową.
— odczytywanie tablicy pikseli i częste renderowanie obrazu.
R o z d z ia ł 5 .
W y d a jn o ś ć
Ob r a z y zarządzane
Odczytywanie danych z D ata Buffer
Uwaga
Jak już wcześniej wspomnieliśmy, oryginalna zawartość obrazu jest przechowywana w pa_ mięci systemowej, natom iast je j buforowana wersja znajduje się w VRAM . Kluczem do działania tego mechanizmu jest to, że Java 2D „wie”, kiedy zawartość obrazu zostaje zmie
Należy zwrócić uwagę, że operacja ta jest wykonywana 100 razy. Ma to za zadanie osiągnięcie dłuższych i bardziej znaczących czasów. Jest to często stosowane podejście w większości naszych testów związanych z wydajnością, szczególnie w przypadku krótkich operacji, w których ano malie testowania lub rozdzielczość stopera mogą w znacznym stopniu wpływać na wynik.
niona. W momencie aktualizacji oryginalnej zawartości nowa musi być skopiowana do akcelerowanej wersji. Jednak jedno z zastosowań Buffered Image powoduje problemy — dostęp do DataBuffer z obiektu Raster w Buffered Image.
Poniżej zamieszczona jest metoda pai ntComponent (), w której tworzymy i wypełniamy ob raz oraz mierzymy czas zarządzanej i niezarządzanej operacji kopiowania. protected void paintComponent(Graphics g) { // Utworzenie obrazu i wypełnienie go białym kołorem Bufferedlmage blmg = new BufferedImage(SWATCH_SIZE, SWATCH_SIZE, BufferedImage.TYPEJNT_RGB); Graphics glmage = blm g.getGbaphicsQ; glmage. setCol or (Col or .WHITE)’; glmage.f i H R e ct(0 , 0, SWATCjłJIZE, SWATCH_SIZE);
Jeżeli uzyskamy uchwyt obiektu DataBuffer, możemy zmieniać dane pikseli w Bufferedlmage bez „wiedzy” Java 2D. Mając obiekt DataBuffer, można zażądać tablicy surowych
d anych
pikseli, a następnie odwoływać się do nich identycznie jak w przypadku innych tablic
d an ych ,
Ponieważ Java 2D nie może określić, kiedy dane się zmieniają, nie może prawidłowo aktu alizować żadnej z akcelerowanych wersji obrazu. Dlatego w przypadku, gdy odwołujemy się do obiektu DataBuffer, Java 2D może wykonać tylko jedna operację — wyłączyć się:L, Gdy zostanie wykonana taka operacja dla obrazu, Java 2D nie może nim zarządzać, więc nie
// Zmierzenie czasu kopiowania'dla wersji zarządzanej long managedTime = copyImag|(g, blmg, 0, 0 ); System .ou t.println("W ersja ¿zarządzana: 11 + managedTime + 11 m s"); ... • .*'Y • // Zmiana kołorów poprzez tabłiąę piksełi i ponowne wykonanie testu Raster r a s te r = blm g.getR asferO ; DataBufferlnt dataBuffer = | (D ataB u fferIn t)raster.getD ataB u fferQ ; in t p ix e ls[] = d a taB u ffer.g ętD ata(); fo r (in t i = 0; i < pixels.¿length; ++i) { ' // Zmiana koloru wszystkich piksełi na czarny p ix e ls [ i] = 0 ; ;
będą dostępne funkcje przyspieszające dostępne poprzez mechanizm zarządzanych obrazów. DEM O
W SIEC I
Spójrzmy na przykładowy kod znajdujący się
w
aplikacji DataBufferGrabber dostępnej
na
witrynie W W W książki. W tym przykładzie kopiujemy kilkukrotnie obraz do bufora tyl nego Swing, mierząc czas wykonania kopiowania. Następnie obraz jest modyfikowany po przez obiekt DataBuffer i ponownie jest wykonywany test. Poniżej zamieszczona jest metoda używana do kopiowania obrazu: p rivate long copyImage(Graphics g, Bufferedlmage image, in t x, in t y) { long startTim e = System.nanoTime( ) ; fo r (in t i = 0 ; i < 100; ++i) { g.drawlmage(image, x, y , n u li) ; } long endTime = System.nanoTimeQ; return (endTime - startTim e) / 1000000; }
>
::
// Pom iar czasu wersji niezarządzanej long unmanagedTime = copyImage(g, blmg, SWATCH_SIZE, 0 ); System .ou t.println("W ersja niezarządzana: 11 + unmanagedTime + " ms"); ,
1
Należy zwrócić uwagę, że kod odczytujący tablicę danych korzysta z obiektu DataBufferlnt,
Metoda ta wykonuje 100 razy tę samą operację kopiowania i zwraca liczbę oznaczającą
ponieważ wiemy, że ten DataBuffer będzie w formacie całkowitym, bo wcześniej utworzy
czas w milisekundach, jaki był potrzebny na wykonanie tych 100 kopii.
liśmy Bufferedlmage o typie INT_RGB. W bardziej elastycznej wersji tego podejścia powin niśmy sprawdzić typ DataBuffer przed rzutowaniem.Jednak kod ten jest przykładem, w jaki sposób można uzyskać tablicę pikseli z obiektu DataBuffer i jaki wpływ będzie to miało na wydajność systemu.
10 Zespół 2D pracuje obecnie nad mechanizmami dla przyszłych wersji, które pozwoliłyby zmniejszyć liczbę przypadków, w których zostaje wyłączone przyspieszanie. Na przykład do wersji Java SE 6 włącznie zwykłe odwołanie się do obiektu DataBuffer powoduje wyłączenie akceleracji obiektu Bufferedlmage. Opracowy wane zmiany pozwolą na użycie obiektu DataBuffer przy zachowaniu akceleracji obrazu przez Java 2D, choć odwołanie się do tablicy pikseli nadal będzie powodować wyłączenie akceleracji, z opisanych wcześniej przyczyn.
Wynild tego testu zależą znacznie od platformy, na której jest on uruchomiony, oraz od zakresu możliwości przyspieszania zarządzanych obrazów przez Java 2D. Na jednym sys temie testowym uzyskałem 24 milisekundy dla wersji zarządzanej i 225 milisekund dla niezarządzanej. Należy zwrócić uwagę, że czas dla wersji zarządzanej zawiera czas potrzebny
153
R o z d z ia ł 5.
W y d a jn o ść
na uruchomienie zarządzania obrazem przez Java 2D, co zwykle jest wykonywane nr
Ob r a z y z a r z ą d z a n e
skopiować go do bufora tylnego Swing. W takim przypadku zmiany są wykonywane raz
drugiej operacji kopiowania. Należy również wiedzieć, że zmienna blmg w tym kodzie jes|
cii-, każdej kopii obrazu w buforze tylnym. W takim przypadku zarządzanie obrazem wpro
w optymalnym formacie dla tego testu, ponieważ ekran w systemie testowym również oldProgress in t w =(in t) (BAR_WIDTH * ( ( f lo a t ) oldProgress in t x =w + /* wyśrodkowanie pa sk a na ekranie * /; i nt y =/* centrowanie p aska na ekranie * /;
@0verride protected void paintComponent(Graphics g) { // pobranie bieżącego obszaru obcinania Rectangle c lip = g.getCl ipBoundsQ ;
w = (in t) (BAR_WIDTH * ( ( f l o a t ) progress /100.Of)) in t h = BARJ1EIGHT;
// ustawienie 65% prześwitywania AlphaComposite alp ha = A l p h a C o m p o s i t e . S r c 0 v e r . d e r i v e ( 0 . 6 5 f ) ; g 2 . setComposi t e ( a l p h a ) ;
// wypełnienie tła g2.setC olor(getB ackground ()); g 2 .f i l l R e c t ( c l i p .x , c li p .y , clip .w id th , cl ip .h e ig h t);
/1 00.0 f ) ) ;
. j
re p ain t(x , y, w, h );
- w;
J
• V
Metoda ta wygląda na skomplikowaną, ale przerysowanie paska postępu działa znacznie lepiej. Pierwsze wyliczenie wartości-zmiennej w pozwala na określenie bieżącej szerokości
//
w y lic z e n ie w s p ó łrz ę d n y c h x i y , ry s o w a n ie tek stu
paska postępu widzianego na ekranie. Następnie wyliczana jest wartość x, która oznacza
U
[ .. .] w y c ię te [ .. .]
koniec bieżącego paska postępu. N akoniec ponownie jest wyliczana wartość w, tym razem
R o z d z ia ł 9 .
B l o k o w a n ie z d a r z e ń w e jś c io w y c h
Sz k l a n y p a n el
tych wartQ
Jedynym sposobem rozwiązania tego problemu jest ustawienie fokusu na szklanym pane
ści w wywołaniu rep ain t(x, y, w, h) powodujemy, że Swing odrysowuje tylko kilka pil^j
lu. Rozwiązanie to może się początkowo wydać całldem proste; wystarczy wywołać metodę
zawierająca różnicę pomiędzy nowym paskiem postępu a starym. Przez użycie
na ekranie, które zmieniły się od ostatniego wywołania s e tP ro g re ss (in t). W e wszystkie
requestFocusInWindow(), aby przechwycić fokus. Niestety, metoda ta działa tylko w przy
obliczeniach zakładamy, że nowa wartość postępu jest większa niż bieżąca, ponieważ w teaplikacji pasek postępu może przesuwać się wyłącznie do przodu.
padku, gdy kontrolka żądająca fokusu jest widoczna. Poniżej zamieszczony jest kod do umieszczenia w konstruktorze naszego szklanego pulpitu:
sowywany jest prostokąt o wymiarach około 4x10 pikseli. Różnica ta daje znaczną oszczęą
addComponentListener(new ComponentAdapterQ { public void componentShown(ComponentEvent evt) { requestFocusInWi ndow();
ność czasu, a im bardziej skomplikowany jest interfejs znajdujący się poniżej, tym więcej można oszczędzić czasu.
} });
Poprzednio aplikacja przerysowywała obszar 553x394 pikseli, natomiast obecnie pivcry
Ta klasa ComponentListener jest wywoływana od razu po wyświetleniu szklanego panelu,
Rysowanie na szklanym panelu może dać nam wiele zabawy przy programowaniu, jak również znacznie poprawić jakość aplikacji.
co w łatwy sposób pozwala przechwycić fokus. Jeżeli uruchomimy aplikację z tym kodem, wszystkie zdarzenia klawiatury zostaną pochwycone w szklanym panelu. Jednak walka nie jest jeszcze zakończona, ponieważ użytkownik może nacisnąć klawisz Tab, aby przesunąć fokus na komponenty znajdujące się pod szklanym panelem. I tym razem rozwiązanie jest bardzo
Blokowanie zdarzeń wejściowych
proste i wymaga dodania do konstruktora szklanego panelu tylko jednego wiersza kodu: setFocusTraversal K eysEnabled(false);
Choć poprzedni przykład wygląda bez zarzutu, zawiera jednak poważny błąd. Jeżeli klik-;
To wywołanie metody wyłącza klawisz przełączania fokusu (zwykle T ab ), co efektywnie
niemy tabelę, będziemy w stanie zaznaczyć jeden z jej wierszy. Podobnie można kliknąć
uniemożliwia użytkownikowi przesunięcie fokusu ze szldanego panelu.
przycisk R ozpoczn ij p o b ie r a n ie i zobaczyć, że aplikacja zaczyna źle działać. Problem tkwi w tym, że pom im o tego, że szklany panel wygląda, jakby zasłaniał interfejs użytkownika,. zdarzenia przechodzą przez niego do znajdujących się poniżej obiektów UL
DEM O j W SIECI
Pełny kod źródłowy tych przykładów można znaleźć w projekcie InterceptEvents na witry nie W W W poświęconej tej książce.
Aby uniknąć tych problemów, można tak skonfigurować szklany panel, aby przechwytywał wszystkie zdarzenia myszy i klawiatury, co uniemożliwi ich przesłanie do pozostałych kom ponentów. Aby przechwycić zdarzenia szklanego panelu, należy dodać nasłuchy myszy i klawiatury. Aby przechwycić te zdarzenia i uniemożliwić ich przesyłanie do komponen tów, należy utworzyć puste nasłuchy, tak jak w poniższym przykładzie: public NullEventsGlassPane() { addMouseListener(new MouseAdapter() { } ) ; addMouseMotionListener(new MouseMotionAdapter() { } ) ; addKeyListener(new KeyAdapter() { } ) ;
Problemy ze zdarzeniami m yszy Oprócz operacji, w których należy zablokować wszystkie zdarzenia w szklanym panelu, zdarzają się również sytuacje, gdy powinien on blokować tylko niektóre ze zdarzeń. Dla przykładu utwórzmy nową ramkę i umieśćmy na niej kilka komponentów, w tym co naj mniej kilka komponentów tekstowych. Wynikowy interfejs użytkownika powinien wyglądać podobnie do przedstawionego na rysunku 9.4. Kiedy uruchomimy aplikację, zauważymy, że kursor myszy zmienia się, gdy umieścimy go
W tym nowym przykładzie wszystkie zdarzenia są przechwytywane przez szklany panel i są ignorowane. Jednak nadal nie wszystko działa prawidłowo. Choć zdarzenia myszy są obsłu
nad polem tekstowym. Działanie takie jest oczekiwane, ale nie pojawia się w przypadku ustawionego szldanego panelu, nawet jeżeli jest on przezroczysty (rysunek 9.5).
giwane prawidłowo, zdarzenia klawiatury nadal są obsługiwane, ponieważ Swing wysyła
Na rysunku 9.5, w prawym dolnym narożniku szldanego panelu, widać obraz. Implemen
zdarzenia klawiatury do komponentu mającego obecnie fokus. Jeżeli kom ponent posiada
towany jako JComponent szklany panel jest przezroczysty i pozwala użytkownikowi widzieć
już fokus (w naszym przypadku jest to tabela), będzie on w stanie przechwytywać zdarze
komponenty znajdujące się pod nim. Jeżeli jednak przesuniemy kursor myszy nad kom
nia klawiatury. Co gorsza, można nacisnąć klawisze C trl+ T ab i przesuwać fokus na ko
ponenty tekstowe, kursor pozostanie taki sam, jak pokazano na rysunku; nie zareaguje na
lejne kontrolki.
umieszczenie nad polem tekstowym. Jest to raczej zaskakujące, ponieważ nie instalowali śmy w szklanym panelu żadnego nasłuchu myszy ani żadnego innego nasłuchu zdarzeń.
R o z d z ia ł 9,
.Ja l'* ] I c i in - D n p t is le F r e y m n n n N i c o la s In o t
Imię:' jJean-Baptistel N a z w is k o :
iFreymann
M a tth ie u G r a m tv a lle t F r é d é r i c H o fm a n n
T e le fo ii:
B l o k o w a n ie z d a r z e ń
Sz k l a n y p a n e l
RsSS) 4 6 2 h 492
E - m a il:
rouian@ acm e.com
A d res:
452 Park V iew Drive 54999 Santa Clara, CA USA
R ysunek 9 .4 . Gdy kursor myszy znajdzie się nad kom ponentem tekstowym, zm ienia wygląd
w e jś c io w y c h
Kod ten powoduje, że nasz szldany panel nie otrzyma żadnych5zdarzeń myszy. Dlatego bardziej przydatna będzie następuj ącafimplementacj a contai ns ():
:j
@0verri de public boolean co n ta in s(in t x ,t i n t y) { i f (getM ouseUsteners() .length == 0 && getMouseMotionListeners().length == 0 && getMouseWheelListenersQ .length == 0 && getCursorQ == Cursor.getPredefinedCursor(C ursor.DEFAULT__CURSOR)) { return fa ls e ; } return su p er.con tain s(x, y ) ; }
W tym przypadku dodanie nasłuchu myszy lub zmiana domyślnego kursora szklanego pa nelu uniemożliwi odrzucanie zdarzeń myszy przez metodę contai n s(). Niestety, działanie takie znów powoduje powrót do początkowego problemu. Najlepszym rozwiązaniem jest ignorowanie zdarzeń myszy w obszarach przezroczystych, nawet jeżeli został dodany nasłuch myszy lub zmieniony kursor myszy. W naszym przykła dzie musimy tylko sprawdzić, czy kursor znajduje się nad rysunkiem w dolnym prawym narożniku okna:
R ysunek 9.5. Szklany panel, nawet przezroczysty, uniem ożliwia zm ianę wyglądu kursora myszy
Problem tkwi w tym, że Swing pokazuje kursor myszy najwyżej położonego widocznego komponentu. Nawet jeżeli szklany panel wygląda na przezroczysty, pozostaje widoczny i dla tego jest traktowany przez Swing jako leżący na samej górze. Aby poprawić ten błąd, wystarczy zmienić szklany panel tak, aby był przezroczysty dla
i f (image == nu li) { return fa ls e ; } else { in t imageX = getWidth() - image.getWidthQ; in t imageY = getH eight() - im age.getH eight(); return x > imageX && x < getWidth() && y > imageY && y < getH eightQ ; } Można dalej udoskonalać tę metodę, ignorując zdarzenia myszy tylko wtedy, gdy jej kursor znajduje się nad nieprzezroczystymi pikselami obrazu. Na rysunku 9.5 zauważymy obrazek
zdarzeń myszy, nadpisując metodę o nazwie contai ns (x , y ). Metoda ta zwraca true, jeżeli
larczy zawierający przezroczyste obszary. Przy użyciu powyższej implementacji kursor myszy
kursor myszy znajduje się wewnątrz granic kom ponentu3. Aby umożliwić odpowiednie
nie zmieni się, nawet jeżeli będzie się znajdował nad tymi obszarami.
zmienianie się kursora myszy, należy zaimplementować tę metodę w następujący sposób: ©Override public boolean co n ta in s(in t x, in t y) { return f a ls e ; }
3 Choć nie przedstawiamy tego zagadnienia dokładniej, m ożna wykorzystać tę metodę do tworzenia kompo nentów innych niż prostokątne. A by zaim plem entować na przykład trójkątny przycisk, należy zmienić m etodę contai ns () , aby zwracała tru e tylko wtedy, gdy wskaźnik myszy znajduje się wewnątrz trójkąta.
Rozwiązaniem tego problemu jest sprawdzenie wartości kanału alfa pílesela znajdującego się pod kursorem. Poprzednio zamieszczony kod zmieni się na następujący: i f (image == n u li) { return f a ls e ; } e lse { in t imageX = getWi dth () - image.getWidthQ; in t imageY = getHeightQ - image.getH eightQ ; // //
je ż e li k u r s o r m y szy z n a jd u je s ię n a d p rz ez ro c z y s ty m p ik s e le m , z d a rz e n ia m y szy s ą d o p u sz cz a n e
in t inlmageX = x - imageX; in t inlmageY = y - imageY;
254
R o z d z ia ł 9.
S z k l a n y p a n el
i f (inlmageX >= O && inlmageY >= O && inlmageX < image.getWidthQ && inlmageY < image.getHeightQ) { in t colo r = image.getRGB(inImageX, inlmageY); return (colo r » 24 & OxFF) > 0; } return x > imageX && x < getWidthQ && y > imageY && y < getH eightQ ;
10 Panele warstwowe
Zamieszczony tu kod wylicza położenie kursora myszy w obrazie i za pomocą m etody getRGB() pobiera kolor danego kursora. Jeżeli wartość kanału alfa dla piksela jest więksi niż 0, kod zwraca true i akceptuje zdarzenia myszy, ponieważ piksel taki nie jest przezroczvsiDEMO W SIECI
Pełny kod źródłowy tych przykładów można znaleźć w projekcie MouseCursor, na witrynie W W W poświęconej tej książce.
DEMO W SIECI
M ożna również zapoznać się z projektem G1 assDragAndDrop, który zawiera przykład łącze nia rysowania na szklanym panelu i obsługi zdarzeń myszy do wyświetlania miniatur obra zów przeciąganych z eksploratora plików do okna aplikacji, przedstawionego na rwsunku 9.6
j ? r z y tworzeniu zaawansowanych interfejsów użytkownika szklany panel oferuje wiele możliwości. Jednak ma on dwa irytujące ograniczenia: 1. Dla danej ramld można skonfigurować tylko jeden panel. Choć w większości przypadków jest to wystarczające, można napotkać sytuację, w której będą potrzebne
dialM P r z e c ią g n ij i u p u ś ć n a sz k la n y m p a n e lu P r z e c ią g n ij i w rz u ć pliki o b ra z ó w (PNG lub JP E G ) do a p lik a c ji.
dwa szklane panele, aby można było namalować kilka efektów w interfejsie użytkownika. Sprawa staje się bardziej skomplikowana, gdy nie mamy kontroli nad tym szłdanym panelem, na przykład w przypadku stosowania zewnętrznej biblioteki Java. 2. Szklany panel musi obejmować całą ramkę, co utrudnia pisanie takich paneli znajdujących się nad określonym kom ponentem lub zbiorem komponentów. Na szczęście Swing oferuje rozwiązanie tego problemu — ldasę JLayeredPane. Informacje na temat relacji pomiędzy szłdanym panelem a panelem warstwowym w ramce można zna leźć w rozdziale 9., „Szldany panel”. Zaletą paneli warstwowych w porównaniu ze szldanym panelem jest to, że można korzystać z nich w dowolnym miejscu hierarchii kom po nentów. Pom im o tego, że każda ramka Swing ma co najm niej jeden panel warstwowy, można swobodnie tworzyć nowe obiekty JLayeredPane i dodawać je do dowolnego konte nera. Jest to główna różnica pomiędzy panelem warstwowym a szłdanym panelem. W danym momencie może istnieć wiele paneli warstwowych, ale tylko jeden szMany panel. Korzystanie z paneli warstwowych jest dość proste, szczególnie jeżeli znamy już mechanizm
R ysunek 9.6. W m om encie przeciągania pliku z obrazem do ramld aplikacja wyświetla miniatury
szklanego panelu, jednak trzeba pamiętać o kilku problemach, które mogą wyniknąć w czasie
podążające za kursorem
korzystania z paneli warstwowych.
Zastosowanie szklanego panelu w aplikacji jest zaskakująco proste i korzysta z większości z własnego kodu rysującego. Możliwości oferowane przez szklany panel pozwalają na two rzenie zadziwiających efektów.
256
R o z d z ia ł 10.
Pa n e l e
w a r stw o w e
W y k o r z y s t a n ie
Wykorzystanie paneli warstwowych Jak sugeruje nazwa, JLayeredPane jest komponentem Swing, panelem, który może zawie
pan eli w a r stw o w yc h
/------------- „ ^ a n .u i u w c warcosci, na przykład numer telefonu zawierający litery, zaznaczone są małą ikoną umieszczoną w dolnym lewym narożniku pola tekstowego, ja k jest to pokazane na rysunku 10.1.
rać kilka warstw elementów potomnych. Ram ki Swing korzystają z panelu warstwowego w celu wyświetlenia poszczególnych komponentów, które muszą rozciągać się na inne kom ponenty. Na przykład dymek podpowiedzi może znajdować się zarówno nad przyciskiem jak i nad polem tekstowym umieszczonym obok niego. Menu ramek oraz menu podręczne są również często stosowanym przykładem kom ponentów rysowanych nad innymi ele mentami ramek.
J e f f D in k in s
Imię;
R i c h a r d B a ir A m y F o w le r iS c o t t V io le t H a n s M u lle r
Nazwisko:: =|Kowalski~ Telefon: ^'5S-462-424A E-mail.
¡C h ris C a m p b e ll C het H a a se
Każda warstwa w tym panelu jest identyfikowana przez wartość całkowitą definiującą głę. bokość w stosie warstw. Najwyższa wartość oznacza najwyższą warstwę stosu, czyli war stwę znajdującą się ponad wszystkimi; najniższa wartość odnosi się do najniższej warstwy, Najniższa warstwa ma głębokość równą 0. Dla naszej wygody Idasa JLayeredPane oferuje kilka identyfikatorów ułatwiających wstawianie komponentów do właściwej warstwy. Iden tyfikatory te są wymienione poniżej, od najniższej warstwy aż do najwyższej.
Rysunek 10.1. Panel warstwowy jest wykorzystywany do rysowania • znaków ostrzegawczych ponad komponentami
• JLayeredPane. DEFAULT_LAYER — jest to najniższa warstwa, na której powinny Komponentem odpowiedzialnym za rysowanie znaków ostrzegawczych jest Val idator. Dzie dziczy on po klasie JComponent i nądpisuje metodę paintComponentQ w celu narysowania
być umieszczane wszystkie zwykłe komponenty, takie jak przyciski i tabele. Jej identyfikatorem jest 0. © J LayeredPane. PALETTE_LAYER — jest to warstwa przeznaczona na palety i pływające paski narzędzi. Jej identyfikatorem jest 100.
zawartości Buffered Image nad każdym nieprawidłowym komponentem. Pełny kod źródłowy tego komponentu jest prosty i dosyć krótki: public c la s s V alidator extends JComponent { private Set
® JLayeredPane.M0DAL_LAYER — jest to warstwa na okna dialogowe.
in v alid Field s = new HashSet(); priv ate Bufferedlmage warninglcon;
Jej identyfikatorem jest 200. ® JLayeredPane. POPUP_LAYER — jest to warstwa przewidziana na okna wyskakujące, w tym dymki podpowiedzi, listy rozwijane, menu ramki i kontekstowe. Jej identyfikatorem j est 300. ® J LayeredPane. DRAG_LAYER — warstwa ta jest wykorzystywana do wyświetlania elementów w czasie operacji przeciągania. M ożna użyć jej na przykład do wyświetlania komponentów przeciąganych w programie do wizualnego budowania interfejsu użytkownika. Jej identyfikatorem jest 400. Jak można zauważyć, Swing przypisuje tym warstwom identyfikatory odległe od siebie o 100,
public Valid ator() { loadlmagesQ;
1•i
public void removeWarning(JComponent fie ld ) { i f (in va lid Field s.co n ta in s(fie ld )) { invalidFields.rem ove(field); repaintBadge(field); y } }
dzięki czemu można łatwo wstawić pomiędzy nie własne warstwy, nie powodując problemów, DEMO W SIECI
Na witrynie W W W poświęconej tej książce dostępny jest projekt o nazwie Layers, który przedstawia sposób dodawania komponentów do paneli warstwowych. Aplikacja ta składa się z jednej ramki zawierającej różne pola wprowadzania danych. Gdy
u ż y tk o w n ik
wpisze
wartość i przejdzie do kolejnego pola, program wykonuje proces kontroli poprawności
public void addWarning(JComponent fie ld ) { in va lid Field s.a d d (fie ld ); repaintBadge(field); ' ^
R o z d z ia ł 10.
258
Pa n e le
W y k o r z y s t a n ie p a n e l i
w a r stw o w e
private void repaintBadge(JComponent fie ld ) { Point p = field.getLocationOnScreen(); SwingUtilities.convertPointFromScreen(p, th is ); int x = p.x - warningIcon.getWidth() / 2; int y = (in t) (p.y + f ie ld .getHeightQ - warninglcon.getHeightQ / pgy repaint(x, y, warninglcon.getWidthQ, warninglcon.getHeightQ);
w a r stw o w yc h
259
\ b y s k o r z y s ta ć z te g o k o m p o n e n tu , n a le ż y u m ie ś c ić g o p o n a d z w y k ły m i k o m p o n e n t a m i S w in g . Z t e g o p o w o d u s k o r z y s t a m y z w a r s t w y , k t ó r e j i d e n t y f i k a t o r j e s t w ię k s z y n iż jL a y e r e d P a n e .D E F A U L T _ L A Y E R . W
ty m p r z y p a d k u w y b r a liś m y ja k o id e n ty fik a to r w a r to ś ć
DEFAULT_LAYER + 5 0 , p o n i e w a ż p o m i ę d z y i n t e r e s u ją c ą n a s w a r s t w ą , DEFAULT_LAYER, a n a s t ę p n ą , PALETTE_LAYER, z n a j d u j e s i ę m i e j s c e n a 9 9 w a r s t w . Z d o k u m e n t a c j i m o ż n a s i ę d o w i e d z i e ć ,
■/c a b y d o d a ć o b i e k t V a l i d a t o r d o p a n e l u w a r s t w o w e g o , n a l e ż y w y w o ł a ć m e t o d ę a d d ( ) ,
}
p r z e k a z u ją c d o n i e j o b i e k t I n t e g e r :
private void loadlmagesQ { try { warninglcon = ImageIO.read(getClass().getResource("images/dialog'-►warning.png11) ) ; } catch (IOException ex) { ex.printStackTraceQ; }
// »
w y w o ła n ie a d d (C o m p o n e n t, O b je c t)
a L a y e r e d P a n e .a d d ( a C o m p o n e n t ,
new
In te g e r(5 0 ));
D o d a w a n ie o b ie k t u V al i d a t o r je s t n ie z w y k le p r o s t e , je ż e l i ja k o i d e n t y f ik a t o r w a r s tw y p o d a m y w a r t o ś ć c a ł k o w i t ą , a le j e ż e l i c h c e m y s k o r z y s t a ć z w a r t o ś c i w z g l ę d n e j, s p r a w a n i e c o s ię k o m p lik u je .
}
'
""U J N a k o n ie c d o d a je m y o b ie k t V al i d a t o r d o p a n e lu w a r s tw o w e g o r a m k i:
^Override protected void paintComponent(Graphics g) { for (JComponent invalid : invalidFields) { i f (invalid.getParentQ instanceof JViewport) { JViewport viewport = (JViewport) invalid.getParen tQ ; //
ro d z ic e m
v a lid a to r
= new V a l i d a t o r Q ;
JL a y ered P a n e
la y e r e d P a n e
= g e t R o o t P a n e Q .g e t L a y e r e d P a n e Q ;
la y e r e d P a n e .a d d (v a lid a to r ,
(In te g e r)
( J L a y e r e d P a n e .D E F A U L T _ L A Y E R + 5 0 ) ) ;
w id o k u j e s t J S c r o l l P a n e
invalid = (JComponent) viewport.getParentQ;
■ Subtelności J 2 S E 5 . 0
} D o w e r s ji J 2 S E 5 .0 je d y n y m s p o s o b e m u ż y c ia id e n t y f ik a t o r a w z g lę d n e g o b y ło u t w o r z e n ie
Point p = invalid.getLocationOnScreenQ; SwingUtilities.convertPointFromScreen(p, t h i s ) ; int x = p.x - warninglcon.getWidth() / 2; int y = (in t) (p.y + in v a lid .getHeightQ - warninglcon.getHeightQ / 1.5); i f (g.getClipBoundsQ.intersects(x, y, warninglcon.getWidthQ, warninglcon.getHeightQ)) { g.drawlmage(warninglcon, x, y, n u ll); } }
n o w e g o o b ie k t u I n t e g e r : . i n t v a lu e = JL a y e re d P a n e .D E F A U L T _ L A Y E R .in tV a lu e () + 5 0 ; a L a y e r e d P a n e .a d d (a C o m p o n e n t, new I n t e g e r ( v a l u e ) ) ; O d J 2 S E 5 .0 m o ż n a s k o r z y s t a ć z f u n k c ji a u t o m a t y c z n e g o o p a k o w y w a n ia , c o p o z w a la ła tw ie j tw o r z y ć c z y t e ln y k o d : a L a y e r e d P a n e .a d d (a C o m p o n e n t, JLayeredPane.D EFA U LT_LA YER + 5 0 ) ; ' O z y t o z a d z ia ła ? J e ż e li u w a ż a s z , ż e .n ie z a d z ia ła , t o d la c z e g o ?
} }
N ie s t e t y , k o n s t r u k c ja t a k a n ie d z ia ła . K o m p i l a t o r j a v a c a u t o m a t y c z n ie o d p a k o w u je o b ie k t DEFAULT_LAYER I n t e g e r d o p o s t a c i t y p u p r o s t e g o i n t o r a z d o d a je d ó n ie g o k o l e j n ą p r o s t ą
Wywołanie metod removeWarning () oraz addWarningQ odpowiednio powoduje ukrycie i po kazanie znaku ostrzegawczego. Jak można zauważyć, Val id ato r utrzymuje listę nieprawi dłowych pól tekstowych i w metodzie pai ntComponent () rysuje obraz nad ich lewym dolnym narożnikiem. Aby to prawidłowo wykonać, położenie każdego komponentu jest konwer towane do przestrzeni współrzędnych komponentu Val i dator.
■ w a r to ś ć i n t o w a r t o ś c i 50. W w y n ik u t e g o z o s t a n ie w y w o ł a n a m e t o d a add (C om ponent,
in t),
a n ie add (C om p onent, O bj e c t ) , k t ó r a d z ia ła w z u p e łn ie i n n y s p o s ó b . A b y r o z w ią z a ć t e n p r o . b le m , n a le ż y s k o r z y s t a ć z n a s t ę p u ją c e g o id io m u : a L a y e re d P a n e .a d d (a C o m p o n e n t, .
( I n t e g e r ) . (JLayeredPane.D EFA U LT_LA Y ER + 5 0 ) ) ;
" W t e j n o w e j w e r s ji w y m u s z a m y n a k o m p ila t o r z e o p a k o w a n ie w y lic z o n e j w a r t o ś c i p r o s t e j i n t d o p o s t a c i o b i e k t u I n t e g e r . A u t o m a t y c z n e o p a lc o w y w a n ie j e s t b a r d z o e fe k t y w n ą f u n k c ją , . a le c z a s a m i n a le ż y u w a ż a ć n a j e j w y n ik i.
R o z d z ia ł 10.
Pan ele
Pa n e l e
w ar stw o w e
261
w a r stw o w e i w a r st w y
Gdy wykonamy ten kod, szybko napotkamy na kolejny problem — obiekt Val i dator nie jest widoczny. W przeciwieństwie do szklanego panelu, obiekty potomne JLayeredPane sp t;0
W ła śc iw o ść p o ło ż e n ia je s t b a rd z o w a ż n a w p rz y p a d k u , gd y o c z e k u je m y , że in n e c z ę śc i n a
myślnie widoczne, więc problem leży w innym miejscu. W rzeczywistości panele warstwowe
kod zie. Z a m ia st k o rzy stać z id e n ty fik a to ró w w arstw , m o ż n a w y b rać je d n ą w arstw ę i tw orzyć
nie mają domyślnego układu, co oznacza, że Val i dator nie posiada informacji o wymiarach Problem ten można łatwo naprawić przez wywołanie metody setBounds ():
n a n ie j sto s k o m p o n e n tó w p rz y w y k o rz y sta n iu w ła śc iw o śc i p o ło ż e n ia .
szej a p lik a cji b ę d ą k o rzy stać z teg o sa m eg o o b ie k tu JL ay ered P an e, ta k ja k w p rzed staw io n y m
valid ator.setBou nds(0, 0, getW idth()s getH eig h tQ );
Panele warstwowe i warstwy
Bezpośrednie ustawienie granic w pokazany tu sposób działa w przypadku, gdy ramka ma' już określoną wielkość. Dodatkowo kom ponent nie rozszerza się odpowiednio, gdy użyt dżera układu dla panelu warstwowego. Niestety, zadanie to okazuje się bardziej skompliko- •
Panele warstwowe, podobnie jak inne kontenery Swing lub AW T, mogą korzystać z zarządcy układu do obliczenia położenia i wymiarów elementów potomnych. Tradycyjne obiekty
wane niż w przypadku zwykłych kontenerów Swing. Zanim zagłębimy się w to zagadnienie przedstawimy jeszcze inną funkcję JLayeredPane, o której trzeba koniecznie pamiętać.
w przestrzeni dwuwymiarowej, natomiast panele warstwowe działają w przestrzeni trój
kownik zmieni wielkość ramki. Aby rozwiązać ten problem, należy skonfigurować mene
zarządców układu nie działają zbyt dobrze na panelach warstwowych, ponieważ działają one wymiarowej. Dlatego tradycyjne obiekty zarządców układu użyte dla paneli JLayeredPane rozmieszczają komponenty tak, jakby wszystkie miały tę samą głębokość — jak gdyby znaj dowały się na tej samej warstwie.
Porządkowanie komponentów wewnątrz jednej warstwy
! demo iWSIECI
Na witrynie W W W poświęconej tej książce znajduje się aplikacja ilustrująca efekt zasto sowania FI owLayout dla panelu warstwowego. Na rysunku 10.2 można zobaczyć kilka zdjęć obok siebie oraz lupę (powiększenie) pokazującą nadkładanie się niektórych zdjęć. W rze
Przedstawiliśmy już, w jaki sposób dodać pojedynczy kom ponent do wybranej warstwy
czywistości każde zdjęcie oraz lupa znajdują się na różnych warstwach panelu warstwowego'.
panelu warstwowego. Nie rozwiązaliśmy jeszcze bardzo często spotkanego przypadku — w jaki
Ponieważ jednak aplikacja korzysta z układu FI owLayout, komponenty są rozłożone obok
sposób można dodać kilka komponentów do tej samej warstwy? Wewnątrz warstwę moż
siebie. Aby jasno zobaczyć, że każde zdjęcie znajduje się na własnej warstwie, można zmienić
na sterować kolejnością komponentów przez ustawienie innej właściwości, nazywanej po
układ dla lupy. Kod źródłowy tej aplikacji znajduje się w projekcie LayeredPaneLayout.
zycją. Pozycja, podobnie jak identyfikator warstwy, jest liczbą całkowitą (ale nie obiektem Idasy Integer!), której wartość definiuje głębokość komponentów wewnątrz warstwy. Nie stety, wszystko jest bardziej skomplikowane, ponieważ schemat numerowania jest inny niż identyfikatory warstw. Na przykład warstwa 0 jest warstwą najniższą, natomiast pozycja 0 oznacza komponent znajdujący się na górze warstwy. Im większa wartość pozycji, tym mniej sza głębokość. Poniżej zamieszczony jest mały przykład kodu przedstawiający sposób usta wiania pozycji komponentu: layered Pane.ad d(niebieski, new In te g e r(lO ), 15); layeredPane.add(zielony, new In te g e r(1 0 )s 4 2 ); layeredPane.add(czerwony, new In te g e r( 5 ) ) ; W takiej konfiguracji czerwony komponent znajduje się na dole ramki, a następnie na tej. samej warstwie znajdują się komponenty niebieski i zielony. Ponieważ niebieski komponent ma niższą wartość położenia niż zielony, znajduje się on na górze. Dlatego stos komponen tów wygląda w następujący sposób: Rysunek 10.2. Tradycyjne obiekty zarządców układu nie sprawdzają głębokości potomków panelu warstwowego
N iebieski (na górze) Zielony Czerwony (na dole)
i
"‘V
" .
I
T
Ą*
r ;■
R o z d z ia ł 10.
Pa n e le
A ltern atyw a
w a r stw o w e
d la
JL a y e r e d P a n e
w p o s t a c i o b ie k t ó w
La y o u t
Jedyną efektywną metodą użycia układu w panelu warstwowym jest napisanie własne
Kolejność z definiuje pozycję komponentów według osi Z, którą można sobie wyobrazić
lub użycie najm niej znanego zarządcy układów, j ava. awt. Over! ay Layout. Ten bardzo oro
jako oś prostopadłą do okna Swing. Mówiąc najprościej, definiuje głębokość komponentu.
sty zarządca tworzy stos komponentów, więc świetnie nadaje się do naprawienia poprze
Im mniejsza jest ta liczba, tym wyżej na stosie znajduje się dany komponent. Na przykład
niej aplikacji (z projektu Layers). Poniższy fragment kodu ilustruje sposób skonfiguro
komponent z wartością kolejności z równą 10 zostanie narysowany powyżej komponentu
wania kom ponentu V alid ato r dla ram ki, aby nie występowały problem y związane ze zmianą wielkości:
o. tej wartości równej 0. N a
v alid ato r = new V alid ato rQ ; JLayeredPane layeredPane = getRootPane().getLayeredPaneQ; 1ayeredPane.setLayout(new Over!ayLayout(1ayeredPane)) ; 1ayeredPane.add(validator, (In teger) (JLayeredPane.DEFAULT_LAYER + 5 0 ) );
witrynie W W W poświęconej tej książce można znaleźć projekt o nazwie StackLayout.
Projekt ten zawiera kilka przykładowych aplikacji, które wykorzystują własną klasę zarządcy układu o nazwie StackLayout. Gdy dodajemy kom ponent do kontenera korzystającego z obiektu StackLayout, można zdecydować, czy umieścimy go na dole, czy na górze stosu wyświetlania. Aplikacja dem onstracyjna pozwalająca na wybieranie fotografii, pokazana na rysunku 10.3, ma trzy różne warstwy: gradientu w tle, fotografii oraz animowanych
Aby napisać własny układ biorący pod uwagę głębokość, konieczne jest odczytywanie okre
białych krzywych.
ślonych właściwości z każdego rozmieszczanego komponentu. Poniższy fragment kodu pozwala odczytać identyfikator warstwy komponentu: Integer layered = (In teger) aComponent.getClientProp erty("layeredC ontain erL ayer"); M ożna również zażądać od panelu warstwowego podania identyfikatora warstwy danego komponentu. Technika ta jest znacznie prostsza, ale musimy wiedzieć, że komponent należy do panelu warstwowego: in t layeredld = 1ayeredPane.getLayer(aComponent); O biekt Layers może być użyty w celu dodania głębokości do hierarchii kom pon en tów Swing. Innym sposobem na osiągnięcie efektu głębokości jest użycie układów, co zostanie przedstawione w następnym podrozdziale.
Alternatywa dla JLayeredPane w postaci obiektów Layout
Rysunek 10.3. Przy użyciu odpowiedniego zarządcy układu dowolny kontener może obsługiwać głębokość Klasa StackLayer korzysta z prostszej metody osiągnięcia efektu głębokości niż JLayered Pane, ale można dodawać komponenty wyłącznie na górę lub na dół stosu, tak jak jest to
M ogą zdarzać się sytuacje, gdy potrzebujem y użyć kom ponentu warstwowego, unikając
pokazane w poniższym fragmencie kodu:
problemów związanych z JLayeredPane. Może się to zdarzyć, gdy k o rz y sta m y z istniejące go, skomplikowanego kodu lub po prostu nie chcemy korzystać z API JLayeredPane. Roz poczynając od J2SE 5.0 dostępny jest prosty sposób dodania obsługi głębi do zwykłych kom ponentów Swing poprzez zastosowanie dwóch nowych metod klasy java.awt.Container: setComponentZOrder() oraz getComponentZOrder().
JPanel pane = new JP a n e lQ ; pane.setLayout(new StackLayout( ) ) ; //
tło z g r a d i e n t e m
GradientPanel gradient = new GradientPanel( ) ; //
w y b ó r z d ję ć
AvatarChooser chooser = new AvatarChooser(); //
a n im o w a n e k rz y w e
CurvesPanel curves = new CurvesPanel( ) ;
R o z d z ia ł 10.
Pa n e l e
w ar stw o w e
A ltern atyw a
pane.add(gradient, StackLayout.TOP); pane.add(chooser, StackLayout.TOP); pane.add(curves, StackLayout.TOP);
d la
JL a y e r e d P a n e
w p o sta c i o b ie k t ó w
La y o u t
Podobnie ja k BorderLayout, StackLayout rozciąga każdy kom ponent, aby wypełnił całą dostępną przestrzeń. Na koniec zarządca układu wywołuje metodę setComponentZOrder() kontenera nadrzędnego, aby przypisać każdemu komponentowi odpowiednią wartość głę
W przypadku tej aplikacji każdy kom ponent jest dodawany ponad poprzednim, co w efek
bokości. Ponieważ mniejsze wartości oznaczają komponenty znajdujące się na górze, war
cie tworzy oczeldwany przez nas wizualny stos. Przy dodawaniu komponentu do konlene-
tość kolejności z jest przeciwieństwem indeksu komponentu na liście. Pełny kod źródłowy
ra korzystającego ze StackLayout jest on dodawany do listy w zależności od jego położe
tych przykładów można znaleźć w projekcie StackLaout, na witrynie W W W poświęconej
nia w stosie:
tej książce.
public class StackLayout implements LayoutManager2 { public sta tic final String BOTTOM = "bottom"; public sta tic final String TOP = "top";
Warstwy są niezwykle przydatne, niezależnie, czy będziemy je tworzyć przy użyciu JLaye '-►redPane, własnego zarządcy układu; czy kombinacji obu rozwiązań. Jeżeli w aplikacji chcemy obsługiwać kilka szklanych paneli, mechanizm ten może rozwiązać wiele problemów, ale niestety, jest on często pomijany.
private List components = new LinkedList(); public void addLayoutComponent(Component comp, Object constraints) { synchronized (comp.getTreeLock()) { i f (BOTTOM.equals(constraints)) { components.add(0, comp); } else { components. add(comp); }
W skazówka Pam iętaj o panelu warstwowym Jako zasadę należy przyjąć, że trzeba rozważyć wykorzystanie panelu warstwowego, jeżeli mamy zamiar skorzystać ze szklanego panelu. Jest to szczególnie istotne w skom plikowanych aplika cjach, w których szklany panel może, być nadużywany, a panele warstwowe m ogą zaoferować potrzebną elastyczność. W m ałych lu b bardzo prostych aplikacjach praw dopodobnie nie m ożna
} }
.
■
-
-Ili ¡ ¡I
/ / ... } Dzięki takiej implementacji lista komponentów zawsze zawiera te komponenty w odpowied niej kolejności. Następnie konieczne jest ustawienie kolejności z komponentów, zgodnie z położeniem na liście: public void layoutContainer(Container parent) { synchronized (parent.getTreeLockQ) { int width = parent.getWidth(); int height = parent.getHeightQ ; Rectangle bounds = new Rectangle(0, 0, width, height); int componentsCount = components.sizeQ ; for (in t i = 0; i < componentsCount; i++) { Component comp = components.get(i) ; comp.setBounds(bounds) ; parent.setComponentZOrder(comp, componentsCount - i - 1); }
uzasadnić wprowadzania dodatkowego skomplikowania związanego z użyciem panelu warstwo wego zam iast szklanego.
R o z d z ia ł 10.
Pa n e le
w a r stw o w e
Zarządca rysowania S w in g jest zaawansowaną i elastyczną biblioteką. W większości przypadków wykonuje swoje zadania bez zarzutu. Istnieją jednak sytuacje, gdy trzeba przechytrzyć Swing i zmie nić jego domyślne działanie. Repai ntManager jest specjalną klasą, którą można dołączyć do elementów wewnętrznych Swing i która, jak się okaże w tym rozdziale, jest bardzo uży teczna przy tworzeniu zaawansowanych efektów wizualnych.
Gdy Swing staje się zbyt sprytny Mechanizm rysowania Swing zawsze próbuje odrysowywać tylko niezbędne elementy. Rysuje on tylko te regiony komponentów, które muszą być przerysowane. Jest to bardzo przydatne z perspektywy wydajności, ale może przeszkadzać w tworzeniu niektórych efektów graficz nych. ,Ąby przedstawić problem, który może wyniknąć w.przypadku korzystania ze Swing, prze analizujmy przykładowy projekt o nazwie Trans! ucentPane!, któiy można znaleźć na witry nie W W W poświęconej tej książce. Przedstawiona poniżej klasa Trans! ucentPane! dziedziczy po JPane! i ustawia przezroczystość wszystkich komponentów potomnych: public c la s s Trans!ucentPane! extends JPane! { Bufferedlmage image = n u li; (¿Override public void paint (Graphics g) { i f (image == null || image.getWidthQ != getWidthQ || image.getHeight() != getH eight() ) { image = (Bufferedlmage) createIm age(getW idth(), getH eig h tQ );
R o z d z ia ł 11.
268
Z arządca
P o z n a je m y Re p a in t M a n a g e r
r y so w a n ia
Graphics2D g2 = im age.createG rap h ics(); g 2 .s e tC lip (g .g e tC lip ()); su p e r.p a in t(g 2 ); g 2 .d is p o se (); g2 = (Graphics2D) g .c r e a t e ( ) ; g2. setComposi te(AlphaComposi t e . SrcOver. deri ve( 0 .2 f ) ) ; g2.drawlmage(innage, 0 , 0, n u li); }
}
lii!
Graj
Pauza
-f'-.
W trakcie rysowania komponent ten tworzy tymczasowe obrazy pamięciowe, rysuje po11.2. W
trzebne komponenty z przezroczystością równą 20%, a następnie wyświetla obrazy na ekra
Rysunek
nie. Na rysunku 11.1 przedstawiony jest wynik dodania do Trans! ucentPanel komponentu
przezroczystość zostaje u tra co n a
czasie odrysow yw ania k o m p o n e n tu p o to m n eg o
JTable oraz kilku JButton. .............. r-iiu-i m ii i )! M m i i i ' '■ Jju n y R l ¡ f i U i l - 1' t i l H fią < y r d i n h l T ' '' " h j' , H i i u P a i ! ; _ 1 > D l M " lln u ul i 1 ' i ‘ I r t i i| M l l l i f l 1 .-ii! , ■ ; fi M i i H M
.
_ i r | x | j , 11, . ' . , U l .1 lin ii! .a r 1lin ,-, w 1 i p ,i i m T ii.j i ■ i 1 C p t . i h 1i i m i i r ' _ r , ‘ * i i 1” , i
_ _
Uwaga Komponenty przezroczyste Swing może wywołać metodę pai nt () komponentu nadrzędnego, gdy komponent do przeryso wania jest przezroczysty. Niestety, nie możemy zagwarantować, aby użytkownicy naszej klasy Transl ucentPanel zapewniali przezroczystość wszystkich dodawanych komponentów. ** Jedynym rozwiązaniem tego problemu jest zmiana sposobu, w jaki Swing decyduje, czy kom ponent musi być przerysowany, i wymuszenie przerysowania Transl ucentPanel oraz jego
j
potomków. Kluczem do tego rozwiązania jest Repai ntManager.
Poznajemy R ep ain tM an age; Rysunek 11.1. Komponent JTable oraz trzy JButton narysowane przez TranslucentPaneł Rolą klasy Repai ntManager jest optymalizacja procesu przerysowywania komponentów Swing. Na pierwszy rzut oka TranslucentPaneł działa perfekcyjnie. Niestety, nie jest to prawda.
Jest to realizowane przez przechwytywanie wszystkich żądań przerysowania komponentów
Jeżeli uruchomimy aplikację i klikniemy tabelę lub jeden z przycisków, komponent ten sta
Swing i śledzenie elementów do przerysowania. Regiony komponentów, które należy zaktu
nie się nieprzezroczysty, jak jest to pokazane na rysunku 11.2. Nie ma potrzeby sprawdzania
alizować, są nazywane brudnym i regionam i.
kodu w Transl ucentPanel; nie ma tam błędu. Po przechwyceniu żądania przerysowania Repai ntManager korzysta z metody Swi ngUti 1i ti e s . Problem tkwi w mechanizmie rysowania zastosowanym w Swing — mechanizm ten pró
'-"i nvokelater() w celu wysłania żądania do wątku przesyłania zdarzeń. Następnie wątek
buje odrysować tylko te komponenty i regiony, które muszą być odrysowane. Gdy klikniemy
F.DT przetwarza żądania i przesyła je do komponentów wymagających aktualizacji.
na przykład JButton, Swing wywołuje metodę pai nt () z ldasy JButton, a nie metodę z jej klasy nadrzędnej. Tak więc metoda pai nt () z ldasy Transl ucentButton, odpowiedzialna za
W wyniku tego żądanie przerysowania jest wysyłane do RepaintManager, gdy w obiekcie
przezroczystość, nie jest wywoływana.
JComponent zostanie wywołana metoda repai nt () lub re p a in t(in t, in t, in t, i n t). Klasa RepaintManager zarządza łączeniem kolejnych wywołań repai nt () w możliwie niewiele wywołań EDT.
R o z d z ia ł 1 1 .
Z a r z ą d c a r y s o w a n ia
N a rysunku 11.3 przedstawiony jest schem at interakcji RepaintManager z JComnQne oraz EDT.
JComponent.repaint()
O dbicia i R epaintM an ager Abv wyjaśnić, w jaki sposob należy korzystać z klasy Renai n LManager, skorzvslainy z projektu o na/wie .RepaintManager, który można znaleźć na witrynie W W W poświęconej tej książce. Projekt ten zawiera, rozszerzenie JPanc"! o nazwie Refl ecLi onPanel. Klasa ta pozwala nam na n a rv so w a n ie
RepaintManager
odbicia wszystkich :c; c.emeiuow potomnych. Można jej użyć na przykład do
dodania efektownego odbicia do filmu, Lak jak na rysunku 1 l.-l. Gdy uruchomimy tę apli kację, zobaczymy, ż.e odbicie h-st aktualizowane w czasie rzeczvwistvm.
EDT
JComponent.paintO V
........
Rysunek 11.3. RepaintManager przechwytuje wszystkie żądania przerysowania Najbardziej interesującą metodą w Repai ntManager jest: void addDirtyRegion(JComponent c , in t x, in t y , in t w, in t h) M etoda addDirtyRegionQ jest odpowiedzialna za śledzenie brudnych regionów, kompo nentów, które muszą być przerysowane. Jest ona wywoływana po repaint () i dlatego może. być używana do przechwytywania wszystkich żądań przerysowania. Co bardziej interesu-1 jące, addDi rtyRegion() może być używana do rozszerzan ia brudnych regionów. W dalszej części rozdziału pokażemy, do czego ta funkcja może być przydatna.
Zarządzanie obiektami R epaintM an ager W implementacji Swing firmy Sun dostępny jest jeden globalny RepaintManager. Można pobrać bieżący obiekt Repai ntManager przez wywołanie jednej z następujących metod klasy
Rysunek 11.4. ReflectionPanel rysuje odbicie w czasie rzeczywistym wszystldch znajdujących się w nim elementów potomnych
RepaintManager: s t a t i c RepaintManager currentManager(Component c) s t a t i c RepaintManager currentManager(JComponent c) Parametry te są obecnie niewykorzystywane, ponieważ zawsze zwracany jest ten sam obiekt Repai ntManager. Można również zamienić bieżący Repai ntManager na własny: void setCurrentManager(RepaintManager aRepaintManager)
Ostrzeżenie Odtwarzanie filmów w programie demonstracyjnym Aby uruchomić przykładową aplikację z filmami, w systemie konieczne jest zainstalowanie pro gramu QuickTime. Jeżeli QuickTime nie jest dostępny, na przykład w systemie Linux, aplikacja automatycznie wyświetli zwykłe komponenty Swing, jak jest to pokazane na rysunku 11.5. W takim przypadku odbicie będzie reagować na wszystkie zmiany w komponentach Swing. Gdy na przykład naciśniemy przycisk, będzie on również wciśnięty w odbiciu.
■ R o z d z ia ł 11.
272
Zarządca
I
r y so w a n ia
Od b ic ia i R e p a in t M a n a g e r
T
.
Panel zawartości
wysokość panelu zawartości x (1,0 + wysokość odbicia)
wysokość panelu zawartości Pusta przestrzeń
X
wysokość odbicia >f
T
ReflectionPanel Rysunek 11.6. Do panelu jest dodawana pusta przestrzeń, aby zrobić miejsce na odbicie Możliwe jest przedefiniowanie metody g etPreferred Size() i zwiększenie wysokości Rysunek 11.5. Odbicie reaguje na wszystkie operacje aktualizacji komponentów dzięki zastosowaniu specjalnego obiektu RepaintManager
Zapewnienie miejsca na odbicie Domyślnie JPanel ma taką preferowaną wielkość, aby można było wyświetlić wszystkie jego kom ponenty potomne. Dlatego w panelu nie ma wolnego miejsca, w którym ReflectionPanel może narysować odbicie elementów potomnych. Aby można było narysować odbicie, konieczne jest powiększenie Ref 1 e c ti onPanel, jak jest to pokazane na rysunku 11.6. Ref 1e c ti onPanel składa się z panelu zawartości, osadzonego obiektu Jpane, do którego będą dodawane komponenty, oraz pustej przestrzeni. Wysokość pustej przestrzeni, i przez to Ref! e c ti onPanel, zależy od wysokości panelu za wartości oraz wysokości odbicia. Wysokość odbicia jest liczbą z zakresu od 0 .0 do 1.0. Ma przykład wysokość odbicia równa 0 .5 da w efekcie odbicie o wysokości równej połowie panelu zawartości. Do umieszczenia panelu zawartości na górze komponentu Refl e cti onPanel korzysta z ukła du GridBagLayout. Dolna część Refl e c ti onPanel jest wypełniana pionowym elementem łączącym, utworzonym za pomocą klasy Box. Element łączący jest to pusty komponent, który zajmuje możliwie dużo miejsca w jednym kierunku.
Refl ecti onPanel. Przedstawiony poniżej kod ilustruje budowę Refl ecti onPanel: public class ReflectionPanel'extends JPanel { private JPanel contentPane; private boolean in itia liz e d = false; private flo at length = 0.65f; public ReflectionPanel () { super(new GridBagLayout( ) ) ; setOpaque(false); buildContentPane(); bui1dFi11e r( ) ; in itia liz e d = true; } private void buildContentPaneQ { contentPane = new JPanel (new BorderLayoutQ); contentPane.setOpaque(false); add(contentPane, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints. BOTH, new lnsets(0, 0, Of 0), 0, 0 ));
R o z d z ia ł 11.
Zarządca
O d b ic ia i Re p a in t M a n a g e r
r y so w a n ia
} else { super.setLayout(mgr); }
private void b u iid F iiie rO { add(Box.createVerticalG1ue(), new GridBagConstraints(Os 1, 1, 1, 1.0, 1.0, Gri dBagConstrai nts.CENTER, Gri dBagConstrai n ts.VERTICAL, new lnsets(0, 0, 0, 0), 0, 0 ));
g i f r ;'} Po zainicjowaniu obiektu ReflectionPanel wszystlde wywołania są delegowane do panelu zaw artości.
©Override public Dimension getPreferredSizeQ { Dimension size = contentPane.getPreferredSizeQ; size.height *= l.O f + length; return size; '}
}
.
Rysowanie odbicia Następnym krokiem jest narysowanie odbicia: -llil
SUB
ReflectionPanel musi również zapewnić, że komponenty dodawane przez użytkownika
1. Rysowanie zawartości panelu w obrazie pamięciowym (buforze zawartości). 2. Rysowanie zawartości bufora na ekranie.
klasy trafiały do panelu zawartości, a nie całego Ref 1ecti onPanel. Zmienna i ni ti al i zed typu
3. Tworzenie odbicia bufora zawartości w innym obrazie (buforze odbicia).
boolean pełni ważną.funkcję przy delegowaniu wywołań add(), remove() oraz setLayoutQ
4. Rysowanie bufora odbicia na ekranie.
do panelu zawartości: ©Override protected void addlmpl(Component comp, Object constraints, in t index) { i f (in itia liz e d ) { contentPane.add(comp, constraints, index); } else { super.addlmpl(comp, constraints, index); } }
Metoda paint() Masy ReflectionPanel zawiera na początku rysowanie zawartości, a na stępnie odbicia: @0verri de public void paint(Graphics g) { paintContent(g); paintReflection(g); } Metoda paintContentQ wykonuje jednocześnie dwie pierwsze operacje — tworzy bufor zawartości i rysuje go na ekranie. Jej implementacja jest następująca:
©Override public void remove(int index) { contentPane.remove(index);
»,
}
I
©Override public void remove(Component comp) { contentPane.remove(comp); } ©Override public void removeAllQ { contentPane.removeAll( ) ; } ©Override public void setLayout(LayoutManager mgr) ( i f (in itia liz e d ) { contentPane.setLayout(mgr);
private BufferedImage contentBuffer = nuli; private Graphics contentGraphics = nul 1; private void paintContent(Graphics g) { i f (contentBuffer == nuli || contentBuffer.getWidthQ != contentPane.getWidthQ || contentBuffer.getHeightQ != contentPane.getHeightQ) { i f (contentBuffer != null) { contentBuffer.flush(); contentGraphics.dispose(); } contentBuffer = new BufferedImage(contentPane.getWidth(), contentPane. getHeight( ) , Bufferedlmage.TYPE_INT_ARGB); contentGraphics = contentBuffer.createGraphics();
R o z d z ia ł 11.
Zarządca
r y so w a n ia
Graphics2D g2 = contentGraphics; g 2.clip R e ct(co n te n tP an e .g e tX (), con tentP an e.getY (), contentPane.getW idth(), contentP an e.getH eight()); // ponieważ bufor zawartości jest ponownie wykorzystywany, // należy wyczyścić obraz g2.setComposite(AlphaComposite.C le a r); Rectangle c lip = g .g e tC lipBounds( ) ; g 2 .f i l l R e c t ( c l i p .x , c li p .y , clip .w id th , c lip .h e ig h t ) ;
O d b ic ia i Re p a in t M a n a g e r
Kod rysujący jest teraz kompletny. Jeżeli jednak uruchomimy tę aplikację, napotkamy na te same problemy, z którymi spotkaliśmy się przy omawianiu przykładu Trans!ucentPanel, jak widać na rysunku 11.7, odbicie nie jest aktualizowane w czasie odtwarzania filmu. Fak tycznie, gdy komponent odtwarzacza musi być odrysowany, domyślny RepaintManager nie
informuje komponentu nadrzędnego, Refl ecti onPanel, o konieczności odrysowania. Z tego powodu widzimy tylko odbicie pierwszej klatki filmu.
g2. setComposi te (A lphaComposi t e . SrcOver); g 2 .se tC o lo r(g .g e tC o lo r()); g 2 .s e tF o n t(g .g e tF o n t()); su p e r.p a in t(g 2 ); g.drawImage(contentBuffer, 0, 0, n u ll); }
■
Kod ten zawiera kilka optymalizacji. Na przykład wykorzystywany jest stale ten sam bufor zawartości, chyba że zmieni się wielkość panelu. Takie działanie pozwala zaoszczędzić sporo czasu, gdy przerysowanie jest wykonywane często, tak jak w przypadku wideo. Do datkowo należy zauważyć, że tworzona jest część wspólna obszaru przycinania i granic pa nelu zawartości, co jest niezbędne, gdy żądania re p a in t() obejmują część pustego obszaru ReflectionPanel. Rysowanie odbicia jest nieco bardziej skomplikowane. Przede wszystkim samo odbicie musi być wygenerowane w buforze odbicia, a bufor ten musi być narysowany w pustej przestrzeni obiektu Refl ectionP anel: p riv ate void paintR eflection(G raphics g) { in t width = contentPane.getW idthQ ; in t height = (in t) (contentPane.getH eightQ * len g th ); c re a te R e fle c tio n (g , width, h e ig h t); Graphics2D g2 = (Graphics2D) g .c r e a te Q ; g 2 .s c a le (1 .0 , - 1 .0 ) ; g2.draw Im age(reflectionBuffer, 0, -contentPane.getH eightQ - heigh t, null); g 2 .d isp o se Q ;
Rysunek 11.7. Bez specjalnego obiektu RepaintM anager odbicie nie je st aktualizowane
Aby rozwiązać len problem, musimy zastosować własny RepaintManager, który będzie iniormowal ReflectionPanel o konieczności odrysowania.
} W ywołanie s c a l e ( 1 .0 , -1 .0 ) nie powinno być niespodzianką po lekturze rozdziału 7.,
Prostszy, przez co sprytniejszy RepaintM anager
„Gradienty”, w którym przedstawione zostały sposoby tworzenia efektu odbicia. W pod rozdziale „Efekty specjalne korzystające ze zwykłych gradientów” rozdziału 7. przedstawi
Aby nasze odbicie działało, musimy zainMaiuwać własny Repai ntManager. Ten nowy Repai nt-
liśmy, w jaki sposób została utworzona metoda c re a teR e fle ctio n Q wykorzystana w tym
Marager będzie prosisz.) i będzie odiy.-owywal komponenty, które według Swing nie muszą
przykładzie kodu.
być aktualizowane. Instalowanie obiektu Repai ntManager jest dosyć proste:
R o z d z ia ł 11.
Za r ządca
O d b ic ia i R e p a in t M a n a g e r
r y s o w a n ia
.Container parent = c.g etParen t();
private void installRepaintManagerQ { ReflectionRepaintManager manager = new ReflectionRepaintManagerQ; RepaintManager.setCurrentManager(manager);
.//
d o p ó k i n ie m o ż n ą z n a le ź ć o b ie k tu n a d r z ę d n e g o
while (parent instanceof JComponent) { // //
}
j e ż e l i o b ie k t n a d r z ę d n y n ie j e s t w id o cz n y , n ie je s t k o m p o n en tem
i f (!p a re n t.is V is ib le ()) { return; }
W klasie ReflectionRepaintManager nadpisana jest jedyna metoda addDi rtyRegion(). Xa leży pamiętać, że metoda ta jest wywoływana za każdym razem, gdy do komponentu jest wysłane żądanie odrysowania.
i f (parent instanceof ReflectionPanel) { x += lastDeltaX; y += lastDeltaY;
Dla każdego kom ponentu, który wymaga odrysowania, nasza implementacja addDi rtyRegion() przegląda obiekty nadrzędne kom ponentu, szukając obiektu ReflectionPanel Gdy zostanie odnaleziony talci obiekt, brudny; region jest tak rozszerzany, aby obejmował
//
ro z s z e rz e n ie
zarówno brudny region, jak i odpowiadający mu obszar odbicia. Na rysunku 11.8 pokazane
//
o b e jm o w a ł o d p o w ie d n i o b s z a r o d b ic ia
są brudne regiony używane przez domyślny Rep.ai ntManager oraz Ref 1ecti onRepai ntManager.
in t gap = contentPane.getHeight() - h - y; h += 2 * gap + h;
b r u d n e g o r e g i o n u w ta k i s p o s ó b , a b y
lastDeltaX = lastDeltaY = 0; // . .
Panel zaw a rto śc i
1
P o c zą tk o w y b ru d n y re g io n -
Panel za w a rtośc i
/
//
R o zs ze rzo n y ,
c = (JComponent) parent;
b ru d n y reg ion
}
'
// //
w y lic z e n ie p r z e s u n i ę c i a lo k a liz a c ji p o m ię d z y o b iek tem n a d rz ę d n y m
i b ru d n y m k o m p o n en tem
lastDeltaX += parent.getX(); lastDeltaY += parent.getY();
Pusta p rze s trze ń
Pusta p rze strze ń
k o m p o n e n te m , k tó ry n a le ż y o d ry s o w a ć , je s t tera z R e fle c tio n P a n e l
parent = parent.getParent(); — ------- --—
................—
—r —r—.......- - .........— « —------
D o m y ś ln y R e p a in tM a n a g e r
n r . ----------------------------------- ------- — —
■ ■■ ...................... .....................r .-f
}
R e fle c tio n R e p a in tM a n a g e r
Rysunek 11.8. ReflectionRepaintManager rozszerza brudny region o panel zawartości, aby obejmował również odbicie
//
w y s ła n ie ż ą d a n ia p r z e r y s o w a n ia
w
E D T
super.addDirtyRegion(c, x, y, w, h );
W przypadku ReflectionRepaintManager brudny region rozszerza się o odbicie. Dlatego, gdy w Ref! e c ti onPanel wywołana jest metoda pai nt (), obszar obcinania obiektu Graphi cs
W kodzie tym odczytywany jest obiekt nadrzędny „brudnego” komponentu i sprawdzane
będzie również obejmować odbicie, co pozwala na aktualizację tego obszaru.
jest, czy jest on obiektem klasy ReflectionPanel. Jeżeli nie, sprawdzany jest obiekt nadrzęd
Pełny kod źródłowy klasy Ref 1e cti onRepai ntManager jest przedstawiony poniżej: private c la s s ReflectionRepaintManager extends RepaintManager { public void addDirtyRegion(JComponent c , in t x, in t y , in t w, in t h) { Rectangle dirtyRegion = getD irty R egio n (c);
ny nadrzędnego, i tak dalej. Gdy zostanie odnaleziony ReflectionPanel, wysokość brudnego regionu jest tak modyfi kowana, aby obejmowała obszar odbicia odpowiadający obszarowi oryginalnego brudnego regionu. Aktualizowany komponent, nazwany w kodzie c, jest w końcu zastępowany przez ReflectionPanel.
int lastDeltaX = c.getXQ ; int lastDeltaY = c.getYQ;
i* r R o z d z ia ł 1 1 .
Z a r z ą d c a r y s o w a n ia
Na końcu pętli wywoływana jest metoda super.addDirtyRegion() i przekazywany jest ^ niej Ref 1e c ti onPanel oraz rozszerzony brudny region. Metoda z klasy super zajmuje się 2a nas przesłaniem żądania odiysowania w EDT. Uwaga Naprawianie TranslucentPaneł
■ /
/
.zęsc
Na podstawie powyższego przykładu warto spróbować zaimplementować RepaintManager, którynaprawi problemy związane z Trans! ucentPane!. Zarządca ten nie musi rozszerzać brudnego re- 1 gionu, lecz tylko zmieniać komponent do aktualizowania.
Podsumowanie
Animacja
Obiekt RepaintManager pozwala dołączać się do mechanizmu odrysowywania Swing. Może być wykorzystywany do przechwytywania żądań odrysowywania, jak również tworzenia efektów wizualnych, które w inny sposób są trudne do prawidłowego wykonania. Należy jednak pamiętać, że w danym momencie może istnieć tylko jeden Repai ntManager. Należy tworzyć własny Repai ntManager tylko wtedy, gdy jest to konieczne.
i
Wszystko o czasie Animacja jest jedną z najważniejszych koncepcji i technik stosowanych w bogatych inter fejsach użytkownika, która powoduje, że nasze aplikacje są bardziej dynamiczne, ponieważ interfejs płynnie odpowiada na akcje użytkownika. Animacja to bardzo obszerny i różnorod ny temat, który obejmuje takie zagadnienia jak proste kopiowanie obrazu na ekranie, jak również tak złożone, jak najnowsze gry trójwymiarowe i filmy animowane. Dla naszych po trzeb skupimy się na jednym ze znaczeń tej techniki. A n im acja to zdeterminowane czasowo przekształcenie obiektów graficznych pomiędzy różnymi stanami, lokalizacjami, wielkościami i orientacjami. W tej prostej definicji znajdują się dwa ważne wyrażenia: zdeterm in ow an e czasowo oraz przekształcenie. Przekształcenie można łatwo objaśnić. Oznacza to po prostu zmianę sposobu rysowania obiektów. Nauczyliśmy się już w poprzednich rozdziałach, jak można to zrealizować w apli kacji Swing; zmienialiśmy stan grafiki i odpowiednio generowaliśmy obiekty GUI oraz obiekty graficzne. Zdeterm inow ane czasow o jest prawdopodobnie mniej oczywiste, więc wyjaśnimy to zagad nienie na kilku następnych stronach. Podstawowym założeniem jest zdefiniowanie sposobu modyfikacji obiektów w czasie, a następnie ich odpowiednie rysowanie w zdefiniowanych momentach.
at.
m.
284
R o z d z ia ł 1 2 .
P o d s t a w o w e k o n c e p c je
P o d s t a w y a n im a c ji
Podstawowa koncepcje Anim acja bazująca na ram kach
\ja rysunku 12.1 oraz 12.2 widzimy pozycję muchy początkową i końcową, jak również ścież kę. jaką przebyła, aby przenieść się ż pozycji początkowej do końcowej. Na rysunku 12.3 przedstawione są poszczególne obrazy wykonane w czasie wędrówki muchy, które w przy padku ich szybkiego wyświetlenia mogą wystarczająco dokładnie przybliżyć ruch muchy tak, że nasz mózg potraktuje je jako płynne przesunięcie, a nie serię zdjęć muchy znajdującej się w kolejnych lokalizacjach2.
W rzeczywistym świecie, czyli w świecie poza moim komputerem, o którym słyszałem oka zjonałnie jakieś plotki, widzimy anim ację jako ciągłe zmiany zachodzące przed naszymi oczami. M ucha przelatuje obok mnie, trafia ją packa, mucha uderza w ścianę, a następnie
'« li
spada na ziemię1. W przypadku animacji komputerowej, takiej jak w filmach, animacja jest serią nieruchomych obrazów, które nasz mózg łączy razem w płynny ruch. Zwróćmy uwa gę na rysunki 12.1 oraz 12.2.
©
(V Rysunek 12.1. Początek Rysunek 12.3. Poszczególne ramki animacji ruchu muchy Takie bazujące na rysunkach, inaczej ram kach, podejście do animacji działa świetnie w więk szości sytuacji. Jeżeli tylko będziemy pokazywać ramki wystarczająco szybko,- nasz mózg przekształci tę serię na płynny ruch. Istnieją również inne sztuczki, pozwalające na. oszukanie mózgu3, które są przedstawione w rozdziale 13., „Płynne przesunięcia”.
W czasie pisania tej książki nie zostały skrzywdzone żadne zwierzęta w naszym bezpośrednim otoczeniu.
Przynajmniej te, którymi ludzie się przejmują.
Myślałem o zamieszczeniu w tej książce animacji w narożnikach kolejnych kartek; czasami takie animacje były spotykane w czasopismach wydawanych za mojej młodości. Choć byłaby to doskonała demonstracja animacji bazującej na ramkach, to również stanowiłaby świetny sposób na pojawienie się na półkach księ garni wielu egzemplarzy tej książki z pozawijanymi rogami. Zdecydowałem się więc na bardziej nudną, teoretyczną dyskusję. Jako ćwiczenie dla ochotników proponuję wycięcie poszczególnych klatek z rysunku 12.3 i wykonanie animacji na kartkach książki. Proszę tylko wykonać to zadanie dopiero po kupieniu egzemplarza książki. Bez korzystania ze środków chemicznych.
285
T 286
R o z d z ia ł 1 2 .
287
P o d s t a w o w e k o n c e p c je
P o d s t a w y a n im a c ji
Zbyt szybko
Częstotliwość klatek
Przez rysowanie wersji początkowej i końcowej bezpośrednio jedna po drugiej efektywnie Jednym z często używanych terminów, jakie powinniśmy na początku zdefiniować '
pokazujemy użytkownikowi jedynie lokalizację końcową. W Swing, jak pokażemy później,
częstotliwość klatek. Każdy osobny widok animacji jest na2ywany ram ką, a animacja jest s 1 tych ramek. Częstotliwość wyświetlania tych ramek jest oczywiście nazywana częstotliw
Nawet jednak w bibliotekach, w których obie wersje są rysowane na ekranie, dzieje się to
użytkownik zobaczy tylko końcową wersję, a nie początkowy rysunek na współrzędnych (0,0).
ścią ramek. Częstotliwość ta jest określana przez połączenie częstotliwości w ym aganej d0
tak szybko, że będzie można zobaczyć tylko mignięcie obiektu w początkowej lokalizacji,
osiągnięcia płynnego ruchu oraz częstotliwości możliwej do osiągnięcia przy danej wyda' ności systemu i złożoności rysowanych w każdej ramce obiektów.
a następnie obiekt w końcowej lokalizacji. Taki rodzaj anim acji nie jest filmem, a tylko zbiorem mignięć.
Buforowanie Swing
Ruch bazujący na czasie
Z powodu zastosowania modelu renderowania Swing, opisanego w rozdziale 2., „Podsta Najprostszym podejściem do animacji jest kolejne wprowadzanie zmian do sceny i sekw en-
I
wy renderingu w Swing”, użytkownik widzi tylko ostateczny wynik. Użytkownik nie zoba
cyjne rysowanie nowych wersji. Załóżmy, że chcemy animować przesunięcie obrazu od
I
czy nawet śladu początkowego renderowania, ponieważ wszystkie operacje rysowania Swing
lewej strony okna do prawej. Zadanie to można osiągnąć przez rysowanie obiektu po lCWc; a następnie po prawej, tak jak w poniższym fragmencie kodu:
wykonuje w buforze pamięciowym. W wyniku zastosowania w Swing podwójnego buforo wania wszystkie polecenia w metodzie pai ntComponent () są wykonywane w buforze tylnym,
public void paintComponent(Graphics g) { int imgW = img.getWidth( ) ; int imgH = img.getHeightQ; // Rysowanie obrazu w pierwszej lokalizacji g.drawlmage(img, 0, 0, n u li); // Kasowanie pierwszej lokalizacji g .setC o lor(b g C o lor); g .f i l l R e c t ( 0 , 0 , imgW, imgH); // Rysowanie obrazu w końcowej lokalizacji g.drawlmage(img, windowWidth - imgW, 0, n u li); }
a po zakończeniu tej operacji bufor jest kopiowany na ekran. Poprzednio przedstawiony kod narysuje obiekt w pierwszej lokacji, skasuje go, a następnie narysuje końcową wersję. Użytkownik zobaczy więc końcową wersję, a nie pośrednie operacje rysowania i wymazy wania. Nie wystąpią więc mrugające artefakty — nie zostanie również wygenerowana żad na animacja, a tylko otrzymamy obraz w docelowej lokalizacji.
Przesunięcia powinny być synchronizowane w czasie Nic nie steruje tym, jak szybko obiekt przesuwa się od lewej do prawej, poza szybkością działania systemu, na którym jest wykonywany kod. Jeżeli chcem y uzyskać realistyczne animacje, które będą zaakceptowane przez użytkowników, musimy skorzystać z jakiegoś
Z podejściem tym jest związanych kilka problemów.
algorytmu czasowego do sterowania przesunięciem obiektu.
Teleportacja to nie animacja
Sprawdźmy, co możemy zrobić, aby rozwiązać talde problemy.
Przykład ten nie jest faktycznie „animacją”, jeżeli obiekt pojawi się na lokalizacji począt kowej i końcowej. Pożądanym efektem każdej anim acji jest płynne przesuwanie obiektu
Przesunięcie, a nie teleportacja
z jednej lokalizacji do innej, a nie pojawienie się obiektu w końcowej lokalizacji. Pierwszy problem jest dosyć prosty. Wystarczy dodać kroki pośrednie, aby animacja była stopniowa. W ekstremalnym przypadku powinniśmy próbować uzyskać najbardziej płynną
W skazów ka W rzeczywistości spowodowanie, aby aplikacja płynnie anim ow ała grafikę, jest jednym z celów tej książki. Aplikacje z bogatym interfejsem użytkownika odchodzą od tradycyjnego modelu apli kacji, w którym obiekty, elementy GUI, tekst i stan aplikacji natychmiast się zmieniają. W aplikacji pow inny być wykorzystane przesunięcia, a nie nagłe i nieciągłe zmiany.
:
i
animację przez przesuwanie obrazu tylko o jeden piksel, tak jak w poniższym kodzie: public void in t imgW in t imgH fo r (in t
paintComponent(Graphics g) { = img.getWidth( ) ; = im g.getH eight(); i = imgW; i 0) { //
//
//
o b lic z e n ie j p s d la d o d a tn ic h w a rto ś c i d e lta
...f a k t y c z n e o p e r a c j e r e n d e r o w a n i a
} W tym przykładzie wyliczamy dokładną wartość fps dła każdej rysowanej ramki przez po
} return fps; } public void paintComponent(Graphics g) { flo at fps = getFPSO; //
dzielenie 1 sekundy — 1000 milisekund — przez czas, jaki minął od ostatniego wywołania tej metody. Taki sposób pomiaru ma kilka wad, które omówimy poniżej.
Ś r e d n ia w a rto ść f p s w k a ż d ej s e k u n d z ie
i f (delta > 1000) { fps = numFrames / delta * 1000; numFrames = 0; startTime = currentTime; }
fps = 1000.Of / (flo a t)d e lta ; } previousTime = currentTime;
c z a s u ( o ra z n a r z ę d z ia p o m ia r u c z a s u pla t fo r m y )
...fa k t y c z n e o p e r a c j e r e n d e r o w a n i a
} W tej wersji obliczamy wartość fps przez czas około sekundy. Dokładniej, obliczamy fps
Nieprawidłowa wartość dla pierwszej ramki
tylko wtedy, gdy wartość delta, służąca nam do pomiaru czasu pomiędzy momentem bieżą
Ponieważ ustalamy wartość previousTime na podstawie starej wartości currentTime, przy
cym a czasem ostatniego obliczenia wartości fps, będzie większa niż 1000 ms. Dla wartości
pierwszym obliczaniu wartości del ta, previ ousTime ma nieprawidłową wartość, co prowadzi
poprzednich po prostu zwracamy poprzednią wartość fps. Warto zwrócić uwagę, że począt
do uzyskania nieprawidłowego wyniku. W praktyce wystarczy zignorować tę początkową wartość lub zacząć obliczanie fps po pewnym czasie po wyświetleniu pierwszej ramki.
kowa wartość fps jest bezużyteczna, ponieważ ma ona wartość 0, aż minie pierwsza; sekunda pomiaru, więc przed okresem „rozgrzania” nie jest zwracana rzeczywista wartość. To jest tylko prosty przykład. Inne metody pomiaru i obliczenia fps mogą w lepszy sposób
Duża zmienność
uwzględniać początkowe wartości, obliczać częstotliwość w dłuższych i krótszych okresach
Czas pomiędzy ramkami może być różny, na przykład 15 ms dla jednej ramki, a następnie
lub uwzględniać różne stany aplikacji. Jednak przykład ten miał za zadanie pokazać pod
60 ms dla następnej. Zamiast widzieć, jak wyliczona częstotliwość ramek „dziko skacze”
stawy wykonania takiej operacji w naszej aplikacji przy wykorzystaniu prostego stopera
pomiędzy różnymi wartościami, lepiej jest śledzić wartość fps przez dłuższy czas, aby wy
System.currentTimeMi11is ().
gładzić wyniki i wyświetlać zmierzoną średnią częstotliwość ramek.
System.nanoTime() Rozdzielczość
Metoda System. nanoTime() została wprowadzona w J2SE 5.0 jako odpowiedź na zapotrze
Jednym z czynników, które prowadzą do zmienności czasów między ramkami, jest roz
bowanie na stoper o wysokiej rozdzielczości. Rozdzielczość ta zostanie przedstawiona póź
dzielczość mechanizmu stopera; zagadnienie to jest przedstawione w punkcie „Rozdziel
niej, ale trzeba pamiętać, że metoda nanoTi me () daje lepszą rozdzielczość w dwóch aspek
czość stopera”, w dalszej części rozdziału. I w tym przypadku uzyskamy lepsze wyniki, ob
tach — oferuje wartości czasu w nanosekundach, czyli miliardowych częściach sekundy;
liczając średnią częstotliwość ramek i eliminując zmienność między ramkami.
czas może być również mierzony przy użyciu stoperów systemu operacyjnego o wysokiej rozdzielczości, innych niż te, które są używane w metodzie currentTimeMi 11 i s ().
Spójrzmy na kolejny przykład, w którym jest rozwiązany ten problem: private long startTime = 0; private int numFrames = 0; private flo at fps = O.Of; private flo at getFPSO { ++numFrames; i f (startTime == 0) { startTime = System.currentTimeMi11i s ( ) ;
Zauważyłem, że rzadko potrzebowałem czasów krótszych niż milisekundy. Jeżeli jednak napotkamy problemy z rozdzielczością, to poprawiona rozdzielczość nanoTi me () jest atrak cyjną alternatywą dla currentTi meMi 11 i s (). Na przykład w niektórych systemach metoda currentTimeMi 11 i s () nie może zmierzyć dokładnie czasów krótszych niż 16 ms, natomiast nanoTi me () może mierzyć dokładnie czas poniżej zakresu milisekund. Dzięld tej rozdziel czości zastosowanie metody nanoTi me () jest niezbędne w sytuacjach, w których musimy
296
;
R o z d z i a ł u . P o d s t a w y a n im a c ji
M ie r z e n ie
c z a s u ( o ra z n a r z ę d z ia p o m ia r u c z a s u p l a t f o r m y )
wiedzieć dokładnie, ile czasu upłynęło, a mniej dokładna metoda currentTimeMillis() jest
W środowisku Java funkcja budzenia jest obsługiwana przez metodę Thread .sleep(ms),
niewystarczająca. W praktyce można używać tej funkcji identycznie jak currentTimeMil 1i s() korygując wartości do potrzebnych przyrostów czasu. W poprzednim przykładzie oprócz
szać wyjątek, jeżeli system spowoduje przerwanie wątku w czasie jego cyklu uśpienia, więc
zmiany nazwy metody musimy pomnożyć wartość delta przez 1 000 000 000 zamiast 1000 aby uzyskać prawidłową wartość fps:
.
i
pełna procedura wywołania sl eep ()•jest następująca: try { //
i f (startTime == 0) { startTime = System.nanoTime(); } ełse { long currentTime = System.nanoTime(); long delta = (currentTime - startTime); i f (delta > 1000) { fps = numFrames / delta * 1000000000 ; numFrames = 0; startTime = currentTime; }
gdzie ms jest czasem w milisekundach, na który chcemy uśpić wątek. Metoda ta może zgła
s le e p u ś p ie n ie n a 1 0 0 m ilis e k u n d
Thread.sleep(100); } catch (InterruptedException e) { //
o d p o w ie d n ie o b s ł u ż e n i e w y ją tk u
} W róćmy teraz do naszego poprzedniego przykładu animacji i wstawmy faktyczną funkcję usypiania w miejsce, gdzie „powinien upłynąć pewien czas”. 'I B S . .¡¡¡j
„C l y m ogę zamówić budzenie?" Innym często wykorzystywanym narzędziem związanym z czasem jest budzenie, podobnie jak w hotelu6. Mechanizm budzenia jest dokładnie tym, czego potrzebujemy w naszym, prostym przykładzie animacji w miejscu, gdzie program musi „odczekać określony czas", bez „kręcenia się” w ciasnej pętli. W takiej sytuacji aplikacja może przekazać sterowanie do systemu operacyjnego z zastrzeżeniem, że zostanie ona „obudzona” w określonym momencie. Proces ten jest nazywany usypianiem , ponieważ wątek, który żąda operacji budzenia, jest „usypiany” przez system. Większość bibliotek GUI i systemowych ma podobny mechanizm usypiania wątku, uruchamiany przy użyciu funkcji o takiej nazwie, jak sle e p (). Zazwyczaj funkcja sle e p () jest wywoływana z liczbą oznaczającą czas, przez jak i wątek pozostanie
int imgX„ imgY; int prevImgX, prevImgY; ‘ public void paint(Graphics g) { g.setColor(bgColor); g .fillR e ct(p re vX , prevY, img.getWidthQ,img.getHeight()); g.drawlmage(img, imgX, imgY, n u ll); prevX = imgX; prevY = imgY; } public void someMethodQ { imgX = prevX = imgY = prevY = 0; for (in t i = 0; i CYCLE_TIME) { cycleStart = currentTime; } flo at fraction = ( f l oat)total Ti me / CYCLE_TIME; fraction = Math.min(1.0f, fractio n ); fraction = 1 - Math.abs(l - (2 * fra c tio n )); anim ate(fraction); }
Renderowanie . Na koniec zajmiemy się najważniejszą częścią aplikacji — renderowaniem grafiki w czasie animacji. W metodzie paintComponent() wykonywane są trzy główne zadania: czyszczenie tła, rysowanie animacji przyciemniania oraz rysowanie animacji przesuwania.
Czyszczenie tła Operacja ta jest prosta; czyścimy zawartość kom ponentu za pomocą białego koloru: g .se tC o lo r(C o lo r.WHITE); g .f i l l R e c t ( 0 , 0, getW idthQ, g e tH e ig h t());
Rysowanie anim acji przyciem niania W tym kroku korzystamy z bieżącej wartości zmiennej opacity, która została obliczona w metodzie animateQ, do utworzenia nowego obiektu AlphaComposite i ustawienia go w obiekcie GraphicsŻD. Następnie renderujemy nasz istniejący obraz przy wykorzystaniu obiektu GraphicsŻD.
355
R o z d z ia ł 13. P ł y n n e
p r z esu n ięc ia
SMOOTHMOVES — PROGRAM DEMONSTRACYJNY
Graphics2D gFade = (G raphics2D )g.create( ) ; gFade. setComposi te(AlphaComposi t e .SrcOver. derive(opaci t y ) ) ; gFade.drawlmage(image, fadeX, fadeY, n u li); gF ad e.d isp ose();
image = gc.createCompatibleImage(imageW, imageH, Transparency.TRANSLUCENT); Graphics2D glmg = (Graphics2D)im age.getGraphics(); i f (uselmage) { try { URL url = getClass().getResource("duke.gif"); Image origin al Image = ImagelO.read(u r l) ; gImg.drawImage(originalImage, 0, 0, imageW, imageH, n u li) ; } catch (Exception e) { System .out.println("Problem z ładowaniem pliku obrazu: " + e ) ;
W arto zwrócić uwagę, że tworzymy tu nowy obiekt Graphi cs2D przez klonowanie na pod stawie obiektu Graphi cs, a na koniec usuwamy go. Pozwala nam to na ustawianie pizozir). czystości w obiekcie Graphi cs bez konieczności jej resetowania po zakończeniu, więc renderowanie pozostałych obiektów przy użyciu oryginalnego obiektu Graphi cs nie jest zakłócane przez efekty uboczne tej zmiany. Zmienna opaci ty jest ustawiana w czasie opisanego wcze śniej wywołania anim ate(). Zmienne instancyjne fadeX oraz fadeY są wykor/y-L-.wanc do
} } glm g.disposeQ ;
określenia miejsca narysowania przyciemnianego obrazu.
Rysow anie anim acji przesuwania Ten krok jest bardzo prosty: g.drawlmage(image, moveX, moveY, n u li); Po prostu kopiujemy obraz w odpowiednie miejsce, definiowane przez parametry moveX oraz moveY. moveY jest stałą. Przesuwamy obiekt tylko w kierunku X. Jak wcześniej wspo mnieliśmy, wartość moveX jest ustawiana w czasie wywołania anim ate().
Warto zwrócić uwagę, że po prostu podstawiamy nową zawartość do obrazu zawierające go wcześniej czarny prostokąt. W czasie renderowania rysujemy w oknie ten sam obraz co poprzednio, ale tym razem pojawia się rysunek Księcia zamiast czarnego prostokąta.
C (kolor) Opcja ta przełącza pomiędzy domyślnym czarnym kolorem a jasnoszarym . Powinniśmy zauważyć, że animacja przesuwania wygląda na znacznie bardziej płynną przez zmniejsze nie kontrastu lub inaczej odległości kolorów pomiędzy kolorem tła i kolorem obiektu. Kod
Opcje renderowania Przedstawione tu zadania wystarczą do realizacji domyślnego działania aplikacji. Tworzony jest w nich obraz, konfigurowany jest stoper oraz w kółko rysowane są obie animacje. Jed nak ten program demonstracyjny ma większe możliwości. Dostępne są opcje uruchamiane z klawiatury, których można używać w czasie działania aplikacji i które pozwalają na wy próbowanie różnych podejść do ograniczania merównomierności i natychmiastowo zoba czenie wyników. Przedstawiliśmy te opcje przy omawianiu problemów i ich rozwiązań, ale
zmieniający kolor obiektu znajduje się w metodzie createAnimati onlmage (): Color graphicsColor; i f (alterC o lor) { graphicsColor = Color.LIGHT_GRAY; } e lse { graphicsColor = C o lo r.BLACK; } glm g.setC olor(graphicsC olor); g Im g .fillR e c t(0 , 0, imageW, imageH);
poniżej znajduje się spójna lista opcji programu.
B (rozmycie) 1 (obraz) Opcja ta włącza nasz prosty efekt rozmycia ruchu, który powoduje, że kod rysujący dodaje Opcja ta pozwala na przełączenie animacji pomiędzy wypełnionym prostokątem a obrazom.
ślad z przezroczystych obrazów-duchów w ostatnich lokacjach obiektu. W arto zauważyć,
Użycie jej pozwala uzyskać nieregularny kształt obiektu, co powoduje, że trudniej zobaczyć
że artefakty na tylnej krawędzi obiektu znacznie się zmniejszyły. Kod tworzący ten efekt
niektóre artefakty, widoczne w przypadku pełnego prostokąta. Kod tworzący ten obraz zna
znajduje się w metodzie pai ntComponent (). Na początku znajduje się kod tworzący tablicę
jduje się w metodzie createAnimati on Image ():
wartości rozmycia:
357
R o z d z ia ł 13.
Płyn n e
S m o o th M
p r z esu n ięc ia
i f (motionBlur) { i f (prevMoveX == nuli) { // tablica lokalizacji rozmycia nie jest utworzona; tworzymy j ą prevMoveX = new in t[b lu rS iz e ]; prevMoveY = new in t[b lu rS iz e ]; trailOpaci ty = new flo a t[b lu rS iz e ]; flo at incrementalFactor = .2f / (blurSize + 1); for (in t i = 0; i < blurSize; ++i) { // wartość domyślna, służy ja k o znacznik blokady renderowania ¡ I do momentu zmiany wartości prevMoveX[i] = -1; prevMoveY[i] = -1; // zmiana przezroczystości o liczbą obrazów-duchów; // im dalej o d bieżącego obrazu, // tym bardziej jest przezroczysty tra i!0 p a c ity [i] = (.2 f - incrementalFactor) i * incrementalFactor; } }
oves
—
pr o g r a m d e m o n s t r a c y jn y
Kolejny raz warto przypomnieć, że istnieje wiele sposobów na uzyskanie rozmycia ruchu, z których część jest bardziej złożona, czasochłonna I bardziej prawidłowa fizycznie niż za stosowane tu proste podejście. Mieliśmy zamiar skorzystać z rozmycia ruchu w celu pokaza nia wpływu tego efektu na płynność aplikacji i dlatego wybraliśmy to proste rozwiązanie. Można również eksperymentować z bardziej złożonymi metodami uzyskania tego efektu.
Od 1 do 9 Klawisze numeryczne pozwalają na zmianę długości rozmycia ruchu, od jednego obrazuducha do dziewięciu. Im więcej obrazów, tym bardziej stopniowe przejście od koloru obiektu do koloru tła i mniej widoczne artefakty na tylnej krawędzi. Jednak zbyt dużo duchów po woduje powstanie zbyt długiego i nierealistycznego rozmycia obiektu. Kod dla tego efektu jest przedstawiony wcześniej, w punkcie „B (rozm ycie)”. N aciśnięcia klawiszy zmieniają wartość zmiennej blurSize.
A (wygładzanie) Opcja ta pozwala na włączenie wygładzania obrazu prostokąta. Brzegi prostokąta są ryso
Następnie rysujemy kolejne obrazy-duchy: Graphics2D gTrail = (Graphics2D)g.create(); for (in t i = 0; i < blurSize; ++1) { i f (prevMoveX[i] >= 0) { // Renderowanie każdego obrazu rozmycia // przy użyciu odpowiedniego poziomu przezroczystości gTrail.setComposite(AlphaComposite.SrcOver. d e r iv e (tra ilO p a c ity [i])); gTrail.drawlmage(image, prevMoveX[i], prevMoveY[i], n u li); } } g Trail.di spose(); Położenie duchów jest aktualizowane na końcu metody pai ntComponent (): i f (motionBlur) ( // przesunięcie pozycji duchów w celu dodania bieżącej pozycji I I i usunięcia najstarszej for (in t i = blurSize - 1; i > 0; --i) { prevMoveX [i] = prevMoveX[i - 1]; prevMoveY[i] = prevMoveY[i - 1]; }
prevMoveX[0] = moveX; prevMoveY[0] = moveY; 1
wane przy użyciu przezroczystości zapewniającej stopniowe rozjaśnianie, aż do pełnej prze zroczystości. Podobnie jak przedstawiony wcześniej efekt rozmycia, wygładzanie pozwala uzyskać bardziej płynne przejścia pomiędzy kolorem obiektu a kolorem tła. Jednak efekt ten powoduje rozmywanie wszystkich brzegów obiektu, a nie tylko tylnej krawędzi, jak . w przypadku efektu rozmycia ruchu: Zastosowane jest tu bardzo proste podejście. Rysujemy coraz bardziej rozjaśnione obwódki prostokąta, jak jest to przedstawione w poniższym ko dzie z metody createAnimationImage(): i f (useAA) { glmg. setComposi te(Al phaComposi te .S r c ); int red = graphicsColor.getRed(); int green = graphicsColor.getGreen(); int blue = graphicsColor.getBlue(); glmg.setColor(new Color(red, green, blue, 50)); gImg.drawRect(0, 0, imageW - 1, imageH - 1); glmg.setColor(new Color(red, green, blue, 100)); gImg.drawRect(l, 1, imageW - 3, imageH - 3); gImg.setColor(new Color(red, green, blue, 150)); gImg.drawRect(2, 2, imageW - 5, imageH - 5); gImg.setColor(new Color(red, green, blue, 200)); gImg.drawRect(3, 3, imageW - 7, imageH - 7); gImg.setColor(new Color(red, green, blue, 225)); g!mg.drawRect(4, 4, imageW - 9, imageH - 9);
R o z d z ia ł 13. P ł y n n e
p r z esu n ięc ia
Strzałki w górę i w dół
14
Animacja jest uruchamiana przy dosyć niskiej częstotliwości ramek, ale może ona z0stai zwiększona lub zmniejszona przez naciśnięcie klawiszy strzałek w górę lub w dół. Każde na, ciśnięcie zwiększa lub zmniejsza rozdzielczość o określoną liczbę milisekund, do minimum 0 i maksimum 500.
Biblioteka Timing Framework.
L (liniowość) O pcja ta zmienia tryb interpolacji animacji. Domyślnie animacja przesuwa się w sposób liniowy. Klawisz L pozwala na użycie w anim acji funkcji nieliniowej sinus. Funkcja sinus umożliwia uzyskanie efektu „odbijania”. Wajrto zauważyć, że takie nieliniowe poruszanie się utrudnia wykrycie nierównomierności pojedynczych ramek. Dla oka znacznie trudniej
Podstawy
jest przewidzieć dokładnie, gdzie powinien ‘Być obiekt w przypadku zastosowania nieli niowego ruchu niż w przypadku użycia ruchu liniowego.
Podsumowanie Na początku pracy z animacją zauważyliśmy kilka artefaktów i chcieliśmy, aby animacja działała szybciej, lepiej, płynniej i fajniej. Porady zamieszczone w tym rozdziale pomagają w identyfikowaniu i rozwiązywaniu problemów zauważonych w takich animacjach. Klu czem do budowy bogatego interfejsu użytkownika nie jest wykonanie ruchomego GUI, ale uczynienie go bardziej dynamicznym i spowodowanie, że użytkownik uwierzy w realizm i płynność aplikacji. Zapewnienie płynności i realizmu jest ważnym aspektem tworzenia takich animacji.
Wstęp Gdy zaczynamy pracować nad animacjami w Swing, szybko zdajemy sobie sprawę z dwóch cech wbudowanych stoperów: o ich prostota powoduje, że możliwe jest zbudowanie dowolnej animacji; ® ich prostota powoduje, że możliwe zbudowanie jakiejkolwiek animacji jest niezwykle trudne1.
1 Stopery ilustrują klasyczny rozdźwięk pomiędzy prostotą i siłą. Oczywiście, starożytni Egipcjanie mogli zbudować piramidy i Sfinksa ze sterty kamieni, ale wymagało to olbrzymiego nakładu pracy. Anglicy chyba nieco praktyczniej podeszli do problemu przy konstruowaniu Stonehenge i podobnych monumentów, gdzie końcowy produkt był po prostu stertą dużych kamieni. Ostateczny rezultat nie jest tale efektowny, ale znacznie prostszy do osiągnięcia niż piramidy. Takie samo podejście jest wykorzystywane przy więk szości aplikacji z „bogatym interfejsem” — animacje są albo całkowicie pomijane, albo są bardzo proste, ponieważ proces tworzenia złożonych animacji jest trudny i czasochłonny, a w firmach programistycznych brakuje taniej siły roboczej, która była powszechnie dostępna w starożytnym Egipcie.
R o z d z ia ł 1 4 .
B i b l io t e k a T i m i n g F r a m e w o r k . P o d s t a w y
W *
P o d s t a w o w e -k o n c e p c j e ..
Oznacza to, że przy wykorzystaniu mechanizmu wywołań zwrotnych uwarunkowanych czasowo, takich jak ja vax. swing. Ti mer, można wykonać dowolne zadanie zależne od czasu takie jak zmiana charakterystyki komponentu Swing w czasie, i przez to animować GUI
Dodatkowe funkcje są umieszczone w pakietach trig g e rs oraz in terp o latio n . Wyzwala-
Jednak szczegóły implementacji takiej anim acji są niezwykłe złożone, więc większość pro
w paldecie i nterpol at i on pozwalają animować właściwości obiektów Java oraz definiować
gramistów pomija tę możliwość i korzysta ze statycznych komponentów domyślnie udostęp nianych przez biblioteki GUI.
złożone modele interpolacji tych właściwości pomiędzy różnymi wartościami. Wyzwalacze
363
cze (trig g ers) pozwalają skojarzyć anim ację z dowolnymi zdarzeniami i zautomatyzować uruchamianie animacji na podstawie tych zdarzeń. Metody ustawiania wartości właściwości
i metody ustawiania właściwości są opisane w rozdziale 15., „Biblioteka Timing Framework. Funkcje zaawansowane”.
Problem ten staje się ewidentny, gdy zaczynamy eksperymentować z animacją w Swing i Java 2D. Osobiście rozpocząłem opracowanie kodu bazowego zapewniającego podsta wowe funkcje wymagane we wszystkich anim acjach. Stało się to inspiracją dla biblioteki Tim ing Framework.
BIBLIOTEKA WSIECI
Podstawowe koncepcje
Uwaga
W centralnych klasach wykorzystywanych przez Tim ing Framework zastosowane zostały
Biblioteka Timing Framework jest rozwijana w projekcie, którego strona domowa znajduje się pod adresem http://timingframework.dev.java.net. Wybraliśmy jedną z wersji tej biblioteki i umie ściliśmy ją na witrynie W W W książki, dzięki czemu wszystkie teksty w książce i kody aplikacu demonstracyjnych odpowiadają dostępnej tam wersji biblioteki. Jeżeli więc chcemy użyć tej samej
następujące koncepcje i właściwości: ® An im ator — klasa ta zawiera większość funkcji przedstawionych w tym rozdziale, ale warto przedstawić je osobno, dzięki czemu można pokazać, jak klasa Animator oraz definiowana przez nią animacja jest tworzona i uruchamiana.
wersji, która jest przedstawiona w książce, należy wykorzystać kod zamieszczony na witrynie WWW książki. Jeżeli chcemy skorzystać z najnowszej i najlepszej wersji biblioteki lub chcemy spraw dzić, jak rozwija się ta biblioteka, należy skorzystać z witryny'projektu na serwerze java.ncl.
® W yw ołania zw rotne — aplikacja m usi mieć możliwość powiadamiania o zdarzeniach w czasie animacji. W ten sposób aplikacja może wykonywać akcje w zależności od stanu animacji. Powiadamianie o zdarzeniach jest realizowane
Biblioteka Timing Framework jest zbiorem klas użytkowych, które zapewniają efekt vwny
przez wywołania zwrotne, które aplikacja może zaimplementować w kodzie.
system animacji, obsługujący wiele szczegółów, które w przeciwnym razie trzeba zaimple
M echanizm ten jest podobny do tego, który przedstawiliśmy przy opisie
mentować w aplikacji. Zadaniem biblioteki jest umożliwienie tworzenia zaawansowanych
wbudowanych stoperów Java, ale Timing Framework posiada więcej wywołań
animacji w Swing bez konieczności zajmowania się szczegółami implementacji na niskim
zwrotnych z większą ilością inform acji pozwalających na większą elastyczność
poziomie.
naszych animacji. Motywacja do utworzenia tych wszystkich funkcji biblioteki Timing Framework była dwojaka. ® Obsługa często w ykonyw anych z ad ań — większość kodu, jaki napiszemy do animowania grafiki i GUI, jest niezbędna w niemal wszystkich animacjach. Na przykład większość animacji bazujących na czasie musi określić, jaka część animacji została wykonana w danym momencie, więc dlaczego nie uprościć sobie życia przez automatyczne obliczenie tej części? ® Proste A P I — dając więcej możliwości aplikacji, nie chcemy tworzyć API, które jest zbyt złożone. Powinno być ono tak proste w użyciu, jak jest to tylko możliwe. Biblioteka ta ma kilka osobnych poziomów funkcji. Podstawą biblioteki jest pakiet timing,
'
® Czas trw an ia — wartość ta pozwala na zdefiniowanie czasu trwania animacji. Animacja zatrzymuje się automatycznie, gdy minie jej czas trwania. Można również zdefiniować, że animacja będzie działała bez przerwy. © P ow tarzan ie — niektóre animacje mają być wykonane raz, a następnie zakończyć się. Inne mają działać bez przerwy. Jeszcze inne mogą działać przez określony czas, ą następnie być powtarzane. ® R ozdzielczość — rozdzielczość animacji steruje częstotliwością klatek animacji. Koncepcja ta została przedstawiona w rozdziale 12., „Podstawy anim acji”. o O peracje startow e — animacja może uruchamiać się inaczej niż w standardowy
zawierający najważniejsze elementy używane przez wszystkie inne części. Ta grupa klas
sposób i zaczynając się od poc?l'ątku. Może zamiast tego. działać wstecz lub zaczynać
zapewnia odpowiednik dla wbudowanych obiektów Ti mer, ale o znacznie większym zakresie
się od innego punktu niż początkowy. M ożna również przed uruchomieniem
funkcji. W tym rozdziale został opisany ten zakres funkcji.
odczekać pewien czas.
S
WWW
364
R o z d z ia ł 14.
P o d staw o w e
B ib l io t e k a T im in g F r a m e w o r k . P o d sta w y
• O peracje koń cow e — domyślnie animacja zachowuje końcową wartość po zatrzymaniu. Można również wybrać uruchomienie animacji od początku. ® In terpolacja — najprostszym rodzajem interpolacji jest interpolacja liniowa,
k o n c ep c je
An imator(int duration, double repeatCount, Ani mator.RepeatBehavi or repeatBehavi or, TimingTarget target)
Ostatni wariant ma te same co poprzednio parametry — czas trwania oraz obiekt
która została przedstawiona we wcześniejszych rozdziałach. Istnieją również inne
Ti mi ngTarget, a dodatkowo dwa inne parametry pozwalające na sterowanie powtarza
rodzaje interpolacji, które możemy zastosować w celu uzyskania nieliniowego działania animacji.
niem animacji, co zostanie przedstawione w punkcie „Powtarzanie”.
Przebieg s te r o w a n ia
A nim ator
Dostępnych jest kilka metod, które sterują działaniem i zatrzymywaniem animacji. Trzeba pamiętać, że animacja może zatrzymywać się automatycznie, jak jest to opisane w punkcie
Klasa Animator jest podstawową klasą biblioteki. Użytkownicy biblioteki Timing
Fram ew ork
tworzą obiekty Animator z danymi na temat animacji, którą chcemy uruchomić. Właści wości definiujące animację są ustawiane poprzez kombinację konstruktorów pozwalających na ustawienie najczęściej używanych właściwości, jak również innych metod klasy. Animacje są uruchamiane i zatrzymywane przez wywołanie metod z tej klasy. Klasa ta jest również odpowiedzialna za generowanie zdarzeń animacji w czasie jej pracy, co zostanie wione w kolejnym punkcie, „Wywołania zwrotne”.
przedsta
Tworzenie Obiekty Animator są tworzone za pomocą jednego z następujących konstruktorów:
„Czas trwania”. Jednak animacje mogą być również zatrzymywane programowo za pomocą niektórych opisanych poniżej metod klasy Animator. void start()
Metoda ta uruchamia animację, co powoduje wywołanie metod wywołania zwrotnego TimingTarget begi n () oraz tim ingEvent(), jak jest to opisane w punkcie „Wywołania zwrotne”. void stop()
Metoda ta zatrzymuje animację, co powoduje wywołanie metody end() z TimingTarget, powiadamiającej wszystkie obiekty docelowe o zakończeniu animacji.
Animator(int duration)
Metoda ta ma tylko jeden parametr, opisany nieco dalej, pozwalający na ustawienie czasu działania animacji. Należy zwrócić uwagę, że konstruktor ten nie posiada parame
void cancel()
Metoda ta działa podobnie jak sto p (), poza tym że nie wywołuje metody Ti mi ng
tru TimingTarget. Wywołujący zwykle dodają jeden lub więcej obiektów Ti mi ngTarget
Target. end () w żadnym obiekcie docelowym. To tak, jakby wyciągnąć wtyczkę z kon
za pomocą metody addTarget (), ponieważ bez nich działający obiekt Ani mator nie będzie generował zdarzeń2.
taktu, zamiast normalnie wyłączyć urządzenie.
Animator(int duration, TimingTarget target)
Ten wariant konstruktora, który jest najczęściej wykorzystywany, posiada parametr cza su trwania oraz obiekt TimingTarget. Obiekt TimingTarget, przedstawiony w punkcie „Wywołania zwrotne”, zawiera metody, które będą wywoływane przez zdarzenia anim acji w czasie jej działania.
void pause()
Metoda ta powoduje pauzę w działaniu animacji, zatrzymując animację w jej bieżącym stanie do mom entu wywołania metody resume(). void resume()
Metoda ta pozwala na wznowienie działania animacji wcześniej zatrzymanej pauzą. Animacja wznowi działanie od stanu, w którym wcześniej została zatrzymana, tak jakby pomiędzy wywołaniem pause() i resume() nie upłynął czas. Metoda ta nie daje żadnego efektu, jeżeli animacja nie została wstrzymana.
2 Jest, to w animacji odpowiednik znanego pytania filozoficznego: „Jeżeli w lesie przewróci się drzewo i nikogo nie będzie w pobliżu, aby je usłyszeć, to czy wytworzyło ono jakiś dźwięk?”. To samo pytanie w odniesieniu do klasy Animator może brzmieć następująco: „Jeżeli działa Animator i nie ma obiektu TimingTarget, aby odbierać zdarzenia, to czy cokolwiek się dzieje?”. Chyba nigdy się nie dowiemy.
boolean isRunningO
Metoda ta pozwala sprawdzić, czy animacja jest uruchomiona.
365
R o z d z ia ł 1 4 .
P o d s t a w o w e k o n c e p c je
B ib l i o t e k a T i m i n g F r a m e w o r k . P o d s t a w y
może być również wykorzystywana jako mechanizm łączący sekwencje animacji. Na
Sterowanie działaniem animacji
przykład obiekt docelowy może użyć wywołania end() do zasygnalizowania uruchomienia innej, zależnej animacji. Trzeba jednak wiedzieć, że wyzwalacze zapewniają jeszcze
W arto wspomnieć, że większość parametrów sterujących animacją, takich jak czas tr\vanj czy parametry powtarzania, działa tylko w przypadku zatrzymanej animacji. Gdy animac-a
prostszy mechanizm realizacji takiego działania, co zostanie opisane w rozdziale 15.
działa, nie jest jasne, jak powinna być interpretowana zmiana tych parametrów. Z tego po 1 wodu większość metod ldas Animator, zmieniających te parametry, generuje wyjątek, jeżeli1 są wywołane w czasie działania animacji.
void repeat()
Metoda ta jest wywoływana w czasie powtarzania animacji, za każdym razem, gdy animacja rozpoczyna kolejne powtórzenie. A nim acje powtarzające są przedstawione w dalszej części rozdziału.
W yw ołan ia zwrotne
void timingEvent(f1oat fraction)
Tim in gTarget
M etoda ta je s t najważniejszym elem entem interfejsu, a właściwie ona stanowi rdzeń biblioteki3. Metoda t i mi ngEvent () zwraca obiektowi docelowemu ułamek od 0 do 1 czasu
Animacje korzystające z biblioteki Tim ing Framework działają dzięki wywołaniom zwrot
trwania anim acji. O biekt docelowy może użyć tych inform acji do zmiany właściwo
nym generowanym przez obiekty Animator w co najmniej jednej implementacji Ti mi ngTarget
ści, które należy modyfikować w czasie animacji oraz planowania odświeżania w razie
Obiekt Timi ngTarget ma za zadanie odbierać zdarzenia stoperów z obiektu Animator. Obiekt
potrzeby.
Ti mi ngTarget służy jako łącznik pomiędzy animacją działającą w klasie Animator i animacją widoczną dla użytkownika. Wywołania zwrotne w TimingTarget są uzupełniane o infor
W artość ułamka jest bezpośrednio związana z właściwością duration. Jeżeli obiekt
macje dotyczące bieżącego stanu animacji i mogą zmieniać stan obiektów, obliczać nowe wartości animacji lub wykonywać inne operacje odpowiednie w tej sytuacji.
Ani mator ma ustawiony czas trwania równy 2 sekundy, to anim acja generująca,t i mi ngEvent() sekundę po uruchomieniu spowoduje wywołanie metody timingEventQ z war tością ułamka równą 0 . 54.
Gdy konfigurujemy obiekt Animator przy użyciu konstruktora ldasy Animator lub metody
Wartość tego ułamka jest bardzo użyteczna. Jeżeli chcemy animować pewną zmienną
addTarget(), przekazujemy mu jeden lub więcej obiektów TimingTarget. W czasie działania
w sposób liniowy pomiędzy wartością początkową a końcową, trzeba wiedzieć, jaka część
animacji obiekt Animator wywołuje metody z każdego obiektu Timi ngTarget.
czasu animacji upłynęła. Jeżeli animacja jest w połowie działania, można ustawić Zmienną ,,
Interfejs T i mi ngTa rget ma cztery różne metody zdarzeń do zaimplementowania: public in te rfa c e TimingTarget { publi c void b e g in f); public void end( ) ; public void re p e a tf); public void tim ingE ventffloat fr a c tio n );
na połowę wartości pomiędzy wartością początkową i końcową. Część parametrów obiektu Animator, takich jak kierunek początkowy oraz działanie odwrot ne, pozwala na odwrotne działanie animacji. Jeżeli zostanie, uruchomiona taka praca, warto ści ułamka otrzymywanego w timi ngEvent () również są zmieniane w odwrotnej kolejności.
¡ Oznacza to, że wartość ułamka reprezentuj e ułamek czasu trwania animacji, od początku do końca. Animacja działająca odwrotnie jest uruchamiana, w punkcie początkowym i jest
}
. wykonywana w tył. Animacja rozpoczynająca się w punkcie końcowym i działająca w tył
void begin()
będzie otrzymywała wartości od 1 do 0.
,,
. ,
Metoda ta jest wywoływana przez obiekt Animator w momencie uruchomienia animacji, Pozwala obiektowi docelowemu na wykonanie niezbędnych operacji konfiguracyjnych przed uruchomieniem animacji. void end()
Metoda ta jest wywoływana w momencie zakończenia animacji — albo z powodu jej
3 Faktycznie metoda ta była inspiracją do powstania całej bibłioteld. Miałem dosyć ponownego kodowania tegó samego algorytmu „jaka część animacji została wykonana?” w kolejnej aplikacji, więc lepiej było napisać przeznaczony do tego mechanizm — taki, który zwracał m i ułamek czasu działania, zamiast obliczać go kolejny raz przez sprawdzanie czasu systemowego i porównywanie z czasem rozpoczęcia. Choć można tego nie zauważyć, to jednak cała biblioteka wyrosła z tej jednej małej metody.
naturalnego zakończenia po upływie czasu działania i zadeklarowanej liczby
p o w ió r/ e ń ,
\ależy pamiętać, że część niedomyślnych właściwości ldasy Animator, na przykład nieliniowy Interpolator
albo z powodu wywołania metody stop () w obiekcie Animator. Metoda ta
p o z w a la
na
lub;niezerowy ułamek startowy, będzie zmieniona w tym prostym przykładzie. Przedstawimy te właściwości
wykonanie niezbędnych operacji czyszczenia przez obiekt docelowy. M etoda end()
później.
R o z d z ia ł 14.
368
P o d sta w o w e
B ib l io t e k a T im in g F r a m e w o r k . P o d sta w y
Tim in g T arg etA d ap ter
k o n c ep c je
369
wykorzystywana. Zwykle przedstawiamy animację, korzystając z tego ułamka zamiast całego czasu, ponieważ w taki sposób Animator śledzi i raportuje czas dla obiektów docelowych,
Klasa TimingTargetAdapter jest prostą implementacją TimingTarget, zawierającą pUsle me
jak również dlatego, że jest to bardziej użyteczne dla użytkowników obiektu Animator.
tody tego interfejsu. Klasa ta jest podstawą dla klas potomnych, które powinny otrzymyw^ tylko specyficzne zdarzenia Animator, i gdy nie chcemy implementować wszystkich metod TimingTarget, aby skorzystać tylko z jednej lub dwóch, które nas naprawdę interesują
powtarzanie Często jest stosowane powtarzanie animacji. Powtórzenia mogą przyjmować formę wielo
Czas trwania
krotnego wykonywania tej samej animacji, podobnie jak nieskończony pasek postępu, w któ rym status przesuwa się od lewej do prawej. Powtarzane animacje mogą być również stale
Opis metody timingEvent() jest ściśle związany z właściwością duration, ponieważ ułamek
odwracane, tale jak w przypadku pulsującego przycisku z efektem podświetlenia, które stale
czasu animacji jest obliczany na podstawie minionego czasu oraz całkowitego czasu ani
rozjaśnia się do pełnej jasności, a następnie przyciemnia do pewnego domyślnego stanu.
macji. Czas trwania jest definiowany w konstruktorze klasy Animator, jak wcześniej poka
Zamiast tworzyć osobne animacje dla każdego powtórzenia lub tworzyć jedną dużą ani
zywaliśmy, lub za pomocą następującej metody:
mację obsługującą wszystkie powtórzenia jako szczegóły implementacji, biblioteka zapew
setD u ration fin t duration) Zarówno metoda setDurationf), jak i konstruktor Animator powodują ustawienie czasu trwa nia animacji wyrażonego w milisekundach. Na przykład można ustawić animację o czasie działania równym 2 sekundom za pomocą konstruktora: Animator myAnimation = new Animator(2000); Można również w późniejszym czasie przydzielić czas do istniejącej animacji: myAnimati on. setDurati on(2000);
nia możliwość definiowania podstawowej animacji oraz parametrów określających sposób powtarzania. W ldasie Animator dostępne są dwie właściwości sterujące powtarzaniem — liczba powtó rzeń animacji oraz akcja wykonywana po każdym powtórzeniu. Właściwości te są sterowane za pomocą następujących konstruktorów i metod: Animator(int duration, double repeatCount, Animator. RepeatBehavior repeatBehavior, TimingTarget target) void setRepeatCount(double repeatCount) void setRepeatBehavior(Animator.RepeatBehavior repeatBehavior)
Istnieje również dodatkowa, ważna wartość, jaką może przyjmować czas trwania: Animator. ‘-►INFINITE, która oznacza, że animacja ta będzie działała bez przerwy. W arto wiedzieć, że animacje takie nadal regularnie wywołują timi ngEvent (), ale ułamek czasu w tym wywołaniu będzie bezużyteczny, ponieważ nie można obliczyć procentowej wartości nieskończoności7.
W tym konstruktorze i metodach działanie powtórzenia jest sterowane za pomocą para metrów repeatCount oraz repeatBehavi or. Parametr repeatCount jest po prostu liczbą po wtórzeń animacji. W artość ta może być ułamkowa, na przykład 2,5, dzięki czemu można zatrzymać animację w połowie ścieżki. Parametr repeatCount, podobnie jak durati on, może
W ażną koncepcją w odniesieniu do czasu trwania jest to, że wszystkie animacje są śledzo
przyjmować wartość Animator. INFINITE, która wskazuje, że animacja powinna być powta
ne przez Animator w częściach czasu. Oznacza to, że animacja, niezależnie od faktycznego
rzana bez przerwy.
upływu czasu, może być definiowana przy użyciu procentu upływającego czasu animacji. Tak więc animacja o czasie trwania innym niż INF1NITE, ma ułamkowy czas trwania równy ). Wywołania timingEvent() w czasie animacji korzystają z ułamku czasu trwania zamiast fak tycznego czasu. M echanizm ten jest prostszy do wykorzystania w metodach wywołujących, w których bardziej użyteczną informacją od tej, że upłynęło 500 ms czasu, jest to, że upłynęła jedna czwarta całkowitego czasu animacji. Koncepcja części czasu, jaki upłynął, będzie często
repeatBehavi or może przyjmować wartości RepeatBehavi o r . LOOP lub RepeatBehavior. ^REVERSE. W artość LOOP pozwala na powtarzanie za każdym razem w tym samym kierun ku. Gdy animacja osiągnie koniec, zaczyna od początku. Tak więc ułamek czasu animacji przekazywany do timi ngEvent () zwiększa się od 0 do 1, następnie znów od 0 do 1 i tak dalej. W artość REVERSE powoduje, że po osiągnięciu końca animacji zmienia ona kierunek. W takim przypadku ułamek czasu animacji przekazywany do timingEventQ zwiększa się od 1 do 1, następnie zmniejsza się od 1 do 0, potem od 0 do 1 i tale dalej.
5 Dlatego, jeżeli jesteśmy na spotkaniu lub na wykładzie, ciągnącym się w nieskończoność, to stale spoglądamy na zegarek, ale wskazówka minutowa wcale się nie posuwa. Ponieważ spotkanie ma nieskończoną długość, upływający czas nie ma znaczenia.
...
^j^uêÊÊÊÊÎÊÊ-''
R o z d z ia ł 14.
B ib l io t e k a T im in g F r a m e w o r k . P o d st a w y
P o d sta w o w e
k o n c ep c je
f
T im in gTargetA dap ter
1: wykorzystywana. Zwykle przedstawiamy animację, korzystając z tego ułamka zamiast całego czasu, ponieważ w taki sposób Animator śledzi i raportuje czas dla obiektów docelowych,
Klasa TimingTargetAdapter jest prostą implementacją TimingTarget, zawierającą puste me
jak również dlatego, że jest to bardziej użyteczne dla użytkowników obiektu Animator.
tody tego interfejsu. Klasa ta jest podstawą dla klas potomnych, które powinny otrzymywać tylko specyficzne zdarzenia Animator, i gdy nie chcemy implementować wszystkich metod Timi ngTarget, aby skorzystać tylko z jednej lub dwóch, które nas naprawdę interesują.
Powtarzanie Często jest stosowane powtarzanie animacji. Powtórzenia mogą przyjmować formę wielo
Czas trwania
krotnego wykonywania tej samej animacji, podobnie jak nieskończony pasek postępu, w któ rym status przesuwa się od lewej do prawej. Powtarzane animacje mogą być również stale
Opis metody timingEvent() jest ściśle związany z właściwością duration, ponieważ ułamek
odwracane, tale jak w przypadku pulsującego przycisku z efektem podświetlenia, które stale
czasu animacji jest obliczany na podstawie minionego czasu oraz całkowitego czasu ani
rozjaśnia się do pełnej jasności, a następnie przyciemnia do pewnego domyślnego stanu.
macji. Czas trwania jest definiowany w konstruktorze klasy Animator, jak wcześniej poka
Zamiast tworzyć osobne animacje dlą^każdego powtórzenia lub tworzyć jedną dużą ani
zywaliśmy, lub za pomocą następującej metody:
mację obsługującą wszystkie powtórzenia jako szczegóły implementacji, biblioteka zapew
set.D uration(int duration) Zarówno metoda setDuration(), jak i konstruktor Animator powodują ustawienie czasu trwa nia animacji wyrażonego w milisekundach. Na przykład można ustawić animację o czasie działania równym 2 sekundom za pomocą konstruktora:Animator myAnimation = new Animator(2000); M ożna również w późniejszym czasie przydzielić czas do istniejącej animacji: myAnimation.setDuration(2000);
nia możliwość definiowania podstawowej animacji oraz parametrów określających sposób powtarzania. W klasie Animator dostępne są dwie właściwości sterujące powtarzaniem — liczba powtó rzeń animacji oraz akcja wykonywana po każdym powtórzeniu. Właściwości te są sterowane za pomocą następujących konstruktorów i metod: Animator(int duration, double repeatCount, Animator. RepeatBehaviór repeatBehavior, TimingTarget ta rg e t) : void setRepeatCount(double repeatCount) void setRepeatBehavior(Animator.RepeatBehavior repeatBehavior)
Istnieje również dodatkowa, ważna wartość, jaką może przyjmować czas trwania: Animator, '-»-INFINITE, która oznacza, że animacja ta będzie działała bez przerwy. W arto wiedzieć, że
W tym konstruktorze i metodach działanie powtórzenia jest sterowane za pomocą para
animacje takie nadal regularnie wywołują timingEvent (), ale ułamek czasu w tym wywołaniu
metrów repeatCount oraz repeatBehavi or. Parametr repeatCount jest po prostu liczbą po
będzie bezużyteczny, ponieważ nie można obliczyć procentowej wartości nieskończoności-'.
wtórzeń animacji. W artość ta może być ułamkowa, na przykład 2,5, dzięki czemu można
W ażną koncepcją w odniesieniu do czasu trwania jest to, że wszystkie animacje są śledzo
przyjmować wartość Animator. INFINITE, która wskazuje, że animacja powinna być powta
ne przez Animator w częściach czasu. Oznacza to, że animacja, niezależnie od faktycznego
rzana bez przerwy.
zatrzymać animację w połowie ścieżki. Parametr repeatCount, podobnie jak durati on, może
upływu czasu, może być definiowana przy użyciu procentu upływającego czasu animacji. Tak więc animacja o czasie trwania innym niż INFINITE, ma ułamkowy czas trwania równy 1. Wywołania timingEvent() w czasie animacji korzystają z ułamku czasu trwania zamiast fak tycznego czasu. Mechanizm ten jest prostszy do wykorzystania w metodach wywołujących, w których bardziej użyteczną informacją od tej, że upłynęło 500 ms czasu, jest to, że upłynęła jedna czwarta całkowitego czasu animacji. Koncepcja części czasu, jaki upłynął, będzie często
repeatBehavi or może przyjmować, w artości RepeatBehavi o r. LOOP lub RepeatBehavi or. '-»'REVERSE. W artość LOOP pozwala na powtarzanie za każdym razem w tym samym kierun ku. Gdy animacja osiągnie koniec, zaczyna od początku. Tak więc ułamek czasu animacji przekazywany do tim ingEvent() zwiększa się od 0 do 1, następnie znów od 0 do 1 i tak dalej. W artość REVERSE powoduje, że po osiągnięciu końca animacji zmienia ona kierunek. W taldm przypadku ułamek czasu animacji przekazywany do timingEventQ zwiększa się od 1 do 1, następnie zmniejsza się od 1 do 0, potem od 0 do 1 i tak dalej.
5 Dlatego, jeżeli jesteśmy na spotkaniu lub na wykładzie, ciągnącym się w nieskończoność, to stale spoglądamy na zegarek, ale wskazówka minutowa wcale się nie posuwa. Ponieważ spotkanie ma nieskończoną długość, upływający czas nie ma znaczenia.
R o z d z ia ł 1 4 .
P o d s t a w o w e k o n c e p c je
B ib l i o t e k a T i m i n g F r a m e w o r k . P o d s t a w y
Parametr startD i r e c ti on może przyjmować domyślną wartość Direction.FORWARD lub
Rozdzielczość Rozdzielczość w obiekcie Animator steruje odstępem czasu pomiędzy kolejnymi wywofo. niami tim ingEvent(). W artość domyślna ustawiona w obiekcie Animator jest wystarczają,
, j ¡Direction.BACKWARD.
początkowy u łam ek czasu
ca w większości sytuacji, więc programiści nie muszą jej zmieniać, ale w razie potrzolw Wy starczy wywołać metodę setResol uti on () :
Domyślnie animacja rozpoczyna się od ułamka czasu równego 0. Ustawienie to może zo: •stać zmienione, dzięki czemu animacja może się rozpocząć od dowolnego punktu. Zmiany
void setR eso lu tio n (in t reso lu tio n )
takiej można dokonać za pomocą metody s e tS ta r tF r a c ti on () : void s e tS ta r tF r a c tio n (flo a t sta rtF ra c tio n )
Metoda ta pozwala na ustawienie czasu w milisekundach pomiędzy kolejnymi wywołaniami t i mi ngEvent (). Jak zauważono w opisie rozdzielczości w rozdziale 12., „Podstawy animacji”
Parametr s ta rtF ra ctio n przyjmuje wartości od 0 do 1, reprezentujące ułamek czasu anima
faktyczna rozdzielczość może zależeć od wielu czynników, takich jak rodzaj zastosowane
cji. Warto wiedzieć, że aby uruchomić animację od końca do początku, wywołujący powinien
go mechanizmu wewnętrznego oraz platforma działania. W bibliotece Tim ing Framework
ustawić początkowy ułamek czasu na 1, a kierunek na BACKWARD. Przykład takiego działania
został zastosowany stoper Swing i dlatego jego rozdzielczość jest ograniczana przez roz
jest pokazany w programie demonstracyjnym Fadi ngButtonTF w dalszej części rozdziału.
dzielczość tego stopera6.
Operacje końcowe
Operacje startowe Istnieją są trzy czynniki dotyczące stanu startowego sterowanej przez nas animacji: opóź nienie uruchomienia, kierunek oraz początkowy ułamek czasu.
Opóźnienie uruchom ienia
;
Domyślnie animacja zachowuje końcową wartość po zatrzymaniu. Na przykład animacja, '. która zakończyła normalny cyld pracy w przód od 0 do 1, zachowa wartość 1 na końcu. Można zmienić to działanie na ustawienie wartości 0 na końcu przez wywołanie metody setEndBehavior(): void setEndBehavior(Animator.EndBehavior endBehavior)
W niektórych animacjach możemy chcieć wprowadzić początkowe opóźnienie przed ich roz
Parametr endBehavior może przyjmować wartość EndBehavior.HOLD, będącą wartością do
poczęciem. Wielkość tego opóźnienia jest kontrolowana za pomocą metody setStartDel ay ();
myślną, lub EndBehavior. RESET, która powoduje wysłanie końcowego wywołania t i mi ng
void setS ta rtD e la y (in t startD elay)
Event () z ułamkiem równym 0.
W metodzie tej parametr startD el ay jest wartością opóźnienia w milisekundach.
Kierunek uruchom ienia Domyślnie po uruchomieniu animacja działa w przód. Początkowy kierunek może być zmie niony, aby animacja działała wstecz. Ustawienie to może być sterowane za pomocą metody s e tS ta rtD ire c tio n (): • void setS tartD irectio n (A n im ato r.D irection s ta rtD ire ctio n )
Demonstracja — FadingButton Nie zakończyliśmy jeszcze przedstawiać podstawowych funkcji klasy Animator. Nadal po zostaje jeszcze przedstawienie ważnych informacji na temat Masy Interpol ator. Jednak czas na przerwę i pokazanie kilku koncepcji w akcji. Sprawdźmy, co można zrobić przy użyciu przedstawionych do tej pory Mas. Mamy do przed stawienia jeszcze sporo ldas z biblioteld, ale bogactwo funkcji i elastyczność podstawowych Mas Animator oraz TimingTarget pozwalają na zbudowanie prostego kodu sterującego za
6 W najnowszych wersjach Timing Framework dodana została możliwość skorzystania z zewnętrznego stopera. Dzięki temu można zastąpić domyślny stoper Swing przez stoper o innej rozdzielczości. Więcej informacji na ten temat można znaleźć w dokumentach JavaDoc dla TimingSource, ale prawdopodobnie więlcszosc użytkowników nie będzie potrzebowała wymieniać domyślnego stopera.
awansowaną animacją. W szczególności spróbujmy zrealizować tę samą animację GUI, którą wykonaliśmy przy użyciu wbudowanych stoperów w poprzednich rozdziałach, lub coś, co wydawało się niezwylde mozolne, jak cyłdiczne, powtarzalne animacje.
372
R o z d z ia ł 1 4 .
B ib l i o t e k a T i m i n g F r a m e w o r k . P o d s t a w y
PODSTA WO WE KONCEPCJE
Na początek wrócim y do programu dem onstracyjnego Fadi ngButton, przedsUuvione 0
Nie potrzebujemy już zmiennej animationStartTime, ponieważ nie musimy obliczać wy
w rozdziale 12. Choć aplikacja ta nie jest zbyt skomplikowana, użytecznym przykładem będzie pokazanie, w jald sposób klasa Animator pomaga tworzyć animacje.
konanej części cyklu. Zrobi to za nas Animator. K onstruktor je st p od obny do poprzedniego, ch o ć d eklaracja zm iennej typu Animator jest
Jak pamiętamy, w tym przykładzie zdefiniowaliśmy klasę pochodną po J Button i umieści liśmy w niej rożne metody pozwalające na rysowanie przezroczystego przycisku oraz ani mowanie jego wartości alfa. Na początku umieściliśmy kilka zmiennych instancyjnych po. zwalających śledzić stan: flo at alpha = l.O f; // bieżąca przezroczystość przycisku Timer timer; // na potrzeby późniejszych akcji uruchomienia i zatrzymania int animationDuration = 2000; // animacja będzie trwała 2 sekundy long animationStartTime; // czas rozpoczęcia każdej animacji W konstruktorze utworzyliśmy obiekt Timer sterujący animacją: timer = new Timer(30, t h i s ) ; Na koniec dodaliśmy metodę a c tio n Performed(), która służyła do dwóch celów — prze chwytywała kliknięcia przycisku i odpowiednio włączała i wyłączała animację, jak również odbierała zdarzenia stopera i animowała wartość alfa,przy użyciu następującego kodu: public void actionPerformed(ActionEvent ae) { // ... kod obsługujący kliknięcia nie jest tu pokazan y...
■animator = new Animator(animationDuration/2, Animator.INFINITE, RepeatBehavior.REVERSE, th is ); W wywołaniu tym można wskazać kilka interesujących elementów. Przede wszystkim ko rzystamy z czasu trwania równego połowie animati onDurati on. Różnica ta wynika ze spo sobu obsługi nowej animacji. Poprzednio każda animacja składała się z fragmentu przy ciemniania oraz z fragmentu rozjaśniania, a cały cykl miał trwać 2 sekundy. Przy użyciu obiektu Animator możemy zadeklarować bardziej interesujące odwrócenie animacji co se kundę, co daje w efekcie ten sam wynik. Dodatkowo anim acja ta ma być powtarzana bez przerwy, czyli w taki sam sposób, jak we wcześniejszym przykładzie z wykorzystaniem Ti mer. Zadeklarowaliśmy również działanie REVERSE, czyli animacja zmienia kierunek przy każdym powtórzeniu. W ostatnim parametrze przekazujemy th is jako TimingTargęt, w którym będą wywoływane zdarzenia stoperów. Nasz obiekt implementuje interfejs TimingTargęt, aby mógł przechwytywać wywołania timingEvent(), podobnie jak poprzednia wersja programu demonstracyjnego otrzymywała zdarzenia z obiektu Ti mer w metodzie acti onPerf ormed (). Dodatkowo, ponieważ chcemy zacząć od nieprzezroczystego przycisku i zmieniać go w kie runku przezroczystości, musimy się upewnić, że prawidłowo połączymy ułamek czasu ani
long currentTime = System.nanoTimeQ / 1000000; long totalTime = currentTime - animationStartTime; i f (totalTime > animationDuration) { animationStartTime = currentTime;
więc jesteśmy niemal u celu. Jednak ponieważ nasza animacja domyślnie rozpoczyna się
}
te zmieniają się przeciwnie do siebie. Możemy albo obliczyć wartość alfa jako odwrotność
flo at fraction = (float)totalTim e / animationDuration; fraction = Math.m in(l.Of, fractio n ); // Wyrażenie to powoduje zmianę wartości alfa o d 1 do 0 // i z powrotem do 1, wraz ze zmianą ułamka o d 0 do 1 alpha = Math.abs(l - (2 * fra c tio n )); repaint( ) ;
ułamka, dzięki czemu wartość alfa będzie miała wartość 1, gdy ułamek będzie 0, lub możemy
} DEMO W SIECI
nieco inn a niż zm iennej Timer:
Teraz, gdy mamy do dyspozycji klasę Animator, spójrzmy, jak zmieni się kod. Ta wersja kodu, nazwana FadingButtonTF, jest dostępna na witrynie W W W książki. Przede wszyst kim potrzebujemy mniej zmiennych instancyjnych: flo at alpha = l.O f; // bieżąca przezroczystość przycisku Animator animator; // na potrzeby późniejszych akcji uruchomienia i zatrzymania in t animationDuration = 2000; // każdy cykl będzie trwał 2 sekundy
macji i naszą wartość alfa. Obie wartości zmieniają się w czasie animacji pomiędzy 0 a 1, od 0, a wartość alfa ma się zacząć od 1, czyli w pełni nieprzezroczystego obiektu, wartości
skorzystać z dodatkowych funkcji-w klasie Animator, aby rozpocząć animację od końca, odtwarzając ją w tył. Pozwala to zapewnić, że ułamek animacji rozpoczyna się od tej samej wartości, którą chcemy uzyskać dla alfa. Dodajemy więc następujący kod pozwalający od powiednio ustawić właściwości obiektu Animator: animator. setStartFracti on(1.0 f ) ; animator. setStartDi recti on(Di recti on. BACKWARD); Na koniec należy dodać kod animujący do nowej wersji naszego programu dem onstra cyjnego. Tym razem lcod ten znajduje się w m etodzie timingEventQ, która m ieści się w obiekcie docelowym dla zdarzeń stopera dla Animator, a nie w starej metodzie a c tio n Perf ormed (). Porównajm y kod w metodzie a c ti on Performed () z tym, który był zastoso wany w t i mi ngEventQ:
-.i
374
R o z d z ia ł 14.
P o d sta w o w e
B ib l io t e k a T im in g F r a m e w o r k . P o d sta w y
public void timingEvent(float fraction) { alpha = fraction; re p a in t(); } Należy zwrócić uwagę, że nie obliczamy ułamka animacji, ponieważ wartość ta jest dla nas
k o n c ep c je
Program dem onstracyjny R a c e tra c k Program ten można znaleźć na witrynie WW W książki w różnych projektach, których nazwa: kończy się na Race. Znajduje się tam jdUca ,wersji aplilcacji odnoszących się do rożnych funkcji; biblioteki, które przedstawiamy w tym i następnym rozdziale.
obliczona. Dodatkowo elastyczność sposobu działania animacji, możliwość rozpoczęcia je' od końca i wykonywania operacji wstecz w pierwszym przebiegu, upraszcza obliczenia war
Tło
tości alfa do zwykłego przypisania jej wartości samego ułamka. Ekran tej aplikacji jest p0. kazany na rysunku 14.1.
Przede wszystkim powinniśmy przedstawić, jak ta aplikacja działa. W pakiecie aplikacji de monstracyjnej znajdują się cztery główne ldasy które są używane we wszystlcieb wersjach tej aplikacji. Contro! Panel — jest to panel z przyciskami Start 'oraz Stop, które są przedstawione na dole okna widniejącego na rysunku 14.2. Przyciski są dodawane jako nasłuchy w dowol nych miejscach aplikacji, co pozwala na uruchamianie i zatrzymywanie wyścigu.
Rysunek 14.1. FadingButtonTF — taka sama aplikacja jak FadingButton, ale przy użyciu mniejszej ilości kodu
Ta nowa wersja programu demonstracyjnego działa identycznie jak poprzednia, ale przy użyciu znacznie mniejszej ilości kodu. Ten program demonstracyjny jest z założenia bardzo prosty, więc nie pokazuje efektywności biblioteki Tim ing Framework nawet w przypadku bardzo prostych animacji. Jednak pomoże nam opracować znacznie bardziej interesujący przykład pokazujący więcej możliwości biblioteki. Będziemy tworzyć ten program demon stracyjny, Racetrack, w tym rozdziale, jak również następnym, dzięki czemu będzie można zobaczyć, jak różne elementy biblioteki współpracują ze sobą, aby utworzyć bardziej intere sujące i złożone aplikacje. M
I]: stop
Rysunek 14.2. Program demonstracyjny Racetrack
376
R o z d z ia ł 1 4 .
B ib l io t e k a T im i n g F r a m e w o r k . P o d s t a w y
In t e r p o l a c ja
Po kliknięciu jednego z przycisków wywoływana jest metoda actionPerformed(), w której animacja jest zatrzymywana w odpowiedzi na kliknięcie przycisku Stop i uruchamiana od nowa po kliknięciu Start.
TrackView — jest to część aplikacji, która obsługuje rysowanie samochodu w bieżącej pozycji i orientacji na ścieżce. Inny kod może wywołać tę klasę do ustawienia położenia i obrotu samochodu, a metoda paintComponent() obsługuje odpowiednie rysowanie samochodu. RaceGUI — klasa ta tworzy obiekty TrackView. oraz Control Panel wewnątrz JFrame i zarządza nimi.
'■
*Raęe — każda odmiana tego programu demonstracyjnego będzie nazywana *Race w zależności od demonstrowanych rozwiązań. Na przykład pierwsza przedstawion a wersja będzie mieć nazwę Basi cRace. Klasy te obsługują konfigurację animacji i zmianę właściwo ści samochodu w czasie animacji. Teraz, gdy przedstawiliśmy ogólną architekturę, możemy pokazać, jak faktycznie działa pro gramu Nie będziemy zajmować się szczegółami działania klas Control Panel ani TrackVi ew, ponieważ są one dosyć proste i słabo związane z tematem naszych rozważań. Zamiast tego przedstawimy kod z klas *Race, w których są realizowane animacje.
B a sicR a ce DEMO W SIECI
Klasa BasicRace zawiera najprostszą wersję programu demonstracyjnego — samochód jest przesuwany na pierwszym odcinku w dół przez określony okres; pokazuje to, w jaki sposób skorzystać z podstawowych mechanizmów klasy Animator do realizacji tego zadania. W klasie Basi cRace zdefiniowanych jest kilka stałych i zmiennych instancyjnych: public s t a t ic fin ał int RACE_TIME = 2000; Point sta rt = TrackView.START_POS; Point end = TrackView.FIRST_TURN_START; Point current = new PointO ; Animator animator; Stałe sta rt oraz end pochodzą z klasy TrackVi ew i pozwalają na.zdefiniowanie ośmiu naroż ników toru. Znijemia current jest wykorzystywana do przechowywania położenia samochodu. Oczywiście, zmienna animator jest instancją Animator, która steruje animacją.
public void actionPerformed(ActionEvent ae) { - . i f (ae.getActionCommandQ.e q u a ls("S ta rt")) { anim ator.stop(); . . . ■ anim ator.start( ) ; ’ } else i f (ae.getActionCommandO.equals("Stop")) {j , ,anim ator.stop();
.
}
y . . y,,. :,ent(k W czasie przyspieszania, co zawsze dzieje się na początku animacji, wartość ułamka rośnie szybciej niż analogiczna wartość obliczona na podstawie fragmentu czasu trwania animacji, W czasie opóźnienia, które zawsze ma miejsce na końcu animacji, jest odwrotnie; ułamek zwiększa się wolniej niż ułamek wyliczony na podstawie czasu. Ustawienie tych wartości w obiekcie Animator jest proste. Wystarczy przed rozpoczęciem animacji wywołać odpowiednie metody: s e tA c ce le ra tio n (f1oat przyspi eszenie) setD ecelerati o n (f1oat opóźni eni e)
--------------------------------
;------- -------------------- j— ^
Obie metody oczekują wartości z zakresu od 0 do 1, które reprezentują ułamek animacji, jaki ma podlegać przyspieszeniu lub opóźnieniu. Należy pamiętać, że te dwa ułamki wzajemnie się wykluczają. Animacja nie może jednocześnie podlegać przyspieszaniu i opóźnianiu, więc (p rzyspieszen ie + o p óź n ien ie) < 1. Ograniczenia te są przedstawione na rysunku 14.3,
.
0
Czas (ułamek)
1
Rysunek 14.4. Domyślne działanie aplikacji bez przyspieszeń i opóźnień — szybkość animacji jest stała
Wywołanie metody z wartością niezgodną z tymi zasadami powoduje zgłoszenie wyjątku U l ega! ArgumentExcepti on.
Dla porównania weźmy pod uwagę obiekt anim z okresem przyspieszania równym 0 .4 oraz opóźnienia równym 0.2. Parametry te możemy ustawać za pomocą następujących instrukcji:
W czasie przyspieszania, szybkość zwiększa się ze stałą wartością przyspieszenia. W czasie opóźnienia animacja działa odwrotnie. Jak jest to pokazane na rysunku, wszystkie animacje mają początkowy okres przyspieszania, o domyślnej długości równej 0, po którym występuje fragment o stałej szybkości, którego domyślną długością jest 1, czyli cała animacja, a na końcu również znajduje się okres spowalniania, którego domyślna długość wynosi I).
a n im .se tA cc e le ra tio n (.4 f); a n im .se tD e c e le ra tio n (.2 f);
R o z d z ia ł 14.
I n te r p o l a c ja
B ib l io t e k a T im in g F r a m e w o r k . P o d s t a w y
Interpolacja liniowa a nieliniowa
Animacja ta przyspiesza płynnie od O do pełnej szybkości w czasie pierwszych 40% czasu, działa ze stałą szybkością przez kolejne 40% ,:a następnie zwalnia z pełnej szybkości do o w czasie końcowych 20%. Wykres szybkości w czasie dla tej animacji jest przedstawiony na rysunku 14.5.
Liniow a
^
N ieliniow a
Rysunek 14.6. Część interpolowana z przyspieszeniem = 0,4 oraz opóźnieniem = 0,2 w porównaniu do czasu liniowego (linia prosta)
wstępnie interpolowanym ułamku, to nasz obiekt będzie powoli przyspieszał na początku, potem przesuwał się szybciej niż w przypadku ruchu liniowego, a na końcu zwolni aż do osiągnięcia punktu docelowego. Odnosi się nie tylko do przyspieszeń i opóźnień, ale również do bardziej ogólnych metod interpolacji.
Rysunek 14.5. Szybkość animacji z przyspieszeniem (0,4) oraz opóźnieniem (0,2) Takie zastosowanie przyspieszeń i opóźnień daje wrażenie płynniejszej animacji w porów naniu do animacji, w której obiekt ma od razu docelową szybkość. Jeżeli przedstawimy interpolowaną wartość w czasie, uzyskamy wykres zamieszczony na
■W
Wskazówka Ruch nieliniowy może być tworzony przez wykonanie prostych obliczeń interpolacji liniowej przy użyciu nieliniowych wartości synchronizujących.
rysunku 14.6. Dla porównania — linia prosta przedstawia interpolację liniową. Wskazówka Jak wspominaliśmy na początku tego opisu, wartość ułamka timingEvent() jest zmieniana przez wartości przyspieszenia i opóźnienia. Dlatego wartości ułamka uzyskiwane w naszej metodzie timi ngEvent() będą nieliniowe i pozwalają w łatwy sposób obliczyć odpowiednie nieliniowe wartości. Jeżeli spojrzymy na wykres z rysunku 14.6, możemy wyobrazić sobie wpływ, jaki może on mieć na obliczenia ruchu obiektu. Jeżeli ułamek, reprezentowany linię krzywą, jest interpolowany w taki sposób wraz z liniowym upływem czasu reprezen towanym przez prostą linię, to w taki sam sposób wpłynie to na ruch obiektu. Jeżeli skorzy stamy z parametrycznych, liniowych obliczeń położenia obiektu, bazujących na dostarczanym
Przyspieszenia i opóźnienia stanowią prostą metodę uzyskania nieliniowego ruchu w animacjach; wystarczy przekazać do obiektu Animator ułamki przyspieszenia i opóźnienia, a nasze proste obliczenia liniowe dadzą w efekcie bardziej realistyczny ruch.
R o z d z ia ł 1 4 .
382
B ib l i o t e k a T im i n g F r a m e w o r k . P o d s t a w y
I n t e r p o l a c ja
Interpolator
Program dem onstracyjny N o n Lin e arR a ce DEMO W SIECI
Interpol ator zapewnia ogólny i efektywny mechanizm pozwalający na interpolowanie warto
Spróbujmy teraz skorzystać z nowo nabytej wiedzy na temat przyspieszeń i opóźnień, rozwijając program demonstracyjny Racetrack i dodając do niego bardziej realistyczny ruch samochodu.
ści synchronizujących. Jak już wcześniej wspomnieliśmy, mechanizm ten jest bardziej uniwer
W poprzedniej wersji programu, BasicRace, samochód wyglądał całkiem nieźle, sunąc po trasie,
salny niż ułamki przyspieszenia i opóźnienia lub przynajmniej może taki być. Faktycznie,
ale wydawał się dosyć nierealistyczny7. W szczególności, dosyć dziwnie wygląda sytu aci a, gdy samochód natychmiast rozpędza się od 0 do pełnej szybkości, a następnie nagle zatrzymuje się na końcu pierwszego odcinka. Czy nie bardziej realistycznie wyglądałoby przyspieszenie przez pewien czas do pełnej szybkości, a następnie hamowanie na końcu?
dosyć łatwo można uzyskać złożone działanie obiektu Interpol ator, bez konieczności więk szych nakładów pracy. Dodatkowo dostępnych jest wiele gotowych konfiguracji w istniejących implementacjach Interpol ator. Wszystko zależy od tego, co chcemy osiągnąć. Na początku szczegóły API —■Interpol a to r jest bardzo prostym interfejsem zawierającym tylko jedną metodę:
W tym programie demonstracyjnym wykorzystamy w maksymalnym stopniu poprzedni, Bas.icRace. Dlatego utworzymy klasę. NonLinearRace jalco klasę dziedziczącą po Basi c Race. Ta nowa klasa nie ma żadnych nowych funkcji poza umieszczonymi w metodzie main(), pozwalającej na uruchomienie aplikacji oraz wykonanie konstruktora. Konstruktor wywó-■
float in terp olate^ !oat fraction)
łuje kod z klasy nadrzędnej, BasicRace, w celu wykonania zdefiniowanych tam operacji, ¡i
Metoda ta oczekuje wartości ułamkowej z zakresu od 0 do 1 i zwraca również wartość ułam kową z zakresu od 0 do 1.
a następnie wykonywane są dwie niewielkie zmiany: public NonLinearRace(String appName) { super(appName); .animator . ' s e t A c c e l e r a t i o n ( . 5 f ) ; a n i m a t o r . setOecei e r a t i on( . l f ) ;
\ |/ i =
wykorzystywane bezpośrednio przez programistów aplikacji, poza jedną metodą di sarm(); public void disarm!) Metoda ta pozwala na wyłączenie wyzwalacza; wszystkie kolejne zdarzenia, które spowo dowałyby uruchomienie animacji przestają mieć jakikolwiek efekt.
TriggerEven t Ta klasa bazowa ma za zadanie dostarczyć klasom pochodnym po Trigger sposobów na określanie zdarzeń specyficznych dla tych wyzwalaczy. Mechanizm ten pozwala na dostęp do
Rysunek 15.1. Program demonstracyjny Triggers. Różne wyzwalacze są ustawiane za pomocą przycisku Wyzwalacz. Każdy z wyzwalaczy powoduje odbijanie się oddolnej części okna innej sfery
obiektów TriggerEvent przez klasę bazową Trigger w ogólny sposób, co umożliwia prze niesienie części logiki z Idas dziedziczących po Trigger! Programiści aplikacji zwykle nie wy
Każda sfera w programie ma zdefiniowaną animację powodującą odbijanie się od dolnej części
wołują bezpośrednio obiektów TriggerEvent, ale korzystają z jednej z prostych Idas dziedzi
okna. Funkcje rysowania i animowania sfery są umieszczone w osobnej ldasie SpherePanel,
czących, które definiują zdarzenia specyficzne dla określonej klasy dziedziczącej po Trigger,
w której jest tworzona animacja oraz obsługiwane jest rysowanie pojedynczej sfery. Two rzenie tych paneli z różnymi obrazami sfer jest zrealizowane w następujący sposób:
W ldasie TriggerEvent znajduje się jedna metoda publiczna o nazwie getOppositeEvent(), Jednak pomimo tego, że jest ona publiczna, nie jest przeznaczona do bezpośredniego wy woływania przez aplikacje. Jest to metoda użytkowa, która może być nadpisywana w kla sach pochodnych; będzie ona wywoływana przez Trigger w celu automatycznego odwró cenia animacji.
action = new SpherePanel ("yellow -sphere.png"); focus = new SpherePanel("blue-sphere.png"); armed = new SpherePanel("red-sphere.png"); over = new SpherePanel("green-sphere.png"); timing = new SpherePanel("gray-sphere.png"); Obiekt Animator jest definiowany za pomocą PropertySetter, korzystającego z wielu warto
W b u d o w a n e wyzwalacze
ści do przesuwania ich od góry do dołu ekranu i z powrotem. Nie przedstawialiśmy jeszcze metod ustawiania właściwości, ale zajmiemy się nimi wkrótce, więc na razie tylko prowo
Mamy tu sporo do dziedziczenia. Przedstawimy teraz wyzwalacze dostarczane w bibliotece, z których można korzystać w swoich aplikacjach. Wszystkie te wyzwalacze korzystają z Lego samego wzorca dotyczącego konstruktorów i metod factory. Metody factory są nazywane addTrigger() i oczekują one jednego dodatkowego argumentu używanego do wyspecyfi kowania obiektu, do którego wyzwalacz dołącza się jako nasłuch. DEMO W SIECI
kacyjnie z nich skorzystamy: bouncer = PropertySetter.createA nim ator(1000, t h i s , "sphereY", 0, (PANEL_HEIGHT - sphereIm age.getH eight()), 0 ) ; b o u n ce r.se tA cc e le ra tio n (.5 f); b o u n ce r.se tD e c e le ra tio n (.5 f);
Aby pomóc zrozumieć, w jaki sposób należy używać wyzwalaczy, przedstawimy wygląd:
W tym przypadku obiekt Animator ma zdefiniowany czas działania równy jednej sekun
ekranu oraz kod z prostego programu demonstracyjnego Triggers, dostępnego na witry
dzie, w czasie której wartość właściwości sphereY w obiekcie SpherePanel jest zmieniana
nie W W W książki. Aplikacja ta pokazuje pięć kolorowych sfer oraz kilka przycisków po
od 0 do współrzędnej dolnej krawędzi okna i z powrotem. Dodatkowo ustawiliśmy wła
zwalających na sterowanie animacją, co zostało pokazane na rysunku 15.1.
ściwości przyspieszenia i opóźnienia w obiekcie Animator, dzięki-czemu uzyskaliśmy efekt „podskakiwania”.
R o z d z ia ł 1 5 .
W yzw alacze
B ib l io t e k a T im i n g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
Rysowanie sfer we właściwej lokalizacji jest realizowane w prostej metodzie pai ntComponent () obiektu SpherePanel: @0verride protected void paintComponent(Graphics g) { g.setCo1or(Co1o r.w h ite ); g . f i 11 R ect(0 , 0 , getW idthQ, g etH eig h tQ ); g.drawlmage(spherelmage, sphereX, sphereY, n u ll); } W odniesieniu do każdego z kolejnych wbudowanych wyzwalaczy pokażemy, jak każdy
pemonstracjo ¡i yc*¥ demo lw jtfSlECI
—
Triggers
W programie demonstracyjnym Triggers naciśnięcie przycisku Wyzwalacz powoduje ani mowanie odbijania pierwszej sfery, ja k jest to pokazane na rysunku 15.2. Kod tworzący ten wyzwalacz jest następujący: A ctionT rigger.ad d Trigger(triggerB utton, a c t i on.getA nim ator!)); gdzie action jest obiektem ldasy SpherePanel, który zawiera sferę znajdującą się po lewej stronie i skojarzoną z obiektem Animator.
z nich uruchamia tę samą animację dla różnych sfer w oknie programu Tri ggers.
A ctionT rigger Act i onTri gger jest najprostszym wyzwalaczem w bibliotece, ponieważ obsługuje tylko jeden typ zdarzenia: jav a.aw t. event. Act i on Event. Oznacza to, że wyzwalacz ten nie potrzebuje obiektu TriggerEvent, ponieważ jedyne zdarzenie, jakie powoduje uruchomienie wyzwalacza, jest znane.
Konstruktor ActionTrigger(Animator animator)
©
Metoda factory addTrigger(O bject source, Animator animator) Parametr animator jest obiektem animatora, który będzie uruchomiony po otrzymaniu zda rzenia ActionEvent. Argument typu Object w metodzie factory jest obiektem, do którego wyzwalacz doda się jako nasłuch. Trzeba pamiętać, że Obj e ct jest bardziej ogólną klasą niż używane przez ldasy dziedziczące po Trigger, ponieważ dostępnych jest wiele niezwiązanych klas, które mogą wysyłać zdarzenia do obiektu Acti onLi stener. Od wywołującego me todę addTrigger() zależy dostarczenie obiektu, który posiada metodę addActionLi stener(), aby możliwe było prawidłowe wywołanie tej metody przez Acti onTri gger.
Rysunek 15.2. ActionTrigger — pierwsza sfera jest animowana po kliknięciu przycisku Wyzwalacz
FocusTrigger Obiekt FocusTrigger uruchamia animację w zależności od tego, czy komponent uzyska lub straci fokus. Wyzwalacz ten implementuje interfejs FocusLi stener i jest dodawany przez wywołującego lub niejawnie w metodzie factory, jako nasłuch komponentu. Kolejne zdarze nia fokusu w tym komponencie spowodują uruchomienie animacji.
Przykład Załóżmy, że mamy obiekty JButton oraz Animator: JButton button; Animator anim; Aby obiekt anim uruchomił animację po przyciśnięciu przycisku button, należy skorzystać z następującego wywołania: A ctionTrigger.addTrigger(button, anim);
Konstruktory FocusTrigger(Animator animator, FocusTriggerEvent event) FocusTrigger(Animator animator, FocusTriggerEvent event, boolean autoReverse)
Metody factory addTrigger(JComponent component, Animator animator, FocusTriggerEvent event) addTrigger(JComponent component, Animator animator, FocusTriggerEvent event, boolean autoReverse)
■
404
R o z d z ia ł 15.
.■jffi ¡i
B i b l io t e k a . T i m i n g F r a m e w o r k . F u n k c j e z p a w a n s o w a n e
W yzw alacze
Parametr animator jest obiektem animatora, który będzie uruchomiony po otrzymaniu zdarzenia. Zdarzeniem tym może być:
Inny przycisk toyzivalacz1
® FocusTri ggerEvent. IN, gdy kom ponent uzyska fokus,
P T ~ T'- D (? '
® FocusTri ggerEvent. OUT, gdy kom ponent straci fokus. Więcej informacji na temat tych zdarzeń znajduje się w dokumentach JavaDoc dla FocusListener; odpowiadają one tym z interfejsu FocusListener. Znacznik autoReverse jest używany do określenia, czy wyzwalacz powinien zatrzymać się, zmienić kierunek i ponownie
i
O
uruchomić animację po otrzymaniu przeciwnego zdarzenia w stosunku do zdefiniowanego w argumencie event. Argument component w metodzie factory jest komponentem Swing, do którego wyzwalacz doda się jako nasłuch.
Przykład Załóżmy, że mamy obiekty JButton oraz Ani mator:
Rysunek 15.3. FocusTrigger — druga sfera jest animowana po uzyskaniu folcusu przez przycisk Wyzwalacz
JButton button; Animator anim;
MouseTrigger Załóżmy, że anim pozwala animować przejście pomiędzy stanem przycisku nieposiadająWyzwalacz MouseTri gger uruchamia animację na podstawie zdarzeń myszy w komponen
cego folcusu a stanem przycisku posiadającym fokus. Animacja anim może uruchomić się automatycznie po uzyskaniu folcusu przez wywołanie następującej metody: FocusTrigger.addTrigger(button, anim, FocusTriggerEvent.IN, tr u e );
cie. Wyzwalacz ten implementuje interfejs MouseLi sten er i jest dodawany przez wywołują cego lub niejawnie w metodzie factoiy, jako nasłuch komponentu. Kolejne zdarzenia myszy .....
w tym komponencie spowodują uruchomienie animacji. Zdarzenia te są przydatne do uru
Ostatni argument metody addTriggerQ powoduje powstanie wyzwalacza z automat) cz-
chamiania animacji w momencie przesunięcia myszy nad komponent lub stanu, gdy przycisk
nym odwracaniem. Oznacza to, że zdarzenie IN będzie powodowało normalne rozpoczęcie
myszy został naciśnięty, ale niezwolniony.
animacji, a kolejne zdarzenie OUT spowoduje, że animacja zatrzyma się, zmieni kierunek i rozpocznie od tego samego miejsca.
Konstru który
^
MouseTrigger(Animator animator, MouseTriggerEvent event) ■ MouseTrigger(Animator animator, MouseTriggerEvent event, boolean autoReverse)
Demonstracja — Triggers DEMO
Druga sfera jest animowana w momencie uzyskania folcusu przez przycisk W yzwalacz, jak
W SIECI
jest to pokazane na rysunku 15.3. Wyzwalacz ten jest powodem umieszczenia w tym programie demonstracyjnym przycislcu in n y przycis/c, ponieważ jest to inny ooieict mteriejsu, który może otrzymywać fokus. Naciśnięcie klawisza T ab łub kliknięcie myszą tego przyci sku powoduje odpowiednią zmianę folcusu. Kod tworzący ten wyzwalacz jest następujący: FocusTri gger. addTri g g e r(tri ggerButton, focus.getA nim ator( ) , ^FocusTri ggerEvent. IN); gdzie focus jest obiektem klasy SpherePanel, który zawiera drugą sferę po lewej stronie i skojarzoną z obiektem Animator.
Metody factory addTrigger(JComponent component, Animator animator, MouseTriggerEvent event) addTrigger(JComponent component, Animator animator, MouseTriggerEvent event, boolean autoReverse) Param etr animator jest obiektem animatora, który będzie uruchom iony po otrzymaniu zdarzenia. Parametr event może być jednym z następujących: • MouseTri ggerEvent. ENTER, gdy kursor myszy zostanie umieszczony w obszarze komponentu,
r
• MouseT ri ggerEvent. EXIT, gdy kursor myszy zostanie usunięty z obszaru komponentu,
406
R o z d z ia ł 15.
B ib l io t e k a T im in g F r a m e w o r k . F u n k cje z a a w a n so w a n e
© MouseTri ggerEvent. PRESS, gdy przycisk myszy zostanie przyciśnięty w obszarze komponentu, ® MouseTri ggerEvent. RELEASE, gdy przycisk myszy zostanie zwolniony w obszarze komponentu, • MouseTri ggerEvent .CLICK, gdy przycisk myszy zostanie kliknięty, czyli przyciśnięty
W yzw alacze
M ouseTrigger.addTrigger(triggerButton, armed.getAnimatorQ, '-►MouseTri ggerEvent. PRESS); M ouseTrigger.addTrigger(triggerButton, over.getA nim atorQ , '-►MouseTriggerEvent.ENTER); gdzie armed oraz over są obiektami SpherePanel obsługującymi trzecią i czwartą sferę i skoja rzone z nim i obiekty Animator.
i zwolniony w obszarze komponentu. Więcej informacji na temat tych zdarzeń znajduje się w dokumentach JavaDoc dla MouseListener; odpowiadają one tym z interfejsu MouseListener. Znacznik autoReverse jest używany do określenia, czy wyzwalacz powinien zatrzymać się, zmienić kierunek i ponownie uruchomić animację po otrzymaniu zdarzenia przeciwnego w stosunku do zdefiniowanego w argumencie event. Argument component w metodzie factory jest komponentem Sw in g , do którego wyzwalacz doda się jako nasłuch.
Przykład Załóżmy, że mamy obiekty JButton oraz Animator: JButton button; Animator anim; Załóżmy również, że anim pozwala animować przejście pomiędzy domyślnym stanem przycisku a stanem, w którym znajduje się na nim kursor myszy. Animacja anim może uruchomić się automatycznie, gdy przycisk otrzyma zdarzenie umieszczenia kursora myszy,
Rysunek 15.4. MouseTrigger — trzecia sfera jest animowana w momencie kliknięcia przycisku Wyzwalacz
przez wywołanie następującej metody: M ouseTrigger.addTrigger(button, anim, MouseTriggerEvent.ENTER, tru e );
[Ufrflfcr-
_____
-^ A l
In n y p r z y c i s k
Ostatni argument metody addTriggerQ powoduje powstanie wyzwalacza z automatycznym odwracaniem. Oznacza to, że zdarzenie ENTER będzie powodowało normalne rozpoczęcie animacji, a kolejne zdarzenie EXIT spowoduje, że animacja zatrzyma się, zmieni kierunek
.
____________________ W y z w a l a c z j
0 0 0
—
j j
©'■
i rozpocznie od tego samego miejsca.
Demonstracja — Triggers DEMO W SIECI
r>:
W programie demonstracyjnym Triggers znajdują się dwie animacje związane z Mouse Tri gger. Pierwsza animacja jest uruchamiana w momencie „uzbrojenia” przycisku Wyzwa lacz, czyli gdy naciśniemy ten przycisk, jak jest to pokazane na rysunku 15.4. Inna animacja rozpoczyna się, gdy kursor myszy znajduje się „nad” przyciskiem W yzwalacz, jak jest to pokazane na rysunku 15.5. Kod tworzący te wyzwalacze jest następujący:
Rysunek 15.5. MouseTrigger — czwarta sfera jest animowana w momencie umieszczenia myszy na przycisku Wyzwalacz
407
.i ,’ « !
"W * R o z d z ia ł 1 5 .
B ib l i o t e k a T i m i n g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
Tîm ingTrîgger
W yzw alacze
Demonstracja
—
Triggers
Wyzwalacz TimingTrigger jest przydatny do tworzenia sekwencji osobnych animacji. Po zwala on na definiowanie uruchomienia obiektu Animator po zatrzymaniu, powtórzeniu lub uruchomieniu innego. Wyzwalacz ten implementuje interfejs TimingTarget i jest dodawa
DEMo WSiECI,
Ostatnia sfera jest animowana w momencie zakończenia animacji pierwszej sfery, która jest uruchamiana przez kliknięcie przycisku W yzwalacz. Ta animacja TimingTarget jest przedstawiona na rysunku 15.6. Kod tworzący ten wyzwalacz jest następujący:
ny przez -wywołującego lub niejawnie do obiektu Animator.
Tim ingTrigger.addTrigger(action.getA nim ator(), tim ing.getA nim ator(), TimingTriggerEvent.STOP);
Konstruktory TimingTrigger(Animator animator, TimingTriggerEvent event) TimingTrigger(Animator animator, TimingTriggerEvent event, boolean autoReverse)
gdzie action jest obiektem SpherePanel zawierającym sferę znajdującą się po lewej stronie oraz skojarzony z nią obiekt Animator, natomiast Timi ng jest obiektem SpherePanel zawie rającym sferę z prawej strony.
Metody factory -JnliŁi
addTrigger(Animator source, Animator animator, TimingTriggerEvent event) addTrigger(Animator source, Animator animator, TimingTriggerEvent event, boolean autoReverse)
0 Ô 0 O
Parametr animator jest obiektem animatora, który będzie uruchomiony po otrzymaniu zda rzenia. Zdarzeniem tym może być: ® Ti mi ngTri ggerEvent. START, gdy animacja źródłowa zostanie uruchomiona, © Ti mi ngTri ggerEvent. STOP, gdy animacja źródłowa zostanie zatrzymana,
0
® Ti mi ngTri ggerEvent. REPEAT, gdy animacja źródłowa zostanie powtórzona. Więcej informacji na temat tych zdarzeń znajduje się w dokumentach JavaDoc dla Timing Target; odpowiadają one metodom begin(), end() oraz repeat() z interfejsu TimingTarget. Znacznik autoReverse jest używany do określenia, czy wyzwalacz powinien zatrzymać się,
Rysunek 15.6. TimingTrigger — sfera znajdująca się po prawej stronie jest animowana po zakończeniu animacji sfeiy znajdującej się po lewej stronie, uruchamianej przyciskiem Wyzwalacz
zmienić kierunek i ponownie uruchomić animację po otrzymaniu zdarzenia przeciwnego w stosunku do zdefiniowanego w argumencie event. Argument source w metodzie factoiy jest obiektem Animator, do którego wyzwalacz doda się jako nasłuch.
Demonstracja — TriggerRace
Przykład Załóżmy, że mamy dwie animacje: Animator animl, anim2; Chcemy, aby anim2 została uruchomiona w momencie zakończenia animl. Sekwencję taką możemy przygotować w następujący sposób: TimingTrigger.addTrigger(animl, anim2, TimingTriggerEvent.STOP);
DEMO WSIECI
^
.
Czas wrócić do naszego programu demonstracyjnego z rozdziału 14., toru wyścigowego, Gdy znamy mechanizm wyzwalaczy, możemy uprościć kod przedstawiony-poprzednio w NonLinearRace i utworzyć kolejną wersję, TriggerRace, która również jest dostępna na'witrynie WWW książki. W szczególności możemy uruchamiać wyścig' przez kliknięcie przycisku Start. Nadal będziemy potrzebować metody ácti onLi stener do zatr'zymaniaanimácjil ale jej uruchomienie przyciskiem Start będzie znacznie prostsze. Zamiast konfigurowania Acti onLi ste ner dla goButton i umieszczania kodu uruchamiającego wyścig w metodzie acti onPerformed () . możemy skorzystać z następującego wywołania: , . ActionTrigger.àddTrigger'(goButton.j.. animator) ;
R o z d z ia ł 1 5 .
B ib l io t e k a T im i n g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
M e t o d y u s t a w ia n ia w ł a ś c iw o ś c i
Generalnie będziemy tworzyć animacje lub korzystać z nich w aplikacjach, w których bę
Wyzwalacz tenobsługuje kliknięcia goButton wewnątrz ActionTrigger i automatycznie uru
dziemy zmieniać właściwości obiektu w czasie — przezroczystość komponentów, umiesz
chamia naszą animację.
czenie przycisków, tekstu w etykiecie i tak dalej. W iemy, jak wykonać talde animacje przy
•Wszystkie funkcje Tri ggerRace.są następujące: public class TriggerRace extends NonLinearRace { ...... . public TriggerRace(String appName) { super(appName); JButton goButton = control Panel.getGoButton(); ActionTrigger trig ger = ActionTrigger.addTrigger( goButton, animator);
użyciu podstawowych klas Animator oraz TimingTarget; znacznie łatwiej tak je wykonać niż przy stosowaniu wbudowanych stoperów Java. Jednak większość typów operacji może ........................ .
być zautomatyzowana przy użyciu metod ustawiania właściwości z wykorzystaniem pro stych definicji modyfikacji obiektów w czasie. Oznacza to, że nie trzeba ręcznie wykonywać w aplikacji zmiany wartości w czasie; biblio teka robi to za nas zgodnie z pewnym wyrażeniem. Załóżmy, że chcemy zmienić właści wość mylnt typu całkowitego od 0 do 10 w sposób liniowy w czasie jednej sekundy. Można
public void actionPerformed(ActionEvent ae) { •- i f (ae.getActionCommand().equals("Stop")} {..... ' anim ator.stop();
to zrobić przy użyciu podstawowych funkcji Tim ing Framework w następujący sposób: : DEMO
// metoda main() usunięta dla uproszczenia
W SIECI
Klasa ta, podobnie jak NonLinearRace, korzysta z funkcji Idasy bazowej do konfigurowania wyścigu, a następnie dodajemy wyzwalacz do przycisku Start. Wyzwalacze obsługują wyłącznie uruchomienie animacji, więc nadal potrzebujemy mechanizmu, metody actionPerformed() do zatrzymania animacji po kliknięciu przez użytkownika przycisku Stop.
public class MylntAnim { private int mylnt; public void setM yInt(int newValue) { mylnt = newValue;
public MylntAnimQ { // Konfiguracja animacji TimingTarget myTarget = new TimingTargetAdapterQ public void tim ingEvent(float fraction) { setM y!n t((in t)(fractio n * 10)); } }; Animator anim = new Animator(1000, myTarget); a n im .sta rt();
M etody ustawiania właściwości Metody ustawiania właściwości są świetnym mechanizmem sterowania animacją; auto matycznie zmieniają one właściwości obiektu w czasie bez konieczności kodowania całego procesu w aplikacji. Podobnie jak wyzwalacze, metody ustawiania właściwości są mecha nizmem konfiguracji animacji, a następnie automatycznego realizowania zadań animacji.
W tym programie dem onstracyjnym, znajdującym się na witrynie W W W , w projekcie
Jednak wyzwalacze obsługują funkcję uruchamiania animacji, natomiast metody ustawiania
MylntAnim, implementacja timingEvent() wywołuje setM yInt() do zmiany wartości mylnt w czasie animacji.
właściwości obsługują podstawowe funkcje modyfikowania obiektów w czasie animacji. Automatyzacja ta daje bardzo duże możliwości. Uwaga Metody ustawiania właściwości przenoszą nas ze świata ręcznej obsługi zdarzeń animacji do bardziej zautomatyzowanego, deklaratywnego, w którym wskazujemy, co należy animować, i pozwalamy metodom ustawiania właściwości na wykonanie za nas pracy2.
2 Różnica pomiędzy zastosowaniem metod ustawiania właściwości i nielcorzystaniem z nich może być porów nana z różnicą między korzystaniem z taksówki i jazdą własnym samochodem. Oba te samochody dowożą nas do celu, ale jedna z metod wymaga znacznie więcej pracy. Na szczęście metody ustawiania właściwości są nieco bezpieczniejsze i mniej wpływają na poziom adrenaliny niż typowa przejażdżka taksówką.
DEMO
Metody ustawiania właściwości pozwalają na zdefiniowanie obiektu i właściwości do mo-
W SIECI
dyfikowania, a biblioteka będzie zmieniała tę wartość dla nas. W przypadku tego przykładu kod w konstruktorze może być uproszczony do zamieszczonego poniżej; znajduje się on w programie demonstracyjnym MylntAnimPS na witrynie W W W : public MylntAnimPSO { // Konfiguracja animacji Animator anim = P ropertySetter.createA nim ator(1000, t h i s , "m ylnt", 0 , 10); a n im .s ta r t();
412
R o z d z ia ł 1 5 .
M e t o d y u s t a w ia n ia w ł a ś c iw o ś c i
B ib l io t e k a T i m i n g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
Należy zauważyć, że ta wersja nie ma implementacji timingEvent (), ponieważ funkcje te są wbudowane w sam obiekt PropertySetter. Oznacza to, że nasz kod tylko ustawia w obiek cie P ropertySetter, co należy zmieniać oraz w jaki sposób, a obiekt wykona resztę za nas Aby obsłużyć tę funkcję, metody ustawiania właściwości mają kilka ważnych ograniczeń Większość z nich jest związana z używanym mechanizmem — refleksją. Metody ustawiania właściwości przechowują przekazane wartości i tworzą mechanizm wywołania zwrotnego w obiektach wskazanych za pomocą refleksji. M echanizm ten wymaga poczynienia kilku ważnych założeń na temat podanych właściwości i obiektów. Przede wszystkim system musi mieć dostęp do obiektów i właściwości, z czego wynika kilka poniższych uwag.
Znane typy Wartości przekazywane do PropertySetter muszą być typu znanego systemowi. System obecnie zna różne typy wbudowane, takie jak wszystkie typy proste oraz ich odpo wiedniki obiektowe: i nt oraz Integer, fl oat i FI oat i tale dalej; żna również kilka mniej często stosowanych typów GUI, takich jak Point, Dimension i Rectangle. Jeżeli dostarczy my wartości o typach nieznanych systemowi, to w czasie działania aplikacji PropertySetter zgłosi on wyjątek. W takim przypadku musimy zapewnić systemowi mechanizm inter pretowania tego typu — należy udostępnić odpowiedni obiekt Evaluator, który zosta nie przedstawiony później. Teraz przedstawimy klasy używane w metodach ustawiania właściwości. W szczególności przedstawimy samą klasę PropertySetter, Eva! uator oraz KeyFrames i związane z nią ldasy.
Dostęp publiczny Musimy mieć dostęp publiczny do obiektów. Ponieważ P ropertySetter będzie wywo
PropertySetter
ływał obiekty z różnych pakietów, obiekt musi mieć zdefiniowany dostęp pozwalający na wykonanie wywołania. Jeżeli przekażemy obiekt prywatny do PropertySetter, to sys tem nie będzie miał możliwości uzyskania potrzebnych inform acji z powodu upraw nień dostępu.
Klasa P ropertySetter jest główną ldasą, z którą współpracujemy przy korzystaniu z metod ustawiania właściwości w Tim ing Framework. Klasa ta pozwala deldarować obiekty i wła■ ściwości do modyfikowania oraz sposoby zmiany tych właściwości w czasie. Można zadeMarować osobny obiekt Animator do definiowania parametrów animacji, ale PropertySetter
M etoda ustawiająca W łaściwość musi m ieć nazwę dostępną poprzez publiczną metodę s e t * ( ) w stylu ' JavaBean. W tym przykładzie z właściwością "mylnt" zakładamy, że PropertySetter ' znajdzie w obiekcie th is metodę setM y ln t(in t). Jeżeli taka metoda nie zostanie znale ziona w tym obiekcie w czasie konfigurowania mechanizmu refleksji dla przyszłych wy wołań tej metody, w PropertySetter wystąpi błąd.
Metoda pobierająca Potrzebna będzie również metoda g e t* (). Jedno z zastosowań PropertySetter wymaga tylko jednej wartości dla naszej zmiennej, w przeciwieństwie do dwóch wartości w po wyższym przykładzie. Podanie tylko jednej wartości informuje system o konieczności użycia bieżącej wartości właściwości, ustawionej w momencie uruchamiania animacji, jako jej wartości startowej. Aby to wykonać, system musi być w stanie wywołać odpowied nią metodę get* () dla właściwości, co pozwala odczytać bieżącą wartość. Jeżeli na przy kład podamy tylko wartość końcową 10 dla mylnt, tak jak w poniższym przykładzie: Animator anim = PropertySetter.createAnimator(1000, th is, "mylnt", 10); to P rop ertySetter będzie oczekiwał, że w th i s znajdzie metodę: public in t getMylntf)
posiada również przedstawioną wcześniej użytkową metodę factory createAnimator() do two rzenia zarówno P ropertySetter, ja k i Animator, które są potrzebne do sterowania animacji. PropertySetter implementuje interfejs Ti mi ngTarget, który definiuje sposób obsługi zdarzeń synchronizacji z synchronizowanego obiektu Animator w celu modyfikowania właściwości.
Konstru który W Masie PropertySetter dostępne są trzy konstrulctory oraz trzy równoległe metody factory. P ro p erty S etter(Object o b je c t, String propertyName, T . . . params) Konstruktor ten oczekuje obiektu zawierającego właściwość do zmodyfikowania, nazwę wła ściwości do modyfikowania oraz listę wartości. Dziwna notacja T wskazuje na typ ogólny, czyli funkcję dostępną w języku Java od JD K 5.0. Kolejną zastosowaną tu funkcją J2SE 5.0+ jest notacja
. . ” oznaczająca zmienną liczbę argumentów. Zmienne liczby argumentów
mogą być znane starym wyjadaczom C i C++, ale w języku Java funkcja ta została wpro wadzona w wersji J2SE 5.0. Te dwie funkcje połączone razem pozwalają na przekazywanie dowolnej liczby parametrów o dowolnych typach. Częścią tego systemu jest mechanizm interpretowania dowolnych typów danych, co jest realizowane przez Masę Eval uator, letóra zostanie przedstawiona w dalszej części rozdziału.
413
R o z d z ia ł 15.
414
M eto d y
B ib l io t e k a T im in g F r a m e w o r k . F u n k cje z a a w a n s o w a n e
u st a w ia n ia w ł a śc iw o ś c i
PropertySetter(Object object, String propertyName, Evaluator evaluator, T . .. params)
Przykładem wykorzystania tego konstruktora może być przypadek, w którym korzystamy z naszego przykładu MylntAnimPS, i chcemy, aby metoda ustawiania właściwości ustaliła właściwość mylnt, typu całkowitego, pomiędzy wartościami 0 i 10. Konstruktor można wy.
Ten konstruktor jest dokładnie taki sam jak poprzednio, poza tym, że dodatkowo przeka
wołać w następujący sposób:
zywany jest obiekt Eval uator. Klasa ta jest przekazywana, gdy chcemy zapewnić własny
new P ro p e rty S e tte r(th is, "m ylnt", 0 , 10);
,
W arto skupić się na liczbie przekazanych wartości. W typowej animacji są to dwie warto
mechanizm obliczania wartości pomiędzy wartościami przekazanymi jako params. Jednym z ważnych powodów przekazywania własnego obiektu Eval uator jest zapewnienie możliwo
ści — wartość, od której rozpoczyna się modyfikowanie właściwości, oraz wartość, do któ
ści interpolacji pomiędzy typami, które nie są znane przez bibliotekę. Możliwym zastoso
rej przebiega animacja. W najprostszym przypadku wykorzystywana jest pojedyncza war
waniem własnej klasy Eval uator jest także zapewnienie innego sposobu obliczania wartości pośrednich niż dostępny w bibliotece.
tość, która będzie wartością końcową, natom iast wartość początkowa będzie określana dynamicznie w czasie rozpoczęcia animacji. Możliwe jest również przekazanie trzech lub więcej wartości. Co mogą oznaczać te dodatkowe wartości?
Klasa Evaluator będzie opisana dokładniej w dalszej części rozdziału. Na razie wystarczy powiedzieć, że Eval uator zapewnia metody obliczania wartości, które znajdują się pomię
W iele wartości w konstruktorze PropertySetter oznacza, że właściwość będzie przyjmo
dzy wartościami dostarczonymi w konstruktorze.
wała kolejno te wartości w czasie animacji, przechodząc od jednej wartości do kolejnej. Odstęp czasu pomiędzy wartościami jest równy. Jeżeli na przykład zostaną przekazane trzy
PropertySetter(ja v a . 1a n g .0bject object,
wartości, właściwość rozpocznie od pierwszej, przy ułamku animacji równym 0; osiągnie
String propertyN am e, KeyFrames keyFrames)
drugą wartość w połowie czasu trwania anim acji, przy ułamku anim acji równym 0,5, a wartość końcową osiągnie na końcu, przy ułam ku, animacji równym 1. Ten sposób działania jest przedstawiony na rysunku 15.7. n e w P r o p e r ty S e tte r (o b j, p ro p ,
Ten ostatni konstruktor jest najbardziej zaawansowany i elastyczny, ponieważ pozwala przekazać strukturę KeyFrames zamiast zwykłych wartości. Mechanizm realizowany przez KeyFrames jest przedstawiony szczegółowo w dalszej części rozdziału. W sierocie KeyFrames zapewnia mechanizm pozwalający opisać nie tylko wartości, jakie właściwości powinny
10,20,100);
przyjmować w czasie animacji, ale również czasy, w których są te wartości i sposób inter t=
t = 0,5
0,0
t = 0,75
t =0,25
polacji pomiędzy tymi wartościami. P ro p erty S etter korzysta wewnętrznie ze struktury KeyFrames. W pozostałych konstruktorach, które nie korzystają z obiektu KeyFrames, przyj mowanych jest więcej założeń na temat elementów KeyFrames, a wynikowa animacja jest
v_||,. I p rop
= 10
przez to prostsza. Bardziej skomplikowane animacje mogą być tworzone przy wylcorzysta-
1 1 i
!
= 15
prop prop
; niu własnego obiektu KeyFrames. Na przykład parametr KeyFrames jest ważny przy tworzeniu animacji wieloetapowych nie tylko z wartością początkową i końcową.
= 60
= 20
Metody factory prop
Rysunek 15.7. PropertySetter z trzema wartościami przekazanymi w konstruktorze
Na rysunku 15.7 pokazane jest, w jaki sposób prop przyjmuje wartości 10, 20 oraz 100,
W klasie PropertySetter dostępne są trzy metody factory, które są odpowiednikami opisa nych wcześniej konstruktorów, ale z jedną ważną różnicą — posiadają one parametr durati on i zwracają obiekt Animator. Wywołanie tych metod factory jest odpowiednikiem wywoła
w momentach równo dzielących czas trwania. Zmienna prop przyjmuje wartość 10 w czasie
nia jednego z konstruktorów P ropertySetter, a następnie utworzenia obiektu Animator za
t = 0, 20 przy t = 0,5 oraz 100 przy i = 1. Możemy również zobaczyć, że prop przyjmuje
pomocą prostego konstruktora i przekazania do niego parametrów duration i TimingTarget.
wartości liniowo interpolowane w czasie pomiędzy wartościami od 0 do 0,5 oraz od 0,5 do 1,0. Jest to domyślne działanie interpolacji dla prostego przypadku, gdy P ropertySetter
W tym przypadku obiekt P ro p erty S etter utworzony w metodzie factory jest ustawiany
jest utworzony przy użyciu tylko dwóch wartości. W dalszej części rozdziału pokażemy, w jaki sposób można zmienić to domyślne działanie interpolacji3. 3 Brawo dla wszystkich, którzy zgadli, że będzie tu stosowana Masa Interpol ator.
w obiekcie Animator. Aby na przykład animować właściwość mylnt obiektu th is, od 0 do 10 w czasie jednej sekundy, możemy skorzystać z takiego fragmentu kodu: PropertySetter ps = new P ro p e rty S e tte r(th is, "mylnt", 0, 10); Animator anim = new Animator(1000, p s); a n im .s ta r t();
R o z d z ia ł 1 5 .
416
B i b l io t e k a T im i n g F r a m e w o r k . F u n k c j e z a a w a n s o w a n e
M e t o d y u s t a w ia n ia w ł a ś c iw o ś c i
lub taldego: Animator anim = P ropertySetter.createA nim ator(1000, t h i s , "mylnt“, 0 , 10); a n im .s ta r t();
Spójrzmy teraz, jak można obsłużyć te same funkcje w SetterRace. Poniżej mamy operację utworzenia obiektu Animator w konstruktorze:
animator = PropertySetter.createAnimator(RACE_TIME, basicGUI.getTrack(), "carPositłon", ' '• TrackView.START_P0S, TrackView.FIRST_TURN_START);
Nie ma różnicy w funkcjonowaniu obiektów utworzonych na oba sposoby; metoda fac tory jest dostarczana w celu ułatwienia stosowania w przypadku często wykorzystywanych
fi "■ ' 1 , . '-uV
-vr
To wszystko. Utworzyliśmy tu obiekt PropertySetter przy użyciu następujących elementów:
przypadków.
*
M etody Tim in gTarget
race_ time
— czas trwania animacji,
o basicGUl.getTrack()— obiekt, którego w łaściw ość będzie modyfikowana,
Pozostałe metody w PropertySetter pochodzą z interfejsu Ti mi ngTarget. Mówiąc dokład
o "carPosition" — nazwa w łaściw ości, którą chcem y animować,
niej, nadpisują one metody klasy Ti mi ngTargetAdapter, po której dziedziczy PropertySetter:
o
start_ pos
oraz
first _ turn_ start
,
— w artość początkowa ,i końcowa animacji.
Resztą zajmuje się PropertySetter, automatycznie obliczając i ustawiając wartość carPosition w czasie trwania animacji.
void begin() void tim ingE vent(float fra c tio n ) M etody te nie są przeznaczone do wykorzystywania przez kod aplikacji, ale raczej przez obiekty Animator, które korzystają z tego obiektu P ro p erty S etter jako TimingTarget. Metody te zapewniają uruchomienie wszystkich informacji konfiguracyjnych przekazanych
Evaluator
*
do konstruktora P rop ertySetter lub jego metod factory i modyfikowania właściwości Eval uator to prosta klasa pozwalająca obliczać wartości pośrednie dla wybranego typu:
w czasie animacji.
public ab stra ct c la s s Evaluator { Evalu ato r( ) ; a b stra ct T evaluate(T v0, T v l, flo a t f r a c tio n ); ' }
Demonstracja — SetterRace I DEMO j W SIECI
Spójrzmy teraz, jak zastosowanie metod ustawiania właściwości wpłynie na program demonstracyjny.animujący tor -wyścigowy, który przedstawiliśmy w rozdziale 14. Ta wersja jest
Klasa ta jest wykorzystywana przez opisaną wcześniej klasę PropertySetter oraz przedsta
dostępna na witrynie W W W książki, w projekcie SetterR ace,.
wioną dalej KeyVal ues do obliczania wartości pomiędzy wartościami granicznymi w czasie
W porównaniu z początkowym programem BasicRace, W którym konfigurowanie i uru chamianie aplikacji wymagało utworzenia obiektu animatora w konstruktorze:
wartości Point określające początkowe i końcowe położenie samochodu. Za obliczenie
działania animacji. SetterRace na przykład w aplikacji PropertySetter przyjmuje dwie wartości pośrednich właściwości carPosition w czasie animacji jest odpowiedzialny obiekt
animator = new Animator(RACE_TIME, t h is ) ;
Eval uator, który może interpolować wartości pomiędzy wartościami Poi nt.
oraz zmiany położenia samochodu w metodzie timi ngEvent (): Point sta rt = TrackView.START_POS; •■ Point end = TrąckVieW.FIRST_TURN_START; Point cu rren t.= new Point( ) ;
f
!
,
• ■, •
public void timingEvent(filoat fractio n ) { current-.x = (in t) (s ta r t.x + (end.x - s ta r t.x ) * fra ctio n ); current.y,= (in t) (s ta r t, y + (end.y - s ta r t.y ) * .fractio n );' tra ck . setCarPosi t i on (cu rren t);
W systemie jest dostępnych lulka klas Eval uator, które pozwalają na operowanie na wielu podstawowych typach wykorzystywanych w GUI oraz kodzie animacji. Obsłużone są typy proste: in t, long, short, f lo a t, double oraz byte, jak również wiele typów wykorzystywa nych często przez programistów GUI, na przykład RectangleŻD, Point2D, Dimension i Color. Każdy obiekt Eval uator wykonuje prostą interpolację liniową pomiędzy wartościami o poda nym typie: v = v0 + ((v l - v0) * fra c tio n ) i Poniżej przedstawiona jest implementacja metody eval uate () z ldasy Eval uatorFl oat, która jest wywoływana przez system w przypadku konieczności interpolowania wartości zmien noprzecinkowych:
Ditnension2D value = (Dim ension2D)v0.clone(); v alu e.setSize(w , h ); return value; }
uziate 14. przedstawiliśmy ogoiny m ecnanizm pozwalający na ciowome interpolacje, In terp o lato r, ale Eval uator zapewnia alternatywny sposób na realizację własnej interpo lacji. Gdy mamy dwie wartości i ułamek, nasza implementacja może zwrócić dowolny wynik. Zwykle obiekty Eval uator są dostarczane automatycznie przez bibliotekę. Gdy Property
Więcej wbudowanych klas Eval uator można odnaleźć w kodzie źródłowym projektu Timing Framework, który jest dostępny na witrynie W W W książki4. Istnieją dwa przypadki, w których zachodzi potrzeba napisana własnej klasy Eval uator: ® system nie ma wsparcia dla używanego typu, « chcem y wykonać własne wyliczenie wartości pewnego typu.
S e tte r jest tworzony dla wartości danego typu, system wyszukuje obiekt Eval uator, który r pozwala na interpolację pomiędzy wartościami tego typu. Jeżeli użyjemy typu nieznane go bibliotece lub chcemy z pewnych powodów użyć własnej implementacji Eval uator, można skorzystać z konstruktora P ro p erty S etter łub metody factory, która ma jako ar gument obiekt Eval uator. Podobnie można dostarczyć własny obiekt Eval uator do metody KeyVal u es. cre a te () , która zostanie przedstawiona w dalszej części rozdziału, aby obiekt «■' KeyVal ues korzystał z naszego obiektu, a nie domyślnego, dostarczonego przez bibliotekę.
N ow y typ Evalu ato r Choć system obsługuje wiele typów wbudowanych, może nie wspierać typu, który jest nam potrzebny. Na przykład obecnie system nie obsługuje typu AffineTransform, więc jeżeli
KeyFrames R am ka kluczow a jest terminem z tradycyjnej animacji, który definiuje stan obiektu w okre
potrzebna będzie interpolacja pomiędzy wartościami transformacji obiektów, można napisać
ślonym punkcie czasu. W dowolnym punkcie pomiędzy dwoma ramkami stan obiektu
własną klasę Eval uator dla KeyVal ues, która będzie wywoływana przez system do oblicze
może być interpolowany na podstawie stanu sąsiednich ramek kluczowych. Załóżmy, że
nia pośrednich wartości Af f i neTransform:
chcemy animować Księcia pomiędzy dwoma ramkami kluczowymi definiowanymi dla czasu
c la s s EvaluatorTransform extends Evaluator { public AffineTransform ev aluate(AffineTransform v0, AffineTransform v l, flo a t fra c tio n ) { // Tutaj kod interpolacji }
t = 0 oraz t = 1, dla których mamy określone położenie i obrót. Obliczanie położenia i obrotu Księcia w dowolnym czasie pomiędzy tymi ramkami kluczowymi jest proste. Na rysunku 15.8 przedstawiona jest wyliczona ramka dla t = 0,5. W bibliotece Timing Framework każda ramka kluczowa definiuje czas od 0 do 1 w animacji oraz wartość skojarzoną z tym czasem. Struktura KeyTimes przechowuje czasy, a KeyVal ues wartości, natomiast obiekt KeyFrames łączy w sobie te obiekty KeyTimes oraz KeyVal ues. Struktury te współpracują z mechanizm ami ustawiania właściwości. W artości zmieniane w czasie są wpisywane do właściwości, natomiast czasy odpowiadają tym momentom ani
4 Tak naprawdę wszystkie wbudowane klasy Eval uator wyglądają tak samo jak pokazane poniżej. Oczekują one wartości granicznych pewnego typu oraz ułamka, a następnie obliczają interpolację liniową w sposób odpowiedni dla tego typu.
macji, dla których właściwość powinna osiągnąć skojarzone wartości. Jeżeli w czasie ani macji bieżąca wartość ułamka jest równa jednej z wartości czasu ze struktury KeyTimes,
R o z d z ia ł 1 5 .
B ib l io t e k a T i m i n g F r a m e w o r ic F u n k c je 7_a a w an s o w a n e
M e t o d y u s t a w ia n ia w ł a ś c iw o ś c i
421
Ramka kluczowa 1
Ramka kluczowa 0 t = 0,0
t = 0,5
t = 1,0
położenie = (0 ,0 )
położenie = (5 0 ,0 )
położenie = (10 0 ,0 )
obrót = 0
o b rót= 4 5
obrót = 90
Rysunek 15.8. Interpolowana pozycja i obrót przy t = 0,5 pomiędzy ramkami kluczowymi dla t = 0 oraz t = 1
to właściwość obiektu powinna mieć przypisaną odpowiednią wartość z KeyVa1ues. Jeżeli bieżący ułamek ma wartość znajdującą się pomiędzy dwoma czasami w strukturze KeyTimes, to wartość zostanie interpolowana na podstawie dwóch sąsiednich czasów. Istnieje jeszcze jeden element, który powoduje, że klasa KeyFrames jest bardzo efektywna i elastyczna — In terp o lato r. Dla każdego okresu zdefiniowanego w strukturze KeyTimes istnieje skojarzony obiekt In terp olato r. Podobnie jalc w przypadku klasy Animator, do
to = 0,0
m-l
n -1
V l
V n -1
t„ = 1,0
Rysunek 15.9. Obiekt KeyFrames jest definiowany przez czasy (t), wartości (v) i interpolatory (interp). Trzeba pamiętać, że odstępy czasu nie muszą być równe
t = = = = x (f)
(f - t .) / (.7 5 - .5) (.2 5 / .5) .5 = x..,+ t * = 20 + .5 =20+40 = 60
( t - t .) / (1 - .5)
(x„ - X,.,) * (100 - 20) •
myślnym obiektem In terp o lato r dla każdego przedziału jest L in earln terp olator. Jednak obiekt KeyFrames może korzystać z różnych obiektów In terp o lato r dla swoich przedzia
Jedną z zaawansowanych funkcji KeyFrames jest możliwość modyfikowania interpolacji dla
łów, co pozwala na tworzenie interesujących animacji.
każdego odstępu czasu. Powyższa interpolacja jest domyślnym działaniem, jeżeli nie zostanie zadeklarowana inna, ale tworząc obiekt KeyFrames można skorzystać z obiektów
Na rysunku 15.9 przedstawiliśmy obiekt KeyFrames jako serię par czas-wartość, razem
Interpol ato r oraz Eva! uator do modyfikowania sposobu działania.
z obiektami Interpolator, które definiują sposób interpolowania wartości pomiędzy poda nymi czasami.
Ki asy pom ocnicze — Key Values, KeyTim es, Evalu ato r oraz Interpolator
Jalc wcześniej wspomnieliśmy, w obiekcie KeyFrames domyślnie wykorzystywana jest inter
Aby lepiej poznać klasę KeyFrames, przydane będzie zrozumienie działania klas wchodzą
polacja liniowa. Tak więc dla dowolnego ułamka f pomiędzy 0 i 1, gdzie f znajduje się
cych w jej skład i sposobu ich współpracy ze sobą, zgodnie ze schematem z rysunku 15.10.
między czasami t n.j, a t nw obiekcie KeyTimes, natomiast xn_x i xn są wartościami w obiekcie KeyValues odpowiadającymi t ^ oraz t n, możemy obliczyć odpowiednią wartość x (f) dla właściwości w momencie f w następujący sposób: t = ( f - t.) / (t„- t„.,); x (f) = x„.,+ t * (x„— x,.,); Jest to właśnie obliczenie wykonywane na rysunku 15.7. Dla f = 0,75 otrzymujemy war tość t n_j równą 0,5, t n = 1 oraz wartości xn. x i xnrówne odpowiednio 20 i 100. Mamy więc następujące równania:
Na rysunku 15.10 przedstawiony jest sposób przepływu danych w systemie w czasie anima cji. Obiekt Animator wysyła zdarzenie synchronizacji do PropertySetter, który jest jednocze. śnie typu TimingTarget. Obiekt PropertySetter korzysta wewnętrznie z obiektu KeyFrames, nawet jeżeli obiekt PropertySetter nie został jawnie zadeklarowany dla obiektu KeyFrames. Obiekt KeyFrames jest odpytywany w celu uzyskania odpowiedniej wartości dla upływają cej części animacji f. W obiekcie KeyFrames przy użyciu KeyTimes, KeyValues, Evaluator oraz Interpol ato r jest obliczana i zwracana prawidłowa wartość. W artość ta jest następnie . wysyłana do odpowiedniej metody ustawiającej w obiekcie, w którym został utworzony ! PropertySetter.
R o z d z ia ł 1 5 .
422
:
M e t o d y u s t a w ia n ia w ł a ś c iw o ś c i
B ib l io t e k a T im i n g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
•
tim in g E v e n t(f) P r o p e r t y S e tte r
A
s e t P r o p e r t y (v )
.........
:
Można na przykład utworzyć obiekt KeyValues przechowujący liczby całkowite 1, 2 i 3 w następujący sposób:
O b je c t
—y
"p ro p e rty "
KeyValues values = KeyValues.c r e a t e f l , 2, 3 );
..
v = g e tV a lu e ( f)
Powodem użycia składni w deklaracji metody jest wykorzystanie w metodzie typów
___________ Y
ogólnych do utworzenia obiektów KeyVal ues odpowiedniego typu, w zależności od typu
K e y Fra m e s
parametrów użytych w wywołaniu. Jedną z alternatyw niewylcorzystujących typów ogólnych mogło być utworzenie pojedynczej klasy KeyValues przechowującej wartości Objects, które K e y T im e s
V A
K e y T im e s
V ”' Vn
In te r p o la to rs
!0
należałoby rzutować i wykorzystywać wywołania i nstanceof w czasie działania aplikacji,
'n-1
aby określić rodzaj przechowywanych obiektów. Inną możliwością jest utworzenie wielu Idas pochodnych i konstruktorów KeyVal ues, które są specyficzne dla typów. Typy ogólne pozwalają zrealizować taką samą funkcję, co wersja ze specyficznymi typami, ale bez prze
E v a lu a t o r
ciążania API. Musieliśmy sobie tylko poradzić ze składnią , aby to osiągnąć. I■ ’Ti’;1
**"',;"'"i"yir,i,^',i'iyi| v-^i;x"i'iti'Fuł.-iTH t-iv;1
^ll^
-‘"i
Rysunek 15.10. Przepływ danych w czasie animacji
Jednym z mechanizmów wykorzystywanych w klasie KeyVal ues jest inna funkcja JD K 5.0, 0 nazwie a u to b o x in jf, pozwalająca na wybór najbardziej odpowiedniego typu dla przeka zywanych wartości. Autoboxing daje nam możliwość przekazywania na przykład parame
Sposób działania klas Eval uator i Interpol ato r został już opisany. Zajmiemy się teraz do
trów typu i nt, które automatycznie są rzutowane na typ obiektowy Integer7. Akcja ta nie po
datkowymi łdasami pomocniczymi wchodzącymi w skład KeyFrames oraz sposobami zapi
winna m ieć wpływu na nasz kod. M ożna przekazać wartości zarówno typu in t, ja k
sywania i odczytywania niezbędnych informacji.
1 Integer; wartości te będą wykorzystane w zależności od kontekstu jako i nt i Integer. Jednak to niejawne użycie autoboxingu pomaga wyjaśnić tło pewnych szczegółów konwersji typów.
KeyVa1ues KeyVaI ues to klasa pozwalająca na przechowywanie dowolnej liczby wartości dowolnego typu.
Głównym elementem, o którym należy pamiętać w odniesieniu do tej metody, jest koniecz ność zachowania identycznych typów. W przeciwnym razie system może źle zinterpreto wać nasze zamiary. Możemy na przykład próbować utworzyć taki sam obiekt KeyVal ues jak
\1 / ¡f
Wskazówka Wszystkie wartości w obiekcie KeyVa1ues muszą być tego samego typu. Tworzenie KeyValues z obiektami różnych typów może prowadzić do problemów, ponieważ system nie będzie „wie dział”, jak interpolować wartości ogólnego typu bazowego.
poprzednio, z wartościami 1, 2 oraz 3, alé jedną z wartości przekazać jako wartość doubl e: KeyValues values = KeyValu e s .c r e a t e fl, 2 , 3 .0 ) ; W wyniku nie otrzymamy obiektu KeyValues zawierającego wartości in t. Nie otrzymamy również obiektu zawierającego wartości doubl e. Otrzymany obiekt będzie zawierał obiekty
Obiekt KeyVal ues można utworzyć za pomocą jednej z dwóch metod factory: s t a t i c KeyValues c r e a t e ( T ... params)
typu Number. Obiekt KeyVal ues automatycznie wybiera najbardziej ogólny typ obiektowy, który może przechować każdy z parametrów. W tym przypadku wartości i nt zostały upa kowane w obiektach Integer, a double w Double. Wspólną klasą nadrzędną jest Number,
Składnia z zastosowaniem typów ogólnych () jest myląca dla wielu osób5. Na szczęście
więc ten typ zostanie wybrany przez kompilator jako typ tworzonej instancji KeyVal ues.
nie ma konieczności rozumienia sposobu działania typów ogólnych, aby skorzystać z tej
Taki obiekt KeyVal ues nie je st prawdopodobnie takiego typu, jakiego byśmy
metody. W wywołującym kodzie w istocie nie występuje wcale składnia typów ogólnych. 5 Osobiście nie uważam, aby typy ogólne pozwoliły zwiększyć czytelność kodu. Jednak znacznie pomagają one tworzyć zwarte API, w którym nie jest potrzebne tworzenie wielu ldas pochodnych dla różnych typów danych. Więcej informacji na temat typów ogólnych można znaleźć w dokumentacji środowiska J2SE 5.0, w którym funkcja ta została po raz pierwszy wprowadzona: http://java.sun.eom/j2se/l.5.0/docs/guide/
language/generics.html.
6 http://java.sun.eom/j2se/l.5.0/docs/guide/language/autoboxing.html. 7 Praca bez autoboxingu była czasami niezwykłe kłopotliwa. Wszyscy oprócz kompilatora „wiedzieli”, że i nt odpowiada typowi Integer. Teraz kompilator również „potrafi to stwierdzić”.
R o z d z ia ł 1 5 .
B i b l i o t e k a T i m i n g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
M e t o d y u s t a w i a n i a w ł a Sc i w o S c i
oczekiwali. W szczególności obiekt ten może nie może wykonać żadnych użytecznych
stosowanych typów danych8. Jednak mogą zdarzać się przypadki, w których nasza aplikacja
operacji na typach wynikowych, ponieważ może nie być dostępnej klasy Eval uator, która
będzie musiała użyć typu nieznanego w systemie lub konieczne będzie dostarczenie ldasy
może interpolować wartości tego ogólnego typu.
Eval uator, która wykona zadanie interpolacji między typami. W każdym z tych przypadków konieczne jest przekazanie własnego obiektu Eval uator do KeyVal ues.
\ I/
Wskazówka
- ( jp ~ ip
Nie istnieje klasa Evaluator dla wartości typu Number. Należy upewnić się, że przekazane wartośclsą takiego samego typu, chyba że dostarczymy do obiektu KeyValues Evaluator, który będzie interpolować wartości typu nieobsługiwanego przez system.
KeyTimes KeyTimes to bardzo prosta Masa, szczególnie w porównaniu ze szczegółami obsługi typów w KeyValues. W obiektach KeyTimes przechowywane są kolekcje wartości zmiennoprze
Rozwiązaniem jest utworzenie obiektów KeyValues z param etrami tego samego typu, W przypadku poprzedniej sytuacji możemy skorzystać z wywołania: // zwraca KeyValues KeyValues values = KeyValues.c r e a t e ( l, 2, 3 );
cinkowych, reprezentujących czasy, w których wartości z KeyValues powinny zostać użyte w KeyFrames. Istnieje kilka ważnych ograniczeń, które warto przedstawić. Czasy są ułam kam i Wszystłde wartości czasu są podawane w zakresie [0,1] i reprezentują ułamek czasu
lub
trwania animacji. Jeżeli na przykład mamy obiekt Animator o 3-sekundowym czasie // zwraca KeyVałues KeyValues values = K eyV alues.create(1 .0 , 2 .0 , 3 .0 ) ;
ale nie // zwraca KeyValues KeyValues values = K eyV alues.create(1 , 2, 3 .0 ) ; Na koniec warto wspomnieć, że jeżeli obiekt KeyVal ues jest używany do operacji na właści
trwania, to wartość keyTime równa 0,5 reprezentuje 1,5 sekundy tej konkretnej anima cji. Jeżeli jednak użyjemy tej samej struktury KeyTimes dla obiełetu Animator z czasem trwania równym 10 sekund, to wartość 0,5 reprezentuje 5 sekund animacji. Czasy m onofonicznie rosną W artości KeyFrames przesuwa się w przód w czasie, a obiekt KeyTimes odzwierciedla to ograniczenie.
wości przypisanej w PropertySetter, to typy zastosow an e w KeyValues powinny być takie same jak typ tej właściwości. Tale więc, jeżeli mamy właściwość typu Dimensi on, powinniśmy
Czasy zaczynają się od 0 i kończą na 1
utworzyć obiekt KeyValues z parametrami typu Dimension. Podobnie, jeżeli mamy właści
Obiekt KeyFrames musi „wiedzieć”, co należy robić w dowolnym momencie czasu po
wość typu i nt lub Integer, należy utworzyć obiekt KeyVal ues z wartościami i nt lub Integer.
między 0 a 1 włącznie, tale więc muszą istnieć czasy i związane z nim i wartości dla
Wymieszanie wartości lub użycie wartości double nie będzie odpowiednie w takiej sytu
punktu początkowego i końcowego. Na przykład struktura KeyTimes z tylko dwoma wpisami musi zawierać czasy dla punktu O i l .
acji. W przypadku braku dopasowania system może niewłaściwie wywołać metodę usta wiania właściwości, ponieważ nie będzie mógł znaleźć metody, która przyjmuje wartość typu; przechowywanego w KeyVal ues. Druga metoda factory dla KeyVal ues jest dosyć podobna, ale posiada dodatkowy parametr: s t a t i c KeyValues create(E v alu ato r evalu ator, T . . . params) Parametr Evaluator pozwala określić sposób interpolacji między wartościami przekazanymi jako params, wykonywanej w obiekcie KeyVal ues. Klasę Eval uator opisywaliśmy wcześniej, przy okazji przedstawiania PropertySetter. T o wcześniejsze zastosowanie klasy Eval uator sprowadza się dokładnie do bieżącego zastosowania — PropertySetter tworzy wewnętrznie obiekt KeyValues i jeżeli dostarczymy Evaluator do P ropertySetter, to utworzy on obiekt KeyValues z tym obiektem Evaluator. W większości zastosowań możliwość ta prawdopo dobnie nie będzie potrzebna, ponieważ system posiada kilka Mas Eval uator dla najczęściej
Tu zaczyna się cała dyskusja na temat typów i uzyskania obiektu KeyValues przechowującego wartości odpowiednich typów. Jeżeli KeyVal ues nie może efektywnie określić typu parametrów, tale jak w przypadku (1, 2, 3.0), to może bezskutecznie szukać odpowiedniej klasy Evaluator dla tego typu. Na poziomie API zadaniem KeyValues jest przechowywanie wartości. Jest to tylko miejsce do przechowywania wartości ramek kluczowych. Jednak wewnętrznie obiekt ten jest używany do obliczania w czasie animacji wartości pośrednich. Jeżeli nie można określić typu, to nie można pobrać odpowiedniego obiektu Eval uator i nie można obliczyć wartości pośrednich. Jednak nie warto się tym przejmować. Najczęściej udaje się uniknąć problemów, a jeżeli się zdarzą, wystąpią w formie oczywistych błędów kompilacji, talach jak brak możliwości znalezienia obiektu Eval uator, lub błędów wywołania, talach jak brak możliwości znalezienia metody ustawiającej właściwość dla danego typu KeyValues. Jeżeli zdarzą się takie błędy, prawdopodobnie będziemy mogli zorientować się, co jest przyczyną.
426
R o z d z ia ł 15.
B ib l io t e k a T im in g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
M e t o d y u s t a w ia n ia w ł a ś c iw o ś c i
Liczba czasów musi równać się liczbie wartości Liczba punktów czasowych umieszczonych w strukturze KeyTimes musi zgadzać sj„ z liczbą wartości umieszczonych w strukturze KeyVal ues. Obiekt KeyTi mes kojarzy warto ści i czasy, więc oczekuje podania równej liczby każdej z nich. Konstruktor i jednocześnie jedyna metoda KeyTi mes są proste: public K eyTim es(float.. . times) Aby użyć ldasy KeyTimes, wystarczy wywołać konstruktor i przekazać czasy, w których mamy dane KeyFrame. Należy zwrócić uwagę na notację zmiennej liczby argumentów w tym kon struktorze, co odpowiada zmiennej liczbie parametrów w innych, przedstawionych wcze śniej metodach, i pozwala na przekazanie do konstruktora dowolnej liczby parametrów.
In te rp o la to r
-
Klasę In terp o lato r przedstawialiśmy już wcześniej, w kontekście ldasy Animator. Obiekt In te rp o la to r w Animator jest odpowiedzialny za interpolację ułam ka czasu animacji, Domyślnie w klasie Animator jest wykorzystana klasa Li nearlnterpol ator. Podobnie każdy interwał w animacji KeyFrame korzysta domyślnie z Li nearlnterpol ator, ale jest możliwe przekazanie alternatywnego obiektu I nterpol ator.
0
Czas (ułamek)
1
Rysunek 15.11. Animacja dyskretna od 2 do 6
Możemy utworzyć tę animację przy użyciu KeyFrames w następujący sposób: KeyValues keyValues = K eyV alues.create(2, 3 , 4 , 5, 6 ) ; KeyFrames keyFrames = new KeyFrames(keyValues, D isc re te ln te rp o la to r. w *g etln stance()) ; Należy pamiętać, że interpolacja dyskretna nie musi być wykonywana dla wartości se kwencyjnych, jak w tym przykładzie. Aby zobaczyć, w jald sposób używać ldasy Di sc re te -
Domyślne mechanizmy dostępne w KeyFrames interpolują pomiędzy przekazanymi warto
In terp o lato r do animowania pomiędzy wartościami niesekwencyjnymi, należy zapoznać
ściami, ale wykonują to w sposób liniowy. Jeżeli chcem y zmienić ten sposób działania,
się z programem demonstracyjnym D iscreteln terp olation dostępnym na witrynie W W W
konieczne jest przekazanie do KeyFrames innego obiektu Interpol ator.
poświęconej książce. Aplikacja ta konfiguruje obiekt KeyFrames w przedstawiony wcześniej sposób poza tym, że wartości nie są sekwencyjne:
Obiekty In te rp o lato r są wykorzystywane dla odstępów czasu pomiędzy czasami przeka zanymi w KeyTimes. Podobnie jak Interpol a to r określa sposób interpolowania czasu dla obiektu Animator, tak samo Interpol ator olei e~h sposób interpolowania upływającego czasu dla interwałów w KeyFrames. Obiekty KeyFrames mogą być utworzone z użyciem jednego obiektu Interpol ator, który będzie używany w odniesieniu do wszystkich interwałów, lub też ze zbiorem obiektów Interpol ator, których liczba jest równa liczbie interwałów. Każdy obiekt In terp o lato r realizuje interpolację w swoim zakresie w taki sposób, jakby lo by: pełny zakres animacji w zakresie [0 ,1 ]. Ab pokazać, w jaki sposób Interpol ato r operuje na interwałach, zajmiemy się programem dem onstracyjnym D iscre te ln te rp o l a to r. W rozdziale 14. pokazaliśmy, że interpolator ten zwraca wartość 0 w czasie anim acji i 1 po jej zakończeniu. Przy obsłudze interwałów KeyFrames interpolator efektywnie tworzy animację, która przechodzi w sposób dyskretny pomiędzy wartościami struktury KeyVal ues bez ich interpolowania. Załóżmy, że chcemy zrealizować animację, w której zmienna przeskakuje pomiędzy war tościami od 2 do 6, jak jest to pokazane na rysunku 15.11.
KeyValues keyValues = KeyValues.c r e a te (2 , 6 , 3 , 5, 4 ) ; KeyFrames keyFrames = new KeyFrames(keyValues, Di s c r e te ln te r p o la to r .g etIn stan ce( ) ) ; Obiekt Animator jest skonfigurowany do animowania tych wartości w czasie sekundy, przy użyciu obiektu P ro p erty S etter, który je st wywoływany w programie demonstracyjnym D iscreteln terp o latio n do ustawienia wartości intValue w czasie animacji: Animator anim = P ropertySetter.createA nim ator(1000, new D isc re te In te rp o la tio n (), "in tV alu e", keyFrames); a n im .s ta r t(); Metoda ustawiania właściwości dla i ntVal ue zapisuje nową wartość i wypisuje ją: public void s e tIn tV a lu e(in t intValue) { th is.in tV a lu e = intValue; System .ou t.p rin tln ("in tV alu e = 11 + in tV alu e);
R o z d z ia ł 15.
B ib l io t e k a T im in g F r a m e w o r k . F u n k c je
M eto d y
za a w a n so w a n e
u st a w ia n ia w ł a śc iw o ś c i
429
W ynik działania programu wygląda podobnie do zamieszczonego poniżej, z powielonymi
Konstruktory
pozycjami zamienionymi na [ . . . ]:
Dostępnych jest kilka konstruktorów KeyFrames, od prostego do kompletnego, które od zwierciedlają sposoby wykorzystania klasy KeyFrames przez programistów. W ewnętrz
intValue = 2 intValue = 2 [ ...] intValue intYalue intValue [ ...] intValue intValue intVa1ue intValue intValue intValue [•••] intValue intValue
nie wszystkie konstruktory tworzą te same informacje, które zostały zilustrowane na ry sunku 15.9 — serię czasów, wartości i interpolatorów. Różnica pomiędzy konstruktorami polega wyłącznie na tym, co KeyFrames przyjmie za wartość domyślną, a tym, co wywołu
= 2 = 6 =6
jący poda w parametrze. W najprostszym przypadku wywołujący może skorzystać z konstruktora, który wymaga
= 6 = 3 = 3
podania wyłącznie serii wartości w postaci obiektu KeyVal ues: public KeyFrames(KeyValues values)
= 3 = 5 = 5
W artości te odpowiadają (v„, . . . ,
v„) z rysunku 15.13. Czasy (t„,
...,
t„) domyślnie
odpowiadają równemu podziałowi interwału [0, 1], więc dla (n + 1) wartości każda wartość czasu t jest o ( l / n) większa niż poprzednia. Jeżeli wywołujący dostarczy na przykład trzy wartości (v0, v 1, v2), otrzyma odpowiednio czasy 0, 0 .5 i 1.0:
= 5 = 4
tQ = 0,0
t 1 = 0,5
t2 = 1,0
Należy zauważyć, że występują powielone wartości dla każdej wartości pośredniej, poza koń cową wartością 4. W postaci graficznej animacja wygląda ja k na wykresie z rysunku 15.12. A
F
11*-. 1
new KeyFram es(KeyValues,create(vO ,v1,v2));
Rysunek 15.13. Dane KeyFrames w prostym przypadku z trzema wartościami Domyślnym mechanizmem interpolacji dla tego konstruktora jest interpolacja liniowa, tak jak wcześniej wspomnieliśmy. Oznacza to, że do interpolacji wartości dla każdego z dwóch zdefiniowanych tu interwałów będzie używana klasa Li nearlnterpol ator. 0
Czas (ułamek)
1
Rysunek 15.12. Program demonstracyjny Discretelnterpolation — wartości w interpolacji dyskretnej nie muszą być sekwencyjne
Istnieje jeden specjalny przypadek warty przedstawienia. Możliwe jest zdefiniowanie obiektu KeyFrames z tylko jedną wartością. Aby być bardziej dokładnym, możliwe jest zdefiniowa nie obiektu KeyFrames korzystającegójz obiektu KeyVal ues z tylko jedną wartością w nastę pujący sposób:
Klasa KeyFrames
KeyFrames kf = new KeyFrames (keyVal u es. create (v) ) ;
Teraz, gdy wiemy, w jaki sposób działają elem enty KeyFrames, możem y pokazać, w jaki sposób współpracują ze sobą przy tworzeniu i działaniu obiektu KeyFrames.
k
430
R o z d z ia ł 15.
B ib l io t e k a T im in g F r a m e w o r k . F u n k c je
M eto d y
za a w a n so w a n e
Nie ma sensu korzystanie z obiektu KeyFrames zawierającego tylko jedną warLość, ponie
t0 = 0 ,0
u s t a w ia n ia w ł a śc iw o ś c i
431
t 1 = 0,1
t 2 = 0 ,8
t 3 = 1 ,0
waż obiekt ten pracuje na interwałach czasowych, a nie pojedynczych wartościach1'. W tv,n przypadku KeyFrames utworzy wewnętrznie interwał, zakładając pierwszy czas i wartość Jest to animacja „do”, w której dostarczamy tylko końcową wartość, do której będziemy animować. Początkowa wartość jest określana dynamicznie w m om encie rozpoczynania animacji. Podobny mechanizm przedstawialiśmy przy okazji obiektów PropertySetter z jedną wartością. W ewnętrznie przypadła te są takie same, ponieważ PropertySetter tworzy strukturę KeyFrames do przechowywania wartości właściwości wykorzystywanych
l-V . a ... ..... -
|1■. L, ■.
w czasie animacji.
u, .
..........................« ----- — ----------------------
.----------
J
new KeyFrames(KeyVaIues,create(vO, v 1 , v 2 , v3)), new KeyTimes(0, ,1 f , ,8 f, 1 ,0 f » ;
W skazów ka
Nie należy przesadzać. Warto przypomnieć, że choć konstruktory KeyFrames pozwalają na podanie dowolnej liczby wartości, to w typowym przypadku wykorzystywane są dwie wartości — wartość, od której animujemy, i wartość, do której animujemy. Możliwość przekazania więcej niż dwóch wartości przy użyciu magicznego mechanizmu języka pozwala w łatwiejszy sposób tworzyć animacje wieloetapowe — nie oznacza to jednak, że musimy to robić. Nie mamy nic
Rysunek 15.14. Tworzenie KeyFrames ż wieloma wartościami i czasami. Liczba przekazanych czasów musi być równa liczbie wartości
przeciwko tworzeniu prostych animacji z dwiema wartościami.
wywołujący konstruktor dostarcza zbiór obiektów Interpol ator do wykorzystania we wszyst
W pierwszym i drugim konstruktorze brak obiektów Interpol ator dla interwałów oznacza, że do każdego z nich zostaje przypisany domyślny obiekt Li nearlnterpol ator. W tej wersji kich interwałach. Te obiekty Interpol ator mogą obejmować wbudowane interpolatory typu
Następny konstruktor korzysta z tej samej struktury KeyVal ues, ale pozwala na przekaza
singleton Li nearlnterpol ator lub D iscreteln terpolator, instancje klasy Splinelnterpolator
nie czasów, w których te wartości powinny być przypisane do właściwości:
lub własnej klasy Interpol ator. Może to być albo jeden obiekt Interpol ator, który będzie
public KeyFrames(KeyValues keyValues, KeyTimes keyTimes) W tym konstruktorze liczba wartości w obiekcie keyVal ues musi odpowiadać liczbie czasów
wykorzystywany dla wszystkich interwałów, lub dokładnie o jeden obiekt mniej niż wy raża liczba wartości w KeyValues, ponieważ liczba interwałów jest o jeden mniejsza niż liczba wartości.
w obiekcie keyTimes. Ograniczenie to powinno być dosyć oczywiste na podstawie przed stawionych wcześniej informacji, ponieważ KeyFrames zawiera zbiór odpowiadających sobie
Tak jak w pierwszym konstruktorze posiadającym wyłącznie parametr KeyValues, wersja
par czas-wartość. Każda wartość w keyTimes rozpoczynająca się od 0, wzrastająca mono
ta oblicza rozmieszczony w równych odstępach czasu zbiór obiektów KeyTimes.
fonicznie i kończąca się na 1, jest czasem w cyklu animacji, któremu zostanie przypisana odpowiednia wartość keyVal ues. Na rysunku 15.14 przedstawiona jest ilustracja przykładowego obiektu KeyFrame z cztere ma parami czas-wartość. W interwałach pomiędzy każdym z czasów w keyTimes wartość jest interpolowana liniowo,
Ostatni, najbardziej elastyczny konstruktor łączy ze sobą wszystkie przedstawione elementy i pozwala na przekazanie wartości, czasów i interpolatorów: public KeyFrames(KeyValues values, KeyTimes times, In terp o lato r... ^ interp olators) Konstruktor ten jest dokładnie taki sam jak poprzedni, oczekujący wartości i interpolato
tak jak w poprzednim konstruktorze, za pomocą domyślnego obiektu Li nearlnterpol ator
rów, ale czasy są dostarczane jawnie w obiekcie KeyFrames zamiast obliczania równych odle
zKeyFrames.
głości. Wynikowy obiekt KeyFrames będzie podobny do przedstawionego na rysunku 15.9,
Trzeci konstruktor jest podobny do pierwszego, ponieważ są przekazywane tylko wartości,
interpolatorami (i nterp., . . . , i nterp..,).
z dostarczanymi przez wywołującego wartościami (v„, . . . ,
v„), czasami (t„
ale w tym wariancie dostarczany jest również zbiór interpolatorów do wykorzystania w interwałach: public KeyFrames(KeyValues values, I n te r p o la to r ... in te rp o la to rs) 9 Obiekt KeyFrame z tylko jedną wartością czas-wartość jest równie przydatny, jak jedna rękawiczka (nie dotyczy to gwiazd muzyki pop z innej planety), jedno nozdrze lub jeden łyk kawy. Po prostu to za mało.
&ła
'*
Metody KeyFrames W klasie KeyFrames poza konstruktorami dostępna jest tylko jedna metoda: in t g e tln te r v a l(flo a t fra c tio n )
...,
t.) oraz
432
R o z d z ia ł 1 5 .
B ib l io t e k a T i m i n g F r a m e w o r k . F u n k c je z a a w a n s o w a n e
M e t o d y u s t a w ia n ia w ł a ś c iw o ś c i
Jest to prosta metoda użytkowa, która zwraca interwał dla dowolnej podanej wartości z Za. kresu od 0 do 1. Czasami przydatne jest odpytanie obiektu KeyFrames w wieloetapowej ani. macji, aby móc zorientować się, który interwał animacji jest aktywny w danym momencie
Początkowe przyspieszenie — na początku wyścigu samochód rozpocżyna od prędkości
Metoda ta jest używana na przykład w programie demonstracyjnym Mul t i StepRace, który
Zakręty — wszystkie zakręty są wykonywane z taką samą dynamiką zwalniania, na po
teraz przedstawimy.
czątku i przyspieszania na zakręcie.
zerowej i przyspiesza do pełnej prędkości.
■
Proste — poza początkową prostą, gdzie samochód zaczyna od zatrzymania, samochód będzie zaczynał od nieco mniejszej prędkości na wyjściu z zakrętu, a następnie będzie przyspieszał.
Demonstracja — MultiStepRace DEMO W SIECI
Spójrzmy po raz os tatni na nasz program demonstracyjny z animacją toru wyścigowego, który k zmienimy, aby wykorzystać możhwośckklasy KeyFrames. Tym razem skorzystamy z możliwości tworzenia animacji wieloetapowych, ,aby samochód przejechał cały tor. Ta wersja programu znajduje się na stronie W W W w projekcie Mul t i StepRace. Podobnie jalc w poprzedniej wersji, SetterRace, do obsługi animacji wykorzystamy Property,Setter. Dodatkowo, talc samo jak w poprzedniej'wersji,« wszystkie,operacje ¡są umieszczone w części konfiguracyjnej obiektu Animator,; Przetwarzanie .animacji w czasie jej-.działania jest •
Końcowa prosta — chcemy, aby ha końcowej prostej samochód bardziej zwolnił. Powinniśmy pamiętać o jeszcze jednym elemencie dotyczącym różnych etapów wyścigu. Aby uzyskać większy realizm, należy upewnić się, że szybkość na końcu jednego etapu i na początku kolejnego jest zbliżona. Jeżeli tego nie dopilnujemy, uzyskamy wrażenie nieciągłości. Samochód może na przykład zwalniać na zakręcie, a kiedy wychodzi na prostą, nagle jechać szybciej. Zadanie to należy wykonać przy konfigurowaniu obiektów Spl i ne Interpol ator.
realizowane przez Timing Framework.
Wskazówka
W animacji wieloetapowej musimy zdefiniować obiekt KeyFrames, który będzie obsługiwał' ■ wszystkie pary czas-wartość oraz interpolatory interwałów. Na początek zdefiniujemy war-. . ■ tości, które carPosi ti on'będzie przyjmował przy wędrówce wokół toru:.
Warto zauważyć, że korzystaliśmy z programu Spl i neEdi tor,'dostępnego na witrynie W W W książki, umożliwiającego wizualizację tych interpolatorów i uzyskanie odpowiedniego efektu przy spieszania. Polecamy zrobienie tego samego przy zapoznawaniu się z klasą Spl i nelnterpol ator, szczególnie jeżeli Czytelnik nie ma doświadczenia ze splajnami i nie są one dla niego intuicyjne.
■ . Point values[] = { ' 1 TrackView.START_P0S, , ,, ■ . TrackView. FIRSTJURNJTART, Tra c kVi ew. FIRST_TURN_END, TrackView.SECOND_TURN_START, T rackView . SECONDJU R N _EN D , ■ TrackView.THIRD_TURN_START, TrackView.THIRD_TURN_END, TrackView.FOURTHJURNJTART, ■ y ; ■' '
,i
IH F lla M l ; ffirrra® E 5
tN
•ł^H " + " N a t u r e 's S a n i t a t i o n E n g i n e e r s < b r / > + " + "W hy a r e t h e y h e r e ? < b r / > + " +
o b s łu ż y ć t y p o w a a p lik a c ja , w y m a g a j ą o d p r o g r a m i s t y s p o r o p r a c y . Z t e g o p o w o d u praca n ie b y ł a b y n i g d y w y k o n a n a , a n a w e t r o z p o c z ę t a , c o w y ja ś n ia , d la c z e g o o b e c n ie s t o s o w a n e
""); ;
a p lik a c je n ie k o r z y s t a j ą z a n i m o w a n y c h p rz e jś ć .
J S c r o l l P a n e s c r o l l e r = new J S c r o l l P a n e ( r e s u l t s ) ;
P o k a ż e m y je d n a k , j a k m o ż n a w y k o r z y s t a ć b ib lio t e k ę A n i m a t e d T r a n s it io n s , a b y z re a liz o w a ć
Talc, w t y m p r o g r a m i e n a sta łe „ z a s z y li ś m y ” w y n i k i 3.
o p is a n e fu n k c je . W p r o je k c ie S e a r c h T r a n s i t i o n s s y m u lu j e m y a p lik a c ję z d w o m a e k ra n a m i. U ż y t k o w n i k n a w ig u j e z j e d n e g o e k r a n u d o i n n e g o p r z e z n a c iś n ię c ie k la w is z a E nter w p o lu
W m e t o d z ie s e t R e s u l t s S c r e e n ( ) d e f i n i u j e m y r o z m ie s z c z e n ie w s z y s t k i c h e l e m e n t ó w G U I n a d r u g i m e k ra n ie :
t e k s t o w y m . N a p o c z ą t k u z a p o z n a m y się z in t e r f e j s e m u ż y t y m n a t y c h d w ó c h e k ra n a c h .
p u b lic v o id s e t u p R e s u lt s S c r e e n Q
N a p i e r w s z y m e k r a n ie , p o k a z a n y m n a r y s u n k u 1 8.3, m a m y e ty k ie tę , p o le t e k s t o w e o ra z in s t r u k c ję . A p l ik a c j a d e f in iu j e te e le m e n t y j a k o z w y k ł e k o m p o n e n t y : J L a b e l i n s t r u c t i o n s = new J L a b e l ( " S u k a j c i e a z n a j d z i e c i e . . . " ) ; J L a b e l s e a r c h L a b e l = new J L a b e l ( " W y s z u k i w a n i e : " ) ; J T e x t F i e l d s e a r c h F i e l d = new J T e x t F i e l d ( " " ) ;
s e a r c h L a b e l . s e t B o u n d s ( s e a r c h X , 1 0 , LA BEL_W , L A B E L _ H ); s e a r c h F i e l d . s e t B o u n d s ( f i e l d X , f i e l d Y , F IE L D _ W , F IE L D _ H ) ; s c r o l 1e r . se tB o u n d s(R E S U L T S _ X , r e s u lt s Y , g e t W i d t h ( ) - (2 * R E S U L T S _ X ) , g e t H e ig h t () - r e s u lt s Y - 2 0 );
P o ło ż e n i e t y c h k o m p o n e n t ó w je st k o n f i g u r o w a n e w m e t o d z ie s e t u p S e a r c h S c r e e n (): p r iv a t e v o id s e t u p S e a r c h S c r e e n () / /
{
/ / przypisania zmiennych searchX/searchY/itd pominięte a d d (s e a r c h L a b e l) ; a d d (s e a r c b F ie ld ); a d d (s c ro lle r );
{
p r z y p is a n ia z m ie n n y c h s e a r c h X /s e a r c h Y /itd . p o m in ię t e
}
a d d ( i n s t r u c t i o n s ) ; a d d (s e a rc h La b e l) ;
T e r a z t w o r z y m y n a s z o b ie k t S c r e e n T r a n s i t i on:
a d d ( s e a r c h F ie l d ) ; i n s t r u c t i o n s . s e tB o u n d s (in s t r u c t i o n s X ,
i n s t r u c t i o n s Y ,
A n im a t o r a n im a t o r = new A n i m a t o r ( 5 0 0 ) ; a n im a t o r . s e t A c c e le r a t io n ( . 2 f ) ; a n im a t o r . s e t D e c e le r a t io n ( . 4 f ) ;
INSTRUCTIONS_W ,
^ IN S T R U C T I O N S _ H );
s e a r c h L a b e l . s e t B o u n d s ( s e a r c h X , s e a r c h Y , LABEL_W , L A B E L _ H ); s e a r c h F i e l d . s e t B o u n d s ( f i e l d X , f i e l d Y , F IE L D _ W , F IE L D _ H ) ;
S c r e e n T r a n s i t i o n t r a n s i t i o n = new S c r e e n T r a n s i t i o n ( t h i s , t h i s , a n im a t o r ) ;
} P r z e jś c ie t o t r w a p ó ł s e k u n d y , p r z y s p ie s z a j ą c p r z e z p ie r w s z e 2 0 % c z a s u i z w a ln ia j ą c p r z e z
\JL/
o st a tn ie 4 0 % . W y k o r z y s t a l i ś m y t u t h i s, c z y li o b ie k t JCom ponet, z a w ie r a ją c y k o m p o n e n t y G U I ,
W skazów ka
ja k o k o n t e n e r p rz e jśc ia . U ż y l i ś m y r ó w n i e ż t h i s, im p le m e n t a c j i in t e rf e js u T r a n s i t i o n T a rg e t,
W te j a p lik a c ji s k o rz y s ta liś m y z z e ro w e g o o b ie k tu LayoutM anager, c o je s t w y łą c z n ie u p r o s z c z e n ie m
ja k o o b ie k t u d o c e lo w e g o w y w o ła ń z w r o t n y c h p r z e jś c ia d o k o n f ig u r a c j i n a s t ę p n e g o e k ra n u .
te g o p rz y k ła d u . R z e c z y w is te a p lik a c je ze z ło ż o n y m , a tr a k c y jn y m i s o lid n y m in te r fe js e m k o r z y sta ją z o d p o w ie d n ic h o b ie k t ó w LayoutM anager.
■;5
E k r a n w y n i k ó w w y ś w i e t l a m y p o n a c i ś n i ę c i u k l a w i s z a E n ter, w ię c d o d a j e m y r ó w n i e ż K e y L i s t e n e r i im p le m e n t u j e m y m e t o d ę a c t i o n P e rfo rm e d () w n a s t ę p u j ą c y s p o s ó b :
W p o d o b n y s p o s ó b d e f in iu j e m y p a n e l p r z e w ij a n ia u ż y t y n a d r u g i m e k ra n ie , p o k a z a n y m ;
p u b lic v o id a c t io n P e r fo rm e d ( A c t io n E v e n t ae) {
n a r y s u n k u 18.7: J E d i t o r P a n e r e s u l t s = new J E d i t o r P a n e ( " t e x t / h t m l " , "M y L i f e w it h < b > D u n g B e e t le s < / b > < b r / > " + "< b > B e e t le < / b > B a i l e y G e ts L a t r i n e D u t y < b r / > " + " E v o l u t i o n 's O d d i t i e s < b r / > " + " S o c i e t y 's P a r a s i t e s < b r / > " + "Y o u < b > D u n g < / b > Me W ro n g: A C o u n t r y M u s i c H i s t o r y < b r / > " + " D i n g , < b > D u n g < / b > , T h e W it c h i s D e a d < b r / > " + " 'T o be o r n o t t o < b > b e e t l e < / b > '< b r / > " +
/ / Zmiana zmiennej currentScreen, użytej w wywołaniu zwrotnym setupNextScreen() c u rre n tS c re e n = (c u rre n tSc re e n == 0) ? 1 : 0; tr a n s it io n .s t a r t ( ) ;
: }
3 P r ó b o w a łe m z a im p le m e n to w a ć t u p e łn ą , p rz e s z u k iw a ln ą b a z ę w ied z y n a t e m a t o w a d ó w , ale b y ło w n ie j z b y t d u ż o ro b a k ó w . Z a c z ą łe m s ię je d n a k z a s ta n a w ia ć , c z y o n e n ie w p isu ją n a s ta łe w y n ik ó w w w y s z u k iw a rk a c h ? T o w y ja ś n ia ło b y , d la c z e g o s ą t a k ie s z y b k ie . P r z y t a k d u ż e j ilo ś c i ś m ie c i w s ie c i n ig d y n ie je s t e ś m y p e w n i.
R o z d z ia ł 1 8 .
B ib l io t e k a A n i m a t e d T r a n s it io n s
P ł y n n e m r z e jś c ia — b ib l i o t e k a
R o z p o c z ę c i e p r z e j ś c i a p o w o d u j e w y k o n a n i e w y w o ł a n i a z w r o t n e g o w n a s z e j m e t o d z ie s e t u p N e x t S c r e e n ( ) , k t ó r a je st z a i m p le m e n t o w a n a w n a s t ę p u j ą c y s p o s ó b : p u b lic
v o id
s e t u p N e x t S c r e e n ()
D o m y ś l n i e b ib lio t e k a A n i m a t e d T r a n s i t i o n k o r z y s t a z e s t a n d a r d o w y c h e f e k t ó w d o p r z e m ie s z c z a n ia k o m p o n e n t ó w w t r a k c ie a n im a c ji.
{
r e m o v e A l l Q ;
sw it c h ( c u r r e n t S c r e e n ) { ca se 0: se tu p S e a rch S c re e n Q ; b re ak; c a s e 1: s e t u p R e s u lt s S c re e n (); b re a k; d e fa u lt: b re a k; }
® K o m p o n e n t y u s u w a n e k o r z y s t a j ą z e f e k t u z a n ik a n ia . • K o m p o n e n t y d o d a w a n e k o r z y s t a j ą z e fe k t u w y ła n ia n ia .
1
® K o m p o n e n t y p r z e s u w a n e i s k a lo w a n e k o r z y s t a j ą z e fe k tu p r z e s u w a n ia i s k a lo w a n ia . C h o ć e fe k ty te d z ia ła ją c a ł k ie m n ie ź le , w y d a j e s ię p r a w d o p o d o b n e , ż e p r o g r a m i ś c i b ę d ą c h c ie li z a s t o s o w a ć w ła s n e e fe k ty d o w y k o r z y s t a n i a w a p lik a c ja c h . -
}
A b y u p r o ś c i ć m o d y f ik a c j ę p rze jść , e fe k ty u ż y w a n e p r z e z b ib lio t e k ę są im p le m e n t o w a n e ja k o w łą c z a ln e o b ie k t y . D z i ę k i t e m u b i b l i o t e k a k o r z y s t a d o m y ś l n i e z e s t a n d a r d o w y c h e fe k tó w ,
F u n k c j a re m o v e A l 1 () u s u w a w s z y s t k ie k o m p o n e n t y z k o n t e n e r a , c o je st n a j p r o s t s z y m s p o
ale m o ż n a w ła t w y s p o s ó b s k o n f ig u r o w a ć u ż y c ie w ła s n y c h .
s o b e m n a w y c z y s z c z e n ie s t a n u p o m i ę d z y e k r a n a m i i s k o n f ig u r o w a n i e e le m e n t ó w o d n o w a , A l t e r n a t y w n y m s p o s o b e m b y ł o b y w y k r y c ie r ó ż n i c w s t a n ie G U I p o m i ę d z y e k r a n e m b ie ż ą c y m i n a s t ę p n y m , a n a s t ę p n ie o d p o w i e d n i e d o d a n ie , u s u n ię c ie i z m o d y f i k o w a n ie lc o m p o - i
P r z y j r z y j m y s ię te r a z A P I e f e k t ó w i s p o s o b o m i c h w y k o r z y s t a n i a o r a z t w o r z e n ia w ł a s n y c h e f e k t ó w w a p lik a c ja c h .
n e n t ó w . J e d n a k u s u n ię c ie w s z y s t k ie g o i s k o n f ig u r o w a n i e k o m p o n e n t ó w d la n o w e g o e k r a n u i . w y d a j e się n ie c o p r o s t s z e , p r z y n a j m n ie j w tej sy tu a c ji.
Efekty — A P I
In s t r u k c j a s w it c h w y w o łu j e o d p o w ie d n ie m e t o d y s e t u p S e a r c h S c r e e n Q lu b s e t u p R e s u l t s -
Is t n ie j ą d w a r ó ż n e z a s t o s o w a n i a A P I e f e k t ó w — k r e o w a n i e i w y k o r z y s t a n i e is t n ie j ą c y c h
S c r e e n () w s p o s ó b o p is a n y w c z e śn ie j, w z a le ż n o ś c i o d te g o , n a k t ó r y e k r a n je st w y k o n y w a n e
i t w o r z e n ie w ł a s n y c h e fe k tó w . O m ó w i m y t u o b a te p r z y p a d k i.
p rz e jś c ie . Je st t o p r o s t y m e c h a n iz m , w k t ó r y m z a k ł a d a m y , że p r z e ł ą c z a m y się p o m i ę d z y d w o m a e k r a n a m i. W r z e c z y w iste j a p lik a c ji p o t r z e b n a b ę d z ie b a r d z ie j z a a w a n s o w a n a lo g ik a ,
Kreowanie obiektów efektów
w k t ó r e j p o t r z e b n e b ę d z ie o k r e ś le n ie , j a k b ę d z ie w y g l ą d a ł n a s t ę p n y e k ra n . N a p o c z ą t e k p r z y j r z y j m y się r ó ż n y m e fe k t o m o f e r o w a n y m p r z e z b ib lio te k ę . N a s z p r z e g lą d k o d u p r o j e k t u S e a r c h T r e a n s i t i o n je st n i e m a l k o m p le t n y . J a k w c z e ś n ie j p o k a z a liś m y , in t e rf e js k l a s y A n i m a t e d T r a n s i t i o n s je s t b a r d z o p r o s t y . W i ę k s z o ś ć f u n k c j i je st ;
Move
n ie w id o c z n a d la u ż y t k o w n ik a . B ib lio t e k a w e w n ę t r z n ie s p r a w d z a , w j a k i s p o s ó b k o m p o n e n t y
T e n e fe k t p o z w a la n a p r z e s u w a n ie k o m p o n e n t u z p u n k t u p o c z ą t k o w e g o , c z y li p o ło ż e n ia
z m ie n ia j ą się m i ę d z y e k r a n a m i, i w y k o n u j e a n i m o w a n e p r z e jś c ia p o m ię d z y t y m i z m ia n a m i.
n a p i e r w s z y m e k r a n ie , d o p u n k t u k o ń c o w e g o , n a d r u g i m e k ra n ie .
W s z c z e g ó ln o ś c i, je ż e li a p lik a c j a m o ż e u ż y ć s t a n d a r d o w y c h e f e k t ó w p r z e j ś c ia i n ie są w y m a g a n e n i e s t a n d a r d o w e e fe k ty , w s z y s t k o z o s t a ło j u ż w y j a ś n i o n e — n a le ż y u t w o r z y ć o b ie k t S c r e e n T r a n s i t i o n , w y w o ła ć m e t o d ę s t a r t ( ) i o d p o w i e d n i o o b s ł u ż y ć s e t u p N e x t S c r e e n (). Is t n ie j e j e d n a k je sz c z e je d e n e le m e n t w p r o g r a m i e d e m o n s t r a c y j n y m S e a r c h T r a n s i t i o n , ; k t ó r y je st n ie z m ie r n ie w a ż n y . W y k o r z y s t a n e s ą w ł a s n e e f e k t y d o p r z e s u w a n ia i z a n ik a n ia e le m e n t ó w n a e k ra n ie . A b y p o k a z a ć , w jaki s p o s ó b u z y s k a ć coś p o d o b n e g o w n a s z y c h a p li k a c ja c h , m u s i m y p r z e d s t a w ić t w o r z e n ie e fe k tó w .
S c a le E f e k t te n p o le g a n a z m ia n ie w ie lk o ś c i e le m e n t u p o m i ę d z y w ie lk o ś c ią p o c z ą t k o w ą a k o ń c o w ą . P o n i e w a ż s k a lo w a n ie m o ż e s p o w o d o w a ć w p r z y p a d k u n i e k t ó r y c h k o m p o n e n t ó w z m ia n ę w y g lą d u , n a p r z y k ł a d w p r z y p a d k u t y c h z a w ie r a j ą c y c h t e k s t l u b k t ó r y c h w e w n ę t r z n y u k ła d z m ie n ia się z w ie lk o ś c ią , z a s t o s o w a n ie te g o e fe k tu z m ie n ia w e w n ę t r z n y z n a c z n ik w s k a z u j ą c y sy s te m o w i, że k o n ie c z n e je st r e n d e r o w a n ie k o m p o n e n t u w cz a sie a n i m a c j i z a m ia s t k o r z y s t a n i a z m i g a w k i w y g l ą d u k o m p o n e n t u . S k a l o w a n i e o b r a z u k o m p o n e n t u d a je e fe kty , k t ó r e n a jc z ę śc ie j n ie w y g lą d a j ą n a jle p ie j, p o n i e w a ż w c z a s ie
R o z d z ia ł 1 8 .
B ib l io t e k a A n i m a t e d T r a n s i t i o n s
P ł y n n e p r z e jś c ia
p r z e j ś c ia w i d o c z n e s ą z n ie k s z t a łc e n ia o r a z ir y t u j ą c e „ p r z e łą c z e n ie s ię ” n a r z e c z y w is t y
;
— b ib l i o t e k a
Użycie efektów
w y g l ą d p o z a k o ń c z e n i u p r z e j ś c ia i n a r y s o w a n i u r z e c z y w is t e g o k o m p o n e n t u . R e n d e r o w a n i e f a k t y c z n e g o k o m p o n e n t u w c z a s ie a n i m a c j i r o z w ią z u j e t e n p r o b l e m i e lim i- y
P o u z y s k a n i u o b ie k t u E f f e c t n a l e ż y w s k a z a ć b ib lio te c e , w j a k i s p o s ó b i k i e d y m a g o u ż y ć . Jest to r e a liz o w a n e p o p r z e z m e t o d ę s e t E f f e c t () z k l a s y E f f e c t s M a n a g e r :
n u j e a rte fa k ty . s t a t i c v o i d s e t E f f e c t ( J C o m p o n e n t co m p o n e n t, E f f e c t e f f e c t , T r a n s i t i o n T y p e ^ t r a n s i t ; onType)
Fadeln E f e k t t e n p o w o d u j e n a r y s o w a n ie k o m p o n e n t u z e z m ie n ia j ą c y m s ię s t o p n i e m p r z e ś w i t y w a n ia , o d n i e w i d o c z n e g o d o c a ł k o w ic ie n ie p r z e z r o c z y s t e g o , c o p o w o d u j e w y ła n ia n ie
:
się k o m p o n e n t u p o m i ę d z y p i e r w s z y m a d r u g i m e k r a n e m . FadeOut
M e t o d a s e t E f f e c t () o c z e k u j e j a k o p a r a m e t r u k o m p o n e n t u r e n d e r o w a n e g o p r z y p o m o c y efe ktu , e fe k tu d o w y k o n a n i a o r a z o b ie k t u T r a n s i t i onType, p o d k t ó r e g o k o n t r o l ą b ę d z ie u ż y w a n y t e n efe kt. P a r a m e t r t r a n s i t i o n T y p e m o ż e p r z y j m o w a ć n a s t ę p u j ą c e w a r t o ś c i: ® TransitionType.A P P E A R IN G — p r z e jś c ie to je st r e a liz o w a n e , g d y k o m p o n e n t
Je st t o p r z e c iw ie ń s t w o e fe k t u Fadeln; k o m p o n e n t z m i e n ia s ię o d c a łk o w ic ie n ie p r z e z r o c z y s t e g o d o n ie w id o c z n e g o , p o m i ę d z y p ie r w s z y m a d r u g i m e k r a n e m .
z n a j d u j e się n a d r u g i m e k ra n ie , a le n ie m a g o n a p ie r w s z y m . ® T r a n s i t i o n T y p e . D IS A P P E A R IN G — p r z e j ś c ie to je st r e a liz o w a n e , g d y k o m p o n e n t z n a j d u j e się n a p i e r w s z y m e k ra n ie , ale n ie m a g o n a d r u g i m .
Rotate E f e k t t e n je s t u ż y w a n y d o o b r ó c e n ia k o m p o n e n t u o o k r e ś l o n y k ą t w o k ó ł z d e f in io w a ■ n e g o ś r o d k a o b ro tu .
o TransitionType. CHANGING — p r z e jś c ie t o je st r e a liz o w a n e , g d y k o m p o n e n t z n a j d u j e s ię n a o b u e k r a n a c h . U s t a w ie n ie e f e k t ó w w k o m p o n e n t a c h w t a k i s p o s ó b p o w o d u j e , ż e s ą o n e u s t a w ia n e g l o
Unchanging E f e k t t e n n i e d a je ż a d n y c h w y n i k ó w i je st w y łą c z n ie n a r z ę d z ie m d o n a r y s o w a n i a k o m - 1 p o n e n t u w s w o i m p o c z ą t k o w y m p o ł o ż e n i u w t r a k c ie p r z e jś c ia . W y k o r z y s t a n i e j e d n e g o z t y c h e f e k t ó w je st p r o s t e ; w y m a g a n e je s t z w y k ł e w y w o ła n ie k o n st ru k t o r a . W i ę k s z o ś ć t y c h e fe k tó w p o s ia d a d o m y ś l n y k o n s t r u k t o r , k t ó r y n ie m a a r g u m e n - 1
b a ln ie d la a p lik a c ji. N i e są o n e c h a r a k t e r y s t y c z n e d la ż a d n e g o b ie ż ą c e g o a n i p r z y s z łe g o p r z e j śc ia . A b y u s u n ą ć e fe k t k o m p o n e n t u i t y p u p r z e jś c ia , n a le ż y w y w o ł a ć m e t o d ę s e t E f f e c t ( ) z w a r t o ś c ią n u l 1 w p a r a m e t r z e e fe k tu . A b y z a in s t a lo w a ć n a p r z y k ł a d e fe k t o b r o t u , k t ó r y w c z e ś n ie j u t w o r z y l i ś m y , m o ż e m y s k o r z y s t a ć z n a s t ę p u j ą c e g o w y w o ła n ia :
tó w . A b y u t w o r z y ć n a p r z y k ł a d e fe k t Move, m o ż e m y s k o r z y s t a ć z n a s t ę p u j ą c e g o w y w o ła n ia : f Move
m o v e E ffe c t
=
new
E f f e c t s M a n a g e r . s e t E f f e c t (c o m p o n e n t, r o t a t e A r o u n d C e n t e r , T r a n s i t i o n T y p e . ^ C H A N G IN G ) ;
M o v e f );
D a n e d la s t a n u p o c z ą t k o w e g o i k o ń c o w e g o są k o n f i g u r o w a n e p r z e z b ib lio t e k ę p o r o z p o - f c z ę c iu p rz e jśc ia , w ię c w t r a k c ie t w o r z e n ia n ie są p o t r z e b n e ż a d n e d o d a t k o w e d a n e . N ie k t ó r e
W y w o ł a n i e t o in f o r m u j e b ib lio t e k ę , a b y e fe k t r o t a t e A r o u n d C e n t e r z o s t a ł u ż y t y d o w y k o n a n i a p r z e j ś c ia w p r z y p a d k u , g d y k o m p o n e n t z n a jd u je s ię n a o b u e k r a n a c h .
e fe k t y m o g ą p o t r z e b o w a ć d o d a t k o w y c h d a n y c h , p o z a p o ł o ż e n ie m i r o z m ia r a m i. N a p r z y - : k ł a d e fe k t R o t a t e w y m a g a p o d a n ia k ą t a i ś r o d k a o b r o t u . U t w o r z e n i e te g o e fe k tu d la d a n e g o
P o r o z p o c z ę c i u p r z e j ś c ia s y s t e m s p r a w d z a , c z y i w j a k i s p o s ó b k a ż d y k o m p o n e n t z m ie n ia
ś r o d k a o b r o t u w y g lą d a n a s t ę p u j ą c o :
s ię p o m i ę d z y d w o m a e k r a n a m i. N a p o d s t a w i e t y c h i n f o r m a c j i b i b l i o t e k a o k r e ś la o b ie k t
R o ta te
ro ta te A ro u n d X Y
=
new
R o ta te (d e g r e e s ,
x ,
y ) ;
T r a n s it io n T y p e d o u ż y c ia . N a s t ę p n ie o d p y t y w a n y je st o b ie k t E f f e c t s M a n a g e r w c e lu s p r a w d z e n ia , c z y d la tej p a r y k o m p o n e n t - T r a n s i t i o n T y p e z o s t a ł z a i n s t a l o w a n y n i e s t a n d a r d o w y
g d z ie (x, y ) je st p o ło ż e n ie m w z g lę d e m p o c z ą t k u k o m p o n e n t u , d la k t ó r e g o je st o n st o so w a n y . M o ż n a r ó w n ie ż u t w o r z y ć e fe k t R o t a t e ze ś r o d k ie m , k t ó r y je st w y li c z a n y n a p o d s t a w ie ś r o d k a
efekt. Jeże li n ie z o s t a ł p r z y p i s a n y t a k i o b ie k t, b ib lio t e k a p r z e k a z u je s t e ro w a n ie d o d o m y ś ln e g o o b ie k t u d la k a ż d e j w a r t o ś c i T r a n s i t i onT ype :
ko m p o n e n tu : ® F a d e ln d la A P P E A R IN G R o ta te
ro ta te A ro u n d C e n te r
=
new
R o ta te (d e g r e e s ,
com ponent);
® F a d e O u t d la D IS A P P E A R IN G ® Move, S c a l e l u b M o v e / S e a l e d la CHANGING.
R o z d z ia ł 1 8 .
B ib l io t e k a A n i m a t e d T r a n s i t i o n s
— b ib l i o t e k a
P ł y n n e p r z e jś c ia
P r z y o k a z j i p r z e d s t a w ia n ia e fe k t u M o v e / S c a le w a r t o w s p o m n i e ć , ż e d o s t ę p n y je st je sz c ze
® s e t u p (). M e t o d a ta je st w y w o ły w a n a d la k a ż d e j r a m k i a n im a c j i p r z e jś c ia
je d e n w b u d o w a n y efekt, Compos i t e E f f e c t . E fe k t t e n n ie re a liz u je s a m o d z ie ln ie ża d n e j fu n k c ji,
w c e l u o d p o w i e d n i e g o s k o n f ig u r o w a n i a o b ie k t u G r a p h i c s d la r e n d e r o w a n i a d a n e g o e fe k tu .
a le p o z w a l a k o r z y s t a ć z w ie lu e fe k t ó w p o d r z ę d n y c h d o u t w o r z e n i a n o w e g o , b ę d ą c e g o p o łą c z e n ie m w s z y s t k ic h d o d a n y c h e fe k tó w . T a k w ię c e fe k t M o v e / S c a le je st w r z e c z y w is t o ś c i o b ie k t e m C om po si t e E f f e c t , k t ó r y w y k o n u j e o b ie o p e ra c je , M ove o r a z S c a l e, w c z a s ie p rz e jśc ia y S
• p a i n t ( ). M e t o d a ta je s t w y w o ły w a n a p o s e t u p ( ) . W tej m e t o d z ie r e a liz o w a n e je st r e n d e r o w a n ie o b ie k t u .
m i ę d z y e k r a n a m i. W skazów ka
K l a s a C om po si t e E f f e c t m a d w a k o n s t r u k t o r y :
W k la sa c h d z ie d zic zą cyc h p o E f f e c t w ię k sz o ść z ty ch m e to d jest op cjon a ln a . M e t o d a i ni t () jest najczęściej jedyną, k tó rą n a le ży n a dp isać, w za le żn o ści o d sytuacji. N a p r z y k ła d k la sa n a d rzę d n a E f f e c t o b słu g u je m e to d y se t u p () o ra z pai nt () d la k o m p o n e n tó w , któ re m u s z ą p o p ro st u zostać n a ry so w a n e w znanej lo k alizac ji i m ie ć zn a n ą w ie lkość.
C o m p o s i t e E f f e c t c o m p o s it e = new C o m p o s i t e E f f e c t ( ) ; C o m p o s i t e E f f e c t c o m p o s it e = new C o m p o s i t e E f f e c t ( s o m e E f f e c t ) ; J e d y n a r ó ż n i c a p o m i ę d z y n i m i p o le g a n a t y m , ż e je s t p o d a w a n y l u b n i e e fe k t p o c z ą t k o w y . D o d a t k o w e e fe k t y s ą d o d a w a n e p r z e z w y w o ła n i e m e t o d y a d d E f e c t ( ) : c o m p o sit e .a d d E ffe c t (s o m e O t h e r E ffe c t);
j
A b y p o k a z a ć z a s a d y t w o r z e n ia w ł a s n y c h e fe k tó w , p r z e a n a l iz u j e m y k o d k i l k u e f e k t ó w d o s t ę p n y c h w s y ste m ie .
B ib l io t e k a t w o r z y w e w n ę t r z n ie n a p r z y k ł a d e fe k t M o v e / S e a l e w n a s t ę p u j ą c y s p o s ó b :
Im plem entacja efektu Move E f f e c t m ove= new M o v e Q ; E f f e c t s c a l e = new S c a l e Q ; C o m p o s it e E f f e c t c o m p o s it e = new C o m p o s i t e E f f e c t ( m o v e ) ;
E f e k t M o ve p o z w a l a n a p r z e s u n ię c ie k o m p o n e n t u w c z a s ie p r z e j ś c ia z p o z y c j i p o c z ą t k o w e j n a końcow ą.
c o m p o si t e . a d d E f f e c t ( s e a l e ) ; W k la s ie M ove z o s t a ły z d e f in io w a n e d w a k o n s t r u k t o r y — je d e n b e z a r g u m e n t ó w , o c z e k u ją c y ,
Tworzenie własnych efektów J a k w c z e ś n ie j w s p o m n i e l i ś m y , m o ż li w e je s t t w o r z e n ie w ł a s n y c h e f e k t ó w i w s k a z a n ie i c h ;) o b ie k t o w i t f f e c t s M a n a g e r d o u ż y c ia w c z a s ie p rz e jśc ia . E f e k t y d o łą c z o n e d o b ib lio t e k i o b e j- r
ż e s t a n b ę d z ie s k o n f i g u r o w a n y w d z a sie in ic j a liz a c j i p r z e jś c ia , a d r u g i z e s t a n e m p o c z ą t k o w ym i końcow ym . p u b lic
M ove()
{}
y
p u b lic
M o ve(C om p onentState
m u ją p o d s t a w y , a le m o ż liw e je st u t w o r z e n ie w ie le i n n y c h e fe k tó w . A P I p o z w a la j ą c e n a t w o r z e n ie w ł a s n y c h e fe k t ó w je s t d o s y ć p r o s t e . Is t n ie j ą c z t e r y g łó w n e
s t a r t ,
C o m ponentState
end)
{
se tC o m p o ne ntS ta tes ( s t a r t ,!'e n d );
e le m e n t y , k t ó r e m o ż n a w y k o r z y s t a ć ; w ię k s z o ś ć z n i c h je st o p c j o n a ln a : ® K o n s t r u k t o r . Je ż e li e fe k t y w y m a g a j ą p o d a n i a p a r a m e t r ó w , ta lc ic h j a k p o ło ż e n ie p o c z ą t k o w e lu b k o lo r , p o t r z e b n y b ę d z ie s p e c j a liz o w a n y k o n s t r u k t o r d o u s t a w ie n ia t y c h w a rto ś c i. Z a s t o s o w a n ie d o d a t k o w y c h p a r a m e t r ó w b y ło p o k a z a n e w p r z y k ła d z ie z a s t o s o w a n i a e fe k tu R o t a t e , k t ó r y w y m a g a p o d a n i a k ą t a i ś r o d k a o b r o t u . ® i n i t ( ) . B ib lio t e k a w y w o łu j e m e t o d ę i n i t () e fe k t u n a p o c z ą t k u k a ż d e g o p r z e j ś c ia w y k o r z y s t u j ą c e g o t e n efekt. B y ć m o ż e b ę d z ie p o t r z e b n e n a d p i s a n i e tej m e t o d y
A n i m a c j a z m ie n ia j ą c a p o ło ż e n i e k o m p o n e n t u w c z a s ie je s t k o n f i g u r o w a n a w m e t o d z ie i n i t ( ) , p r z y u ż y c i u o b ie k t u P r o p e r t y S e t t e r z m ie n ia j ą c e g o w ł a ś c i w o ś ć l o c a t i o n z k l a s y bazow ej E ffe c t: • p u b lic
v o id
E f f e c t
in it ( A n im a t o r
t a r g e t E f f e c t
P r o p e r t y S e tte r ps
=
new
=
a n im a to r,
E f f e c t
(p a r e n t E ff e c t
new
P o i n t ( g e t S t a r t ( ) . g e t X ( ) ,
w m e t o d z ie i n i t () t w o r z y ć o b ie k t y P r o p e r t y S e t t e r d o a n i m o w a n i a d o w o l n y c h
new
P o i n t ( g e t E n d ( ) * g e t X ( ) ,
S c r e e n T r a n s i t i o n d o m e t o d y i n i t ( ) , c o u m o ż l i w i a d o d a w a n ie d o a n im a t o r a n o w y c h o b ie k t ó w d o c e lo w y c h , t a la c h j a k o b ie k t y P r o p e r t y S e t t e r .
p a r e n t E f f e c t )
n u ll)
?
t h is
:
{ p a r e n t E f f e c t ;
ps;
P r o p e r t y S e t t e r ( t a r g e t E f f e c t ,
w c e lu u t w o r z e n i a s p e c j a ln y c h w ł a ś c i w o ś c i a n im a c j i. N a p r z y k ł a d m o ż n a p a r a m e t r ó w p r z e jś c ia . O b i e k t A n im a t o r je s t p r z e k a z y w a n y p r z e z o b ie k t
==
a n im a to r .a d d T a r g e t(p s ); s u p e r .i n it ( a n i m a t o r ,
n u l l ) ;
" l o c a t i o n " ,
g e t S t a r t Q
. g e t Y Q ) ,
g e tE n d ( ) . g e t Y ( ) ) ) ;
R o z d z ia ł 1 8 .
B ib l io t e k a A n i m a t e d T r a n s it io n s
P ł y n n e p r z e jś c ia
p r i v a t e d o u b le r a d i a n s ; p u b lic v o id s e t R a d ia n s (d o u b le r a d ia n s ) t h is . r a d ia n s = r a d ia n s ; }
W y r a ż e n i e k o rz y s t a ją c e z p a r e n t E f f e c t o b s łu g u j e p r z y p a d e k , w k t ó r y m e fe kt Move je st czę ścią C o m p o s it e E f f e c t . W
— b ib l i o t e k a
t a k i m p r z y p a d k u M o ve z m i e n i a p o ło ż e n ie C o m p o s i t e E f f e c t z a m ia s t
w ła s n e g o , p o n ie w a ż z o s t a n ie n a r y s o w a n y p ó ź n ie j w r a z z Com pos i t e E f f e c t . P r o p e r t y S e t t e r je st p r o s t y m o b ie k t e m , k t ó r y z m i e n i a p o ło ż e n i e o d lo k a liz a c j i p o c z ą t k o
(
M e t o d a i n i t () l d a s y R o t a t e je st p o d o b n a d o M o ve , i n i t ( ) z t y m w y ją tłc ie m , ż e R o t a t e n i e
w e j d o k o ń c o w e j . N a s t ę p n i e o b ie k t t e n je st p r z y p i s y w a n y j a k o o b ie k t d o c e lo w y a n im a t o r a
w y k o r z y s t u j e o b ie k t ó w C o m p o s i t e E f f e c t , p o n i e w a ż n ie o b s ł u g u j ą o n e z m ie n n e j r a d i a n s .
w y k o r z y s t y w a n e g o p r z e z S c r e e n T r a n s i t i on d o o b s ł u g i c a ło ś c i p r z e jś c ia .
Z m i e n n a ta m u s i b y ć z m i e n i a n a w l o k a l n y m o b ie k c ie :
W M a s i e M o ve n ie s ą p o t r z e b n e f u n k c j e r e n d e r u j ą c e p o z a z n a j d u j ą c y m i s ię w M a s i e b a z o w e j
p u b l i c v o i d i n i t ( A n i m a t o r a n im a t o r , E f f e c t p a r e n t E f f e c t ) P ro p e rty S e tte r p s;
E f f e c t . W M a s ie E f f e c t o b ie k t G r a p h ic s 2 D je st w M a s ie E f f e c t . s e t u p ( ) a u t o m a t y c z n ie p r z e
p s = new P r o p e r t y S e t t e r ( t h i s , a n im a t o r .a d d T a r g e t (p s ); su p e r .in it (a n im a t o r , n u li) ;
s u w a n y d o w ła ś c iw e j lo k a liz a c ji, a n a s t ę p n ie a n i m o w a n y p r z e z P r o p e r t y S e t t e r u t w o r z o n y w M o v e . i n i t ('). N a s t ę p n ie w M a s i e E f f e c t . p a i n t ( ) r y s o w a n y je s t o b r a z k o m p o n e n t u .
{
" r a d i a n s " , 0 . 0 , e n d R a d ia n s ) ;
} T o w s z y s t k o . W M a s i e M ove z o s t a ły z a im p le m e n t o w a n e t y lk o te m e t o d y .
y W m e t o d z ie tej t w o r z o n y je st p r o s t y o b ie k t P r o p e r t y S e t t e r i d o d a w a n y j a k o o b ie k t d o c e lo w y
Z a j m i e m y się t e r a z b a r d z ie j s k o m p l i k o w a n y m p r z y lc ła d e m , R o t a t e .
Im plem entacja efektu Rotate E f e k t R o t a t e p o z w a l a n a o b r ó c e n ie k o m p o n e n t u w o k ó ł ś r o d k a o b r o t u o o k r e ś l o n ą lic z b ę f s t o p n i. K l a s a ta m a t r z y k o n s t r u k t o r y p o z w a la j ą c e o b s ł u ż y ć r ó ż n e p r z y p a d ła : p u b lic R o t a t e (in t d e g re e s, in t x C e n te r, i nt y C e n te r) p u b l i c R o t a t e ( i n t d e g r e e s , C om po nent c o m p o n e n t) p u b l i c R o t a t e ( C o m p o n e n t S t a t e s t a r t , C o m p o n e n tS t a te e n d , i n t d e g r e e s , i n t xC en ter, in t yC enter) P ie r w s z y k o n s t r u k t o r o c ze k u je p o d a n ia k ą ta o r a z ś r o d k a o b ro tu , b e z st a n u p o c z ą tk o w e g o i i k o ń c o w e g o . R o t a t e , p o d o b n i e j a k in n e e fe k ty , o c z e k u j e u s t a w ie n ia t y c h w a r t o ś c i w p ó ź n ie j s z y m c z a sie , p o d c z a s in ic ja liz a c ji p rz e jś c ia . D r u g i k o n s t r u M o r je st o d m i a n ą p ie r w s z e g o , a le ś r o d e k o b r o t u s t a n o w i ś r o d e k p o d a n e g o 1 k o m p o n e n t u . W y w o ł a n i e te g o k o n s t r u k t o r a je st o d p o w i e d n i ld e m n a s t ę p u j ą c e g o w y w o ła n i;:: R o t a t e ( d e g r e e s , c o m p o n e n t.g e t W id t h ( ) / 2 , c o m p o n e n t.g e t H e i g h t ( ) / 2 ) ;
d o o b ie k t u A n im a t o r o b s łu g u j ą c e g o p rz e jś c ie . T e n o b ie k t P r o p e r t y S e t t e r z m i e n i a w a r t o ś ć o b r o t u w r a d i a n a c h o d 0 d o e n d R a d i a n s, b ę d ą c e j w a r t o ś c ią w s t o p n i a c h p r z e k a z a n ą w k o n s t r u k t o r z e , a le p r z e l ic z o n ą n a r a d ia n y . W p r z e c iw ie ń s t w ie d o M ove, g d z ie w m e t o d z ie s e t u p ( ) p r z e k a z a liś m y z a d a n ie p r z e s u n ię c ia k o m p o n e n t u n a w ła ś c iw e m ie jsc e o d M a s y n a d r z ę d n e j E f f e c t , w R o t a t e k o n ie c z n e je st n a d p is a n ie m e t o d y s e t u p ( ) w c e lu ta ld e j z m i a n y s t a n u o b ie k t u G r a p h ic s , a b y z o s t a ł u w z g l ę d n i o n y o b ró t : © O v e r r id e p u b lic v o id s e t u p ( G r a p h ic s 2 D g2 d ) { g 2 d .t ra n s la te (x C e n te r , y C e n te r); g 2 d .r o t a t e (r a d ia n s ); g 2 d .t ra n s la t e (-x C e n t e r , -y C e n t e r ); su p e r.se tu p (g 2 d ); } W m e t o d z ie tej o b ie k t G r a p h ic s 2 D je st p r z e s u w a n y d o ś r o d k a o b r o t u , a n a s t ę p n ie z p o w r o t e m d o p o z y c j i p o c z ą tk o w e j, id e n t y c z n ie j a k r o b i l i ś m y t o w r o z d z ia le 3., „ P o d s t a w y g r a f i k i ”. O b i e k t G r a p h i c s 2 D je s t o b r a c a n y o k ą t w y r a ż o n y w r a d ia n a c h , k t ó r y je s t a n i m o w a n y za
T r z e c i k o n s t r u k t o r je st t a M j a k p ie r w s z y , ale d o d a t k o w o o c z e k u j e p r z e k a z a n ia s t a n u p o c z ą t-
p o m o c ą P r o p e r t y S e t t e r . N a s t ę p n ie w y k o n y w a n e je st w y w o ła n i e s u p e r . s e t u p (), c o p o z w a la
lc o w e g o i k o ń c o w e g o d la k o m p o n e n t u . N o r m a l n i e w e r s ja ta n ie je st u ż y w a n a , p o n ie w a ż sta n
n a w y k o n a n ie p o z o s t a ły c h o p e ra c ji k o n f ig u r a c y j n y c h z d e f in io w a n y c h w ld a s ie b a z o w e j E f f e c t .
p o c z ą t k o w y i k o ń c o w y je st a u t o m a t y c z n ie o k r e ś l a n y i u s t a w i a n y p r z e z b ib lio t e k ę . W p r z e c iw ie ń s t w ie d o Move, w M a s i e R o t a t e n i e je st z m i e n i o n a m e t o d a E f f e c t . p a i n t ( ) , E f e k t R o t a t e t y m r ó ż n i się o d Move, że k o n ie c z n e je st z a p a m ię t a n ie i ś le d z e n ie d o d a t k o w y c h
p o n i e w a ż n ie je st w y m a g a n y s p e c j a ln y s p o s ó b r e n d e r o w a n i a p o z a t y m , k t ó r y je st r e a liz o
z m i e n n y c h , k t ó r e n i e z o s t a ły z d e f in io w a n e w M a s i e n a d r z ę d n e j E f f e c t . W M a s i e R o t a te
w a n y w m e t o d z ie E f f e c t . p a i n t ( ). S a m k o m p o n e n t l u b o b r a z k o m p o n e n t u b ę d z ie o d p o
k o n ie c z n e je st r ó w n i e ż u d o s t ę p n ie n ie p u b lic z n e j m e t o d y w y k o r z y s t y w a n e j p r z e z P r o p e r t y
w i e d n i o r e n d e r o w a n y p r z y w y k o r z y s t a n i u o b ie k t u G ra p h i cs2 D , k t ó r e g o s t a n je st z m i e n i a n y p r z e z o p e r a c ję o b r o t u .
S e t t e r w c z a s ie p r z e j ś c ia d o m o d y f i k a c j i z m ie n n e j z a w ie r a ją c e j b ie ż ą c ą w a r t o ś ć o b r o t u :
534-
R o z d z ia ł 1 8 .
P ł y n n e p r z e jś c ia
B ib l io t e k a A n i m a t e d T r a n s it io n s
— b ib l i o t e k a
T a m e t o d a i n i t () je st b a r d z o p o d o b n a d o tej, k t ó r ą w i d z i e l i ś m y w c z e ś n ie j w , p r z y p a d k u
Przykład. Search Transition. Starcie drugie modyfikacje —
w b u d o w a n e g o e fe k tu Move. Z n a c z e n ie w ie r s z a z p a r e n t E f f e c t je st i d e n t y c z n e j a k o p is a n e w c z e śn ie j; o b s ł u g i w a n y je st t u p r z y p a d e k z a s t o s o w a n ia Com pos i t e E f f e c t , t a k j a k w n a sz e j sy tu a c ji. A n i m a c j a je st re a liz o w a n a p r z e z p r o s t y o b ie k t P r o p e r t y S e t t e r , a n im u j ą c y p o ło ż e n ie o d s t a r t L o c a t i o n , u s ta w ia n e j w t r a k c ie t w o r z e n ia o b ie k t u , d o p o ło ż e n ia k o ń c o w e g o , u s t a
DEMO W SIECI
G d y w i e m y ju ż , w j a k i s p o s ó b d z ia ła ją e fe k t y i j a k m o ż n a u t w o r z y ć w ła s n e , w r ó c i m y d o
w ia n e g o d y n a m ic z n ie p r z e z sy ste m , o r a z d o d a n ie te g o o b ie k t u u s t a w ia n ia w a r t o ś c i w ła ś c i
p r z y k ł a d u S e a r c h T r a n s i t i o n , a b y p o k a z a ć , w j a k i s p o s ó b m o ż e m y z a im p le m e n t o w a ć w ła
w o ś c i d o a n im a t o r a . N a k o n ie c w y w o łu j e m y m e t o d ę i n i t () z k l a s y n a d r z ę d n e j, a b y z a p e w n ić
s n y e fe k t n a e k r a n ie w y n ik ó w .
p r a w id ł o w ą in ic ja łiz a c ję w s z y s t k i c h e le m e n t ó w e fe ktu .
D o m y ś l n i e k o m p o n e n t m a j ą c y w a r t o ś ć z m ie n n e j T r a n s i t i o n T y p e r ó w n ą A P P E A R IN G w y k o
G d y m a m y n a s z e fe k t M o v e ln , m o ż e m y u t w o r z y ć s u m a r y c z n y e fe k t p r z e z w y k o r z y s t a n i e
r z y stu je s t a n d a r d o w y efe kt F a d e ln . W a p lik a c ji tej c h c e m y , a b y w y n i k i w s u w a ły się n a o d p o
Com pos i t e E f e c t , b a z u j ą c e g o n a z d e f i n i o w a n y m p r z e z n a s e fe k c ie M o v e ln o r a z w b u d o w a
w ie d n ie m ie jsc e z j e d n o c z e s n y m w y ła n ia n ie m , w ię c p o t r z e b u j e m y d o te g o w ła sn e j k ia s y efektu.
n y m F a d e ln . T w o r z y m y t e n e fe k t w m e t o d z ie s e t u p B a c k g r o u n d A n d E f f e c t Q , k t ó r a je st w y
D o r e a liz a c ji w y ła n i a n i a m o ż e m y w y k o r z y s t a ć d o s t ę p n y e fe k t F a d e ln . M o ż e m y w ię c s k o r z y s t a ć z e z ł o ż o n e g o e fe k tu Compos i t e E f f e c t z a w ie r a ją c e g o j a k o je d e n z o b ie k t ó w p o d r z ę d n y c h e fe k t F a d e ln . A b y p r z e s u n ą ć k o m p o n e n t n a m ie jsc e , p o t r z e b u j e m y n o w e g o e fe ktu . B ib lio t e k a p o s ia d a ju ż
w o ł y w a n a p r z e z m e t o d ę p a in t C o m p o n e n t() p r z y k a ż d e j z m ia n ie w y s o k o ś c i n a s z e g o k o m p o n e n t u . T a z a le ż n o ś ć o d w y s o k o ś c i k o m p o n e n t u w y n i k a ze s p o s o b u d z ia ła n ia e fe k tu M o ve ln , k t ó r y m u s i w s u n ą ć k o m p o n e n t o d d o ln e j c z ę ś c i o k n a . J e ż e li z m i e n i s ię w y s o k o ś ć o k n a , k o n ie c z n e je st o d t w o r z e n ie e fe k tu , a b y b y ł o n o d p o w i e d n i o d o p a s o w a n y . p r iv a t e v o id s e t u p B a c k g ro u n d A n d E ff e c t Q
{
e fe k t M ove, ale d z ia ła o n t y lk o n a k o m p o n e n t a c h z n a j d u j ą c y c h się n a o b u e k r a n a c h , d z ię k i
/ /
c z e m u m a o n d o s t ę p d o lo k a liz a c j i n a o b u e k r a n a c h . W n a s z y m p r z y p a d k u c h c e m y p r z e
b g G r a d ie n t = new G r a d i e n t P a i n t ( 0 , 0 , C o l o r . L IG H T _ G R A Y . b r i g h t e r ( ) , 0, g e t H e ig h t (), C o l o r . D A R K _ G R A Y .b r i g h t e r Q ) ;
s u n ą ć k o m p o n e n t , k t ó r y n ie ist n ie je n a p i e r w s z y m e k r a n ie p r z e jś c ia . P o t r z e b u j e m y efe ktu , k t ó r y p r z e s u w a k o m p o n e n t z p o d a n e j lo k a liz a c j i d o d y n a m i c z n i e o k r e ś la n e g o s t a n u k o ń c o w e g o . Z d e f in iu j e m y w ię c n o w ą k la s ę M o v e ln , d z ie d z ic z ą c ą p o E f f e c t , k t ó r a b ę d z ie r e a li z o w a ła tę fu n k c ję . P o p ie r w s z e s k o r z y s t a m y ze z m ie n n e j d o p r z e c h o w y w a n ia lo k a liz a c ji p o c z ą tk o w e j, o d któ re j ch c e m y p rze su w a ć ko m p o n e n t: p r i v a t e P o in t s t a r t L o c a t i o n = new P o i n t ( ) ;
/ /
i n ic j a li z a c ja g r a d ie n t u t ła z g o d n e g o z b i e ż ą c ą w y s o k o ś c ią
i n ic j a li z a c ja r e s u lt s E ff e c t p r z y u ży ciu b i e ż ą c e j w ie lk o ś c i
M o v e ln m o v e r = new M o v e In ( R E S U L T S _ X , g e t H e i g h t ( ) ) ; F a d e ln f a d e r = new F a d e l n Q ; m o v e r F a d e r = new C o m p o s i t e E f f e c t ( m o v e r ) ; m o v e rF a d e r.a d d E ffe c t(fa d e r); E f f e c t s M a n a g e r . s e t E f f e c t ( s c r o l l e r , m o v e r F a d e r, E f f e c t s M a n a g e r . T r a n s i t i o n T y p e . A P P E A R IN G ) ; p r e v H e ig h t = g e t H e i g h t Q ; }
N a s t ę p n i e p o t r z e b n y b ę d z ie k o n s t r u k t o r , w k t ó r y m o k r e ś l i m y lo k a liz a c j ę p o c z ą t k o w ą : p u b lic M o v e In ( in t x, in t y) { s t a r t L o c a t io n .x = x; s t a rt L o c a t io n .y = y; }
U t w o r z o n y t u o b ie k t G r a d ie n t P a i n t n ie je st z w ią z a n y z n a s z y m p r z e jś c ie m , a le p r z y k ł a d e m z a s t o s o w a n ia b o g a t e g o t ła d la tej p r o s t e j a p lik a c ji4. E f e k t M o v e ln t w o r z y m y p r z y u ż y c i u w y b r a n e j p r z e z n a s lo k a liz a c j i p o c z ą t k o w e j. W a r t o ś ć x je st id e n t y c z n a j a k w l o k a liz a c j i k o ń c o w e j k o m p o n e n t u , a w a r t o ś ć y je st r ó w n a w s p ó ł r z ę d
N a s t ę p n i e m o d y f i k u j e m y m e t o d ę i n i t ( ) , a b y s k o n f ig u r o w a ć a n im a c ję : p u b l i c v o id i n i t ( A n im a t o r a n im a t o r , E f f e c t p a r e n t E f f e c t ) { E f f e c t t a r g e t E f f e c t = ( p a r e n t E f f e c t == n u l l ) ? t h i s : p a r e n t E f f e c t ; P ro p e rtySe tte r p s ; p s = new P r o p e r t y S e t t e r ( t a r g e t E f f e c t , " l o c a t i o n " , s t a r t L o c a t i o n , new P o i n t ( g e t E n d ( ) , g e t X ( ) , g e t E n d ( ) . g e t Y ( ) ) ) ; a n im a t o r .a d d T a r g e t (p s ); s u p e r .in it (a n im a t o r , p a r e n t E f fe c t ); }
n ej d o ln e j k r a w ę d z i k o n t e n e ra . W a r t o ś c i te z a p e w n ia ją , że e fe k t M o v e ln s p o w o d u j e p io n o w e w s u n ię c ie k o m p o n e n t u o d d o ln e j c z ę ś c i o k n a . O c z e k i w a n y e fe k t w y ł a n i a n i a z r e a li z o w a l i ś m y p r z e z z a s t o s o w a n i e w b u d o w a n e g o e fe k t u F a d e ln . N a s z o b ie k t Com pos i te E j je c t u t w o r z y l i ś m y n a p o d s t a w ie e fe k t u p r z e s u n ię c ia , a n a s t ę p n ie d o d a l i ś m y e fe k t w y ła n ia n ia .
4 N ig d y n ie n a le ż y p r z e p u s z c z a ć o k a z ji n a w z b o g a c e n ie in t e r f e js u n a s z e j a p lik a c ji.
R o z d z ia ł 1 8.
536
B i b l io t e k a A n i m a t e d T r a n s it io n s
P ł y n n e p r z e jś c ia — b ib l i o t e k a
N a k o n i e c z a r e j e s t r o w a liś m y z b u d o w a n y w c z e śn ie j e fe k t m o v e rF a d e r w s y s t e m ie p r z e z u s t a
D o a n i m o w a n i a p r z e jś c ia p o m i ę d z y t y m i d w o m a s t a n a m i o k n a w y k o r z y s t a n a je st b ib lio t e k a
w i e n i e g o w w y n i k o w y m k o m p o n e n c i e s c r o H e r d la t y p u p r z e s u n i ę c ia A P P E A R IN G . P o
A n i m a t e d T r a n s it io n s . P r z y k ła d o w e p r z e jś c ie r e a liz o w a n e w p r z y p a d k u p o w ię k s z e n ia w ie l
w o d u j e to p o in f o r m o w a n ie o b ie k t u E f f e c t s M a n a g e r o k o n i e c z n o ś c i z a s t o s o w a n ia d a n e g o
k o ś c i m i n i a t u r z r y s u n k u 1 8 .8 je st p o k a z a n e n a k o l e j n y c h r y s u n k a c h 1 8 . 9 , 1 8 . 1 0 o r a z 18.11 .
e fe k tu w m o m e n c ie w y k o n y w a n ia p r z e jś c ia p o w o d u j ą c e g o p o j a w ie n ie się te g o k o m p o n e n t u
W a r t o z w r ó c ić u w a g ę , w j a k i s p o s ó b o b r a z z n a j d u j ą c y się n a r y s u n k u 18.8, p o p r a w e j s t r o
n a e k ra n ie .
n ie , w g ó r n y m w ie r s z u , p r z e s u w a się s t o p n io w o w d ó ł, n a k o ń c o w ą p o z y c ję d r u g ie g o o b r a z u w d r u g i m w ie r s z u n a r y s u n k u 18.11. W m ię d z y c z a s ie w s z y s t k ie p o z o s t a łe o b r a z y p r z e s u w a ją
T o w s z y s t k o w y k o n a liś m y w t y m p r o g r a m ie d e m o n s tr a c y jn y m . W p r z y k ła d z ie S e a rc h -
się n a ic h k o ń c o w e p o z y c je i w s z y s t ld e o b r a z y s t o p n i o w o p o w ię k s z a j ą się d o n o w e j w ie lk o ś c i.
T r a n s i t i o n z n a j d u j e się r ó w n i e ż n ie c o p r o s t e g o k o d u S w i n g , z a p e w n ia j ą c e g o t w o r z e n ie
. __________
i w y ś w ie t la n ie o k n a a p lik a c j i, a le c a ł y in t e r e s u j ą c y n a s k o d o b s ł u g u j ą c y p r z e j ś c ie je s t t u p r z e d s t a w io n y . O c z y w iś c ie , a p lik a c j a ta je st d o s y ć o g r a n ic z o n a , a le r z e c z y w is t e a p lik a c je p o w i n n y b y ć b a r d z ie j s k o m p li k o w a n e . Z d r u g ie j s t r o n y p o k a z a l i ś m y tu , j a k ła t w o m o ż n a d o d a w a ć f u n k c j e p r z e jś c ia , w r a z z w ł a s n y m i e fe k ta m i, d o s t a n d a r d o w e j a p lik a c j i S w in g .
m Przykład ImageBrowser
p®
.
DEMO W SIECI
P r o g r a m S e a r c h T r a n s i t i o n b y ł g r a f ic z n ie o g r a n i c z o n y , d z ię k i c z e m u m o g l i ś m y s ię s k u p i ć n a p o d s t a w o w y c h f u n k c j a c h b ib li o t e k i A n i m a t e d T r a n s i t i o n r W a r t o p r z e d s t a w ić je sz c z e j e d n ą a p lik a c ję , k t ó r a p o z w o l i n a m p o k a z a ć ła t w o ś ć u ż y c i a b ib lio t e ld w b o g a t s z y m g r a
m
1
h
fic z n ie ś r o d o w is k u . K o l e j n y p r z y k ła d m o ż n a z n a le ź ć w p r o je k c ie Im a g e B ro w se r, z n a j d u j ą c y m się n a w i t r y n i e W W W p o ś w ię c o n e j tej k s ią ż c e . W i ę k s z o ś ć z n a s p r a w d o p o d o b n i e k o r z y s t a ła z p r o g r a m ó w d o p r z e g lą d a n ia z d ję ć — p r o g r a m ó w d z ia ła ją c y c h j a k o s a m o d z ie ln a a p lik a c ja a lb o j a k o a p lik a c ja W W W . S t a n d a r d o w y m
R y s u n e k 1 8 .8 . P r o g r a m d e m o n s t r a c y jn y I m a g e B r o w s e r — a n im o w a n e p r z e jś c ie r e a liz o w a n e w m o m e n c ie z m ia n y r o z m ia r u m in ia t u r p r z e z u ż y tk o w n ik a
e le m e n t e m in t e r f e j s u w t y c h a p lik a c j a c h je st w s p ó ł c z y n n i k p o w ię k s z e n ia , k t ó r y p o z w a la z m i e n i ć r o z m i a r m i n i a t u r p r z e g lą d a n y c h zd ję ć. Z m i a n a t e g o w s p ó ł c z y n n i k a je st r e a liz o
E i Pi /pgliiddrkd abrdzöv
:=JaJxJ
w a n a z w y k le z a p o m o c ą s u w a k a , k t ó r e g o p r z e s u w a n ie p o w o d u j e p o w ię k s z a n ie lu b z m n ie j s z a n ie w i e l k o ś c i m in ia t u r . Z m i a n a w i e l k o ś c i m i n i a t u r w p ł y w a n a w s z y s t ld e e le m e n t G U I . W s z y s t k i e m i n i a t u r y z m i e n ia ją s w o ją w ie lk o ś ć , w ię c ic h p o ło ż e n ie m u s i z o s t a ć o d p o w i e d n i o z m ie n io n e . B y ł o b y m iło , g d y b y te z m i a n y u k ł a d u b y ł y a n im o w a n e z a p o m o c ą p ł y n n e g o p r z e j ś c ia p o m i ę d z y s t a n e m p r z e d z m i a n ą i p o z m i a n i e w i e lk o ś c i m in ia t u r . P r o s t y p r o g r a m Im a g e B ro w se o d c z y t u j e w s z y s t ld e o b r a z y z k a t a lo g u i w y ś w ie t la je w f o r m ie m in ia t u r , j a k je st t o p o k a z a n e n a r y s u n k u 18.8. W d o ln e j c z ę ś c i o k n a z n a jd u je s ię s u w a k p o z w a la j ą c y s t e r o w a ć w ie lk o ś c ią m in ia t u r . W c z a s ie p r z e s u w a n ia s u w a k a z m ie n ia j ą się w ie l k o ś c i m i n i a t u r . T a z m i a n a w ie l k o ś c i w y m u s z a n a o b ie k c i e z a r z ą d c y u k ł a d u , w t y m p r z y p a d k u F I o w L a y o u t, o d p o w ie d n i ą z m i a n ę p o ło ż e n ia w s z y s t k i c h o b r a z ó w .
R y su n ek 1 8 .9 . Im ag eB ro w ser — ro zp o częcie p rz ejścia do w iększych m in iatu r
R o z d z ia ł 1 8 .
P ł y n n e p r z e jś c ia — b ib l io t e k a *
B ib l io t e k a A n i m a t e d T r a n s it io n s
-----
P r z e d e w s z y s t k i m n a le ż y z a u w a ż y ć , że w p r z e c iw ie ń s t w ie d o S e a r c h T r a n s i t i o n w y k o r z y s t a n y z o s t a ł o b ie k t L a y o u tM a n a g e r . W ! S e a r c h T r a n s i t i o n z a s t o s o w a l iś m y p u s t y L a y o u t M a n a g e r w c e lu u p r o s z c z e n i a r o z m i e s z c z a n i a k o m p o n e n t ó w w o k r e ś l o n y c h o b s z a r a c h o k n a . J e d n a k w Im a g e B r o w s e r m e n e d ż e r u k ł a d u j e s t n ie z w y k ł e w a ż n y d la d z ia ł a n i a a p lik a c j i. O c z y w i ste je st, że n ie b ę d z i e m y c h c i e l i z m i e n i a ć p o ł o ż e n i a w s z y s t k i c h m i n i a t u r w z a l e ż n o ś c i o d i c h w i e l k o ś c i o r a z o d w i e l k o ś c i o k n a . B y ł o b y to t w o r z e n ie w ł a s n y c h f u n k c j i o b ie k t u L a y o u tM a n a g e r. W t y m k o d z ie s k o r z y s t a m y z F lo w L a y o u t , k t ó r y r o z m ie s z c z a o b r a z y w k o le j n o ś c i o d le w e j d o p r a w e j i o d g ó r y d o d o łu . Jest to w a ż n y p u n k t . Z a m ie ś c il iś m y g o w c ze śn ie j, ale b y ł o n raczej te o re ty c z n y . P o w t ó r z y m y go.
\ I /
W skazów ka B ib lio t e k a A n im a t e d T r a n s itio n s w s p ó łp r a c u je d o b r z e z o b ie k t a m i LayoutM anager. K o r z y s ta o n a
ąs
z p o z y c jo n o w a n ia b e z w z g lę d n e g o w c z a s ie a n im o w a n ia p r z e jś c ia k o m p o n e n t u d o n o w e j lo k a li z a c ji, w ie lk o ś c i i o r ie n t a c ji. J e d n a k m o ż liw e j e s t z a c h o w a n ie z g o d n o ś c i z d o w o ln y m z a rz ą d c ą u k ła d u z a r ó w n o n a e k r a n ie p o c z ą tk o w y m , j a k i k o ń c o w y m . W r z e c z y w is to ś c i z a r z ą d c y u k ła d u n a o b u e k r a n a c h m o g ą s ię n a w e t r ó ż n ić . J e d e n z a rz ą d c a u k ła d u m o ż e b y ć u ż y ty n a e k r a n ie p o
R y s u n e k 1 8 .1 0 . I m a g e B r o w s e r — n ie m a l z a k o ń c z o n e p r z e jś c ie
c z ą tk o w y m , in n y n a e k r a n ie k o ń c o w y m , a p r z e jś c ie b ę d z ie d z ia ła ło b e z z a rz u tu .
I n n y m w a ż n y m p u n k t e m d e m o n s t r o w a n y m w tej a p lik a c ji je st m ie jsc e w y k o n y w a n i a p r z e j śc ia w o k n ie . W p r o j e k c ie S e a r c h T r a n s i t i o n p r z e jś c ie z a j m o w a ł o c a ły e k r a n , a le m o ż n a r ó w n ie ż z r e a liz o w a ć je w i n n y s p o s ó b .
W skazów ka P r z e jś c ie m o ż e b y ć r e a liz o w a n e w d o w o ln y m k o n t e n e r z e w e w n ą tr z o k n a a p lik a c ji. P r z e jś c ie n ie if
m u s i z a jm o w a ć c a łe g o o k n a S w in g ; m o ż n a j e o g r a n ic z y ć d o d o w o ln e g o k o n t e n e r a w e w n ą tr z te g o o k n a.
W t a k i m p r z y p a d k u c h c e m y u r u c h o m i ć p r z e j ś c ie t y l k o w o b s z a r z e p r z e g lą d a n ia o b r a z ó w . O b s z a r z a w ie r a j ą c y s u w a k je st o d d z i e l o n y o d p r z e g l ą d a r k i z d ję ć i n ie je st u ż y w a n y w a n i m a c j i p rz e jś c ia . W a r t o r ó w n ie ż w s p o m n ie ć , że k o r z y s t a m y t u z n ie c o z m o d y f ik o w a n e j w e r s ji p r o g r e s y w n e g o s k a lo w a n i a d w u l i n i o w e g o , p r z e d s t a w io n e g o w r o z d z ia le 4., „ O b r a z y ” . T e c h n i k a ta p o z w a la R y s u n e k 1 8 .1 1 . I m a g e B r o w s e r — z a k o ń c z o n e p r z e jś c ie
n a u z y s k a n i e b a r d z o d o b re j j a k o ś c i s k a lo w a n y c h o b r a z ó w , p r z y z a c h o w a n i u d o b r e j w y d a j n o ś c i. M e t o d a s k a lo w a n ia je st n a jw a ż n ie js z a d la u z y s k a n ia o d p o w ie d n ie j w y d a j n o ś c i i j a k o ś c i
W i ę k s z o ś ć f u n k c j i a n im a c j i p r z e j ś ć r e a liz o w a n y c h w Im a g e B r o w s e r z o s t a ła p r z e d s t a w io n a
t e g o t y p u a p lik a c ji, p o n i e w a ż z a s t o s o w a n ie m i n i a t u r w y m a g a u ż y c ia d u ż e j il o ś c i o p e ra c ji
w c z e ś n ie j, z a r ó w n o w p r o g r a m ie d e m o n s t r a c y j n y m S e a r c h T r a n s i t i o n , j a k i w o p is ie A P I
s k a lo w a n ia o r y g i n a l n y c h o b r a z ó w .
b ib lio t e k i A n i m a t e d T r a n s i t i o n s . Is t n ie j e j e d n a k k i l k a w a ż n y c h e le m e n t ó w ’’ a p lik a c ji, k t ó r e w a r t o p r z e d s t a w ić .
T e r a z , p o p r z e d s t a w ie n iu in t e r e s u ją c y c h e le m e n t ó w tej a p lik a c ji, p o k a ż e m y k o d p o z w a la ją c y n a i c h realizację . N i e b ę d z ie m y j e d n a k p r z e d s t a w ia ć t u c a ło ś c i k o d u , w ię c o d s y ł a m y n a w i t r y n ę W W W k s ią ż k i, g d z ie m o ż n a - z n a le ź ć p o z o s t a łe sz c z e g ó ły . O p i s z e m y t u n a jb a r d z ie j i n te re su ją c e c z ę ś c i n a s z e j p r a c y , s z c z e g ó ln ie o d n o s z ą c e się d o a n i m o w a n y c h p rz e jś ć .
R o z d z ia ł 1 8 .
B ib l io t e k a A n i m a t e d T r a n s it io n s
P ł y n n e p r z e jś c ia
— b ib l i o t e k a
W g r a fic e z a p a m ię t a n e w s t ę p n ie p r z e s k a lo w a n e w e r sje o r y g i n a l n e g o o b r a z u s ą n a z y w a n e
Struktura GUS
mipmapą. T e c h n ik a ta je st p o w s z e c h n ie w y k o r z y s t y w a n a w g ra c h , g d z ie t e k s t u r y n a k ła d a n e
O k n o z a w ie r a o b ie k t JF ra m e, k t ó r y m a w d o ln e j c z ę ś c i J S 1 i d e r p o z w a la j ą c y n a st e r o w a n ie r o z m i a r a m i m i n i a t u r o r a z n a s z w ł a s n y J C o m p o n e n t Im a g e B r o w s e r , w k t ó r y m s ą p o k a z y w a n e o b ra zy : JF ra m e f = new J F r a m e ( " P r z e g l ą d a r k a o b r a z ó w " ) ; f.se tL a y o u t(n e w B o r d e rL a y o u t ()); Im a g e B ro w s e r c o m p o n e n t = new Im a g e B r o w s e r ( ) ; f.a d d (c o m p o n e n t, B o rd e rL a y o u t.C E N T E R ); J S l i d e r s l i d e r = new J S l i d e r ( l , 4 0 0 / S L ID E R _ IN C R E M E N T , c u r r e n t S i z e / ^ S L ID E R J N C R E M E N T ) ; f . a d d ( s l i d e r, B o rd e rL a y o u t.S O U T H );
n a o b ie k t y tr ó j w y m ia r o w e m o g ą b y ć z a p a m ię t y w a n e w k i l k u r ó ż n y c h w ie lk o śc ia c h . W n a s z y m p r z y p a d k u , p o d o b n i e j a k w p r z y p a d k u g ie r t r ó j w y m ia r o w y c h , p o d e jś c ie ta ld e z a s t o s o w a li ś m y z d w ó c h p o w o d ó w — j a k o ś c i i s z y b k o ś c i. P r o b l e m z j a k o ś c i ą z o s t a ł p r z e d s t a w io n y w r o z d z ia l e 4. P r z e z k o le j n e s k a l o w a n i e o 5 0 % p r z y u ż y c iu filt ro w a n ia d w u lin io w e g o m o ż e m y o s ią g n ą ć b a r d z o w y s o k ą j a k o ś ć w p r z y p a d k u b a r d z o m a ł y c h m i n i a t u r b e z u t r a t y w y d a j n o ś c i p o w o d o w a n e j p r z e z n ie k t ó r e m e t o d y s k a lo w a n i a 5. P r o b l e m z s z y b k o ś c ią n ie d o t y c z y w y łą c z n ie p o c z ą t k o w e g o s k a lo w a n ia , a le r ó w n i e ż o p e r a c ji s k a lo w a n i a d la p r z y s z ły c h w ie lk o ś c i m in ia t u r . Z a k a ż d y m r a z e m , g d y u ż y t k o w n i k w y b ie r z e n o w ą w ie l k o ś ć m in ia t u r y , a p lik a c j a m u s i u t w o r z y ć o b r a z ta k ie j w i e lk o ś c i w p o s t a c i
Obrazy S Im ageHolder
o b ie k t u Im a g e lc o n d la k o m p o n e n t u J L a b e l. Z a w s z e m o ż n a s k a lo w a ć o r y g i n a l n y o b ra z , ale z n a c z n ie s z y b c ie j je st z m n ie j s z y ć t e n o b r a z , k t ó r y je st n a j b liż s z y p o t r z e b n e j w ie lk o ś c i. D o
W y ś w ie t la n e o b r a z y są w r z e c z y w is t o ś c i o b ie k t a m i J L a b e l ze s k o j a r z o n ą w a r t o ś c ią Im a g e lc o n ,
te g o c e lu w y k o r z y s t a n y z o s t a ł o b ie k t Im a g e H o ld e r, k t ó r y p o z w a la p r z e c h o w y w a ć r ó ż n e w e r
O b i e k t y Im a g e lc o n s ą t w o r z o n e n a p o d s t a w i e o b r a z ó w ł a d o w a n y c h z k a t a l o g u n a d y s k u .
sje o r y g i n a l n e g o o b r a z u , m a ją c e r ó ż n e w ie lk o ś c i. Je że li b ę d z i e m y p o t r z e b o w a l i m i n i a t u r y
D l a k a ż d e g o o b r a z u t w o r z y m y o b ie k t Im a g e H o l d e r, w k t ó r y m p r z e c h o w u j e m y w ie le w e r s ji
o n o w e j w ie lk o ś c i, m o ż e m y p o b r a ć z Im a g e H o l d e r o b r a z o ż ą d a n e j w ie lk o ś c i, a o t r z y m a m y
o b ra z u , o d o r y g in a ln e j w ie lk o ś c i a ż d o b a r d z o m a łe j ik o n y . S k a lu j e m y o r y g i n a ł o p o ło w ę , n a
n a j b liż s z ą w s t ę p n ie p r z e s k a l o w a n ą w e rsję . P o n iż e j z a m i e s z c z o n y je st k o d p o z w a la j ą c y n a
st ę p n ie s k a l u j e m y n o w ą w e r s ję d o p o ł o w y i t a k d a le j, a ż d o o s ią g n ię c ia w ie lk o ś c i M I N J I Z E ,
p o d s t a w ie z a w a r t o ś c i Im a g e H o ld e r u s t a w ić w k o m p o n e n c i e J L a b e l o b ie k t Im a g e lc o n z a w ie r a ją c y o b r a z o w ie lk o ś c i c u r r e n t S i ze:
z a p is u j ą c k a ż d y k o l e j n y o b r a z . P o n iż e j p r z e d s t a w io n y je s t k o n s t r u k t o r Im a g e H o l d e r, k t ó r y p o b ie r a Im age, z a p a m ię t u je go , a n a s t ę p n ie t w o r z y i z a p is u je p r z e s k a lo w a n e w e rsje w z m ie n n e j
la b e l[ i] . s e t Ic o n ( n e w
Im a g e Ic o n ( im a g e s . g e t ( i) . g e t lm a g e ( c u r r e n t S iz e ) ) ) ;
A r r a y L is t . p r i v a t e L i s t < B u f f e r e d Im a g e > s c a le d lm a g e s = new A r r a y L i s t < B u f f e r e d I m a g e > ( ) ;
M o ż n a t u z a u w a ż y ć w y w o ła n i e g e t lm a g e ( ) , w c z a s ie r e a liz a c ji k t ó r e g o , n a p o d s t a w ie p o d a n e j s z e r o k o ś c i o b ie k t Im a g e H o l d e r z w r ó c i p r o p o r c j o n a ln i e p r z e s k a l o w a n y o b ra z :
Im a g e H o ld e r ( B u f f e r e d lm a g e o r i g i n a l Im a g e ) { i n t im ageW = o r i g i n a l I m a g e . g e t W id t h ( ) ; , i n t im a geH = o r i g i n a l Im a g e . g e t H e i g h t Q ; s c a le d lm a g e s . a d d ( o r ig in a lIm a g e ) ; B u f f e r e d lm a g e p r e v lm a g e = o r i g i n a l Im a g e ; w h il e (im ageW > M I N J I Z E && im a geH > M I N J I Z E )
B u f f e r e d l m a g e g e t l m a g e ( i n t w id t h ) { f o r ( B u f f e r e d lm a g e s c a le d lm a g e : s c a le d l m a g e s ) i n t sc a le d W = s c a l e d l m a g e . g e t W i d t h ( ) ;
{
im ageW = im ageW » 1 ; im a geH = im a geH » 1; B u f f e r e d lm a g e s c a le d lm a g e = new B u ffe r e d Im a g e (im a g e W , im a ge H , p r e v lm a g e . ^ ► g e tT y p e O ); G r a p h ic s 2 D g 2 d = s c a l e d I m a g e . c r e a t e G r a p h i c s ( ) ; g 2 d . s e t R e n d e r i n g H i n t ( R e n d e r i n gH i n t s . K E Y _ IN T E R P O L A T IQ N , R e n d e r i n g H i n t s . V A L U E _ IN T E R P O L A T IO N _ B IL IN E A R ); g 2 d . d r a w lm a g e ( p r e v lm a g e , 0 , 0 , im ageW , im a g e H , n u l i ) ; g 2 d .d is p o s e ! ) ; s c a le d lm a g e s .a d d ( s c a le d lm a g e );
{
/ /
W ybór o b ra z u d o s k a lo w a n ia :
/ /
-
II
- ż ą d a n a w ie lk o ś ć z n a jd u je s i ę p o m ię d z y w i e l k o ś c i ą b i e ż ą c ą i n a s t ę p n ą
/ /
- j e s t to o b r a z o n a jm n ie js z e j w ie lk o ś c i (o sta tn i)
if
ż ą d a n a w ie lk o ś ć j e s t w ię k s z a n iż j e g o w ie lk o ś ć
(s c a le d W < w id t h || ( ( s c a le d W » ( ( s c a le d W » 1) < M I N J I Z E ) ) { i f ( s c a le d W != w id t h ) { / / / /
1) < w id t h )
||
T w o r z e n ie n o w e j w e r s ji w y s k a lo w a n e j d o p o d a n e j s z e r o k o ś c i ./ p r o p o r c jo n
a ln e j w y so kości
f l o a t s c a l e F a c t o r = ( f l o a t ) w i d t h / sc a le d W ; i n t s c a le d H = ( i n t ) ( s c a l e d l m a g e . g e t H e i g h t ( ) * s c a l e F a c t o r + . 5 f ) ; 5 Je ż e li C z y te ln ik p o m in ą ł t e n p u n k t, p r o p o n u je m y d o n ie g o w r ó c ić lu b c o n a jm n ie j z a p a m ię ta ć p o r a d ę —- n ie k o r z y s ta m y z g e t S c a l e d I n s t a n c e ( ) . Z a s to s o w a n a tu m e to d a p r o g re s y w n e g o s k a lo w a n ia d w u lin io w e g o , k tó r a zo sta ła o m ó w io n a d o k ła d n ie w e w cz eśn ie jsz y m ro zd ziale, d a je p o d o b n ą ja k o ś ć p rz y u ła m k u p o trz e b n e g o czasu .
R o z d z ia ł 1 8 .
B ib l io t e k a A n i m a t e d T r a n s it io n s
B u f f e r e d lm a g e im a ge = new B u f f e r e d l m a g e ( w id t h , s c a le d H , s c a le d lm a g e . ^ g e tT y p e ()); G r a p h ic s 2 D g 2 d = im a g e . c r e a t e G r a p h i c s ( ) ; g 2 d . s e t R e n d e r in g H in t ( R e n d e r i n g H i n t s . K E Y _ IN T E R P O L A T IO N , R e n d e r in g H i n t s . V A L U E _ IN T E R P O L A T IO N _ B IL IN E A R ) ; g 2 d . d r a w lm a g e ( s c a le d lm a g e , 0 , 0 , w i d t h , s c a le d H , n u l i ) ; g 2 d .d is p o s e (); s c a le d lm a g e = im a g e ; } r e t u r n s c a le d lm a g e ; } }
P ł y n n e p r z e jś c ia
— m e c h a n iz m y
w e w n ę t r z n e , c z y l i ja k z m u s ić
p u b lic v o id se t u p N e x t S c re e n Q { f o r ( in t i = 0 ; i < im a g e s . s iz e Q ; + + i) la b e l[ i] . s e t Ic o n ( n e w
S w in g d o t a k i c h r z e c z y
{
Im a g e Ic o n ( im a g e s . g e t ( i) . g e t lm a g e ( c u r r e n t S iz e ) ) ) ;
} re va l i d a t e Q ; 1 W a r t o p r z e d s t a w ić je s z c z e j e d e n p r o b le m . D o r e a liz a c j i e fe k t u M o v e / S e a l e n a n a s z y c h m i n ia t u r a c h w y k o r z y s t a l i ś m y w ł a s n y efekt. D o m y ś l n i e b ib lio t e k a k o r z y s t a z b a r d z o p o d o b n e g o e fe k tu , k t ó r y r ó ż n i s ię w j e d n y m w a ż n y m a s p e k c ie — w y m u s z a o n p r z e r y s o w a n ie k o m p o n e n t u w k a ż d e j r a m c e . P o d e j ś c ie to uniemożliwia s t o s o w a n i e m e t o d o b s ł u g i o b r a z u w y k o
// sterow anie nie p o w in n o tu trafić
r z y s t y w a n y c h p r z e z w i ę k s z o ś ć p o z o s t a ł y c h e fe k t ó w , w k t ó r y c h p o p r o s t u m a n i p u l u j e m y
re tu rn n u li;
w c z e ś n ie j p r z y g o t o w a n y m i o b r a z a m i k o m p o n e n t ó w w c z a s ie p r z e jś c ia . W y m u s z e n i e p r z e r y s o w a n i a k o m p o n e n t u je st d o m y ś l n i e s t o s o w a n e d l a w s z y s t k i c h e f e k t ó w S c a l e, p o n ie w a ż
}
s k a lo w a n ie p o w o d u je , ż e w ię k s z o ś ć k o m p o n e n t ó w ź le w y g lą d a i w c z a s ie p r z e jś c ia w id o c z n e
ScreenTransition K o n f i g u r a c j a o b ie k t u S c r e e n T r a n s i t i o n je st d o s y ć p o d o b n a d o p r z e d s t a w io n e j w c z e ś n ie j w a p lik a c j i S e a r c h T r a n s i t io n . T w o r z y m y o b ie k t A n im a to r, u s t a w ia m y je g o n ie lin io w e d z ia ła n ie , a b y a n im a c j a w y g lą d a ła le p ie j, a n a s t ę p n ie t w o r z y m y o b ie k t S c r e e n T r a n s i t i o n . N a p i s a n y p r z e z n a s k o m p o n e n t Im a g e B r o w s e r b ę d z ie u ż y t y z a r ó w n o j a k o T r a n s i t i o n T a r g e t w m e t o d z i e w y w o ł a n i a z w r o t n e g o s e t u p N e x t S c r e e n Q , j a k i j a k o k o n t e n e r d o a n im a c j i p r z e j ś c ia : A n im a t o r a n im a t o r = new A n i m a t o r ( 5 0 0 ) ; a n im a t o r .s e t A c c e le r a t io n (.lf ); a n im a t o r .s e t D e c e le r a t io n (.4 f ); S c r e e n T r a n s i t i o n t r a n s i t i o n = new S c r e e n T r a n s i t i o n ( t h i s , t h i s , a n i m a t o r ) ;
s ą a rte fa k ty . J e d n a k w t y m p r z y p a d k u n a s z o b ie k t J L a b e l jest o b r a z e m , w ię c s k a lo w a n ie k o m p o n e n t u p r z y u ż y c i u m e t o d d o t y c z ą c y c h o b r a z ó w d z ia ła b e z z a r z u tu . U t w o r z y l i ś m y w ię c w ł a s n y efekt M o v e / S c a le , w k t ó r y m z a p o m o c ą m e t o d y se tR e n d e rC o m p o n e n tQ w s k a z a li ś m y sy s t e m o w i, że m o ż n a u ż y w a ć o b r a z ó w w c z a s ie p r z e jś c ia : E f f e c t e f f e c t = new M o v e Q ; E f f e c t s c a l e E f f e c t = new S c a l e Q ; e f f e c t = new C o m p o si t e E f f e e t ( e f f e c t ) ; { (C o m p o s it e E f fe c t )e f fe c t ).a d d E ff e c t (s c a le E ffe c t ); e f f e c t .s e t R e n d e r C o m p o n e n t (fa ls e ); E f f e c t s M a n a g e r . s e t E f f e c t ( l a b e l [ i ] , e f f e c t , T r a n s it io n T y p e . C H A N G IN G ) ; G ł ó w n a c z ę ś ć k o d u d la tej a p lik a c j i z o s t a ła p r z e d s t a w io n a w c z e śn ie j. W a r t o z a p o z n a ć się ze s z c z e g ó ła m i k o d u tej a p lik a c ji, k t ó r a je st d o s t ę p n a n a w it r y n ie W W W tej k s ią ż k i. Jest t o n ie z ła a p lik a c ja n a p o c z ą t e k n a u k i w y k o r z y s t a n ia e fe k t ó w i f u n k c j i d o s t ę p n y c h w b ib lio te c e
G d y z o s t a n ie w y k r y t e z d a r z e n ie s u w a k a , n a s z o b ie k t o t r z y m a w y w o ł a n i e z w r o t n e m e t o d y
A n i m a t e d T r a n s i t i o n s . W a r t o p o ś w ię c ić n ie c o c z a s u n a z a b a w ę !
s t a t e C h a n g e d Q . M e t o d a ta u s t a w ia w a r t o ś ć z m ie n n e j c u r r e n t S i z e , k t ó r a ste ru je w ie lk o ś c ią ; n a s z y c h m in ia t u r . N a s t ę p n ie w y w o ły w a n a je st m e t o d a t r a n s i t i o n . s t a r t ( ): p u b lic void s t a t e C b a n g e d f C h a n g e E v e n t c e ) { c u r r e n t S i z e = s l i d e r . g e t V a lu e ( ) * 2 5 ; t r a n s it io n . s t a r t (); } N a p o c z ą t k u o p e r a c j i p r z e j ś c ia o t r z y m u j e m y w y w o ł a n ie z w r o t n e n a s z e j m e t o d y s e t u p -
Płynne przejścia — ■mechanizmy wewnętrzne, czyli jak zmusić Swing do takich rzeczy Zignoruj człowieka za kurtynę.
N e x t s c r e e n ( ) , k t ó r e p o w o d u j e z m ia n ę w ie lk o ś c i w s z y s t k ic h m i n i a t u r p r z e z u s t a w ie n ie n o w y c h o b ie k t ó w Im a g e lc o n , b a z u j ą c y c h n a o b r a z a c h t w o r z o n y c h p r z e z Im a g e H o l d e r z g o d n ie
— Czarnoksiężnik z krainy Oz, F r a n k L. B a u m
z b ie ż ą c ą w a r t o ś c ią c u r r e n t S iz e . P o z w a la to s k o n f ig u r o w a ć n a s t ę p n y e k ra n , d o k t ó r e g o b ę d zie p r o w a d z i ła a n im a c j a , a n a s t ę p n ie u r u c h o m i ć a n im a c ję :
W s z y s t k i e in f o r m a c j e p o t r z e b n e d o u ż y c ia b ib lio t e k i z o s t a ły p r z e d s t a w io n e w e w c z e śn ie jsz e j c z ę ś c i r o z d z ia łu . Je ż e li j e d n a k C z y t e l n i k d o t a r ł tale d a le k o w k s ią ż c e n a t e m a t S w i n g o r a z g r a f ik i, p r a w d o p o d o b n i e b ę d z ie c ie k a w y , j a k f a k t y c z n ie d z ia ła j ą n i e k t ó r e z m e c h a n iz m ó w .
544
R o z d z ia ł 1 8 .
B ib l io t e k a A n i m a t e d T r a n s it io n s
P ł y n n e p r z e jś c ia
D z i a ła n i e b ib lio t e k i A n i m a t e d T r a n s i t i o n s k r y je w ie le s z c z e g ó łó w . W p r z y p a d k u s z c z e g ó łó w
— m e c h a n iz m y
w e w n ę t r z n e , c z y l i ja k z m u s ić
S w in g d o t a k i c h r z e c z y
Ukrycie poza widokiem
z a le c a m y z a p o z n a n ie s ię z k o d e m ź r ó d ł o w y m b ib l i o t e k i d o s t ę p n y m n a w it r y n ie W W W tej k s ią ż k i. M o ż n a t u z n a le ź ć j e d n a k k i l k a s z c z e g ó łó w , k t ó r e m o g ą b y ć in t e r e s u ją c e d la p r o
D r u g i e p o d e jśc ie , w y k o r z y s t a n e w b ie ż ą c e j im p le m e n t a c ji, p o le g a n a u k r y c i u k o n t e n e r a a p li
g r a m is t ó w S w i n g i k t ó r e p o k a z u ją , w j a k i s p o s ó b u d a ło n a m się z m u s ić A n im a t e d T r a n s it io n s
k a c j i p r z e d w p r o w a d z e n i e m u k ła d u . P o d e j ś c ie to d z ia ła p o d o b n i e j a k p ie r w s z e , p o z a t y m
d o d z ia ła n ia .
że u ż y t k o w n i k w i d z i i n n y s k o n f i g u r o w a n y k o n t e n e r , w y g lą d a j ą c y d o k ła d n i e j a k p o p r z e d n i e k ra n , z a m ia s t f a k t y c z n e g o k o n t e n e r a d la k o m p o n e n t ó w . W m ię d z y c z a s ie b ib lio t e k a p o z w a la a p lik a c j i n a w y k o n a n i e n i e z b ę d n y c h z m i a n u k ł a d u n a p o t r z e b y d r u g i e g o e k r a n u ,
Konfigurowanie następnego ekranu — po cichu P ie r w s z e p y t a n ie , k t ó r e m o g ą z a d a w a ć p r o g r a m i ś c i S w i n g , b r z m i: „ W j a k i s p o s ó b d e f in i u j e m y n a s t ę p n y e k r a n z p r a w i d ł o w y m u k ła d e m , a le b e z w y ś w ie t la n ia g o u ż y t k o w n i k o w i ? ” . O z n a c z a to , że g d y z o s t a n ie w y w o ł a n a m e t o d a s e t u p N e x t S c r e e n ( ) , n a s z k o d b ę d z ie m u s ia ł
c o je st w y k o n y w a n e d y n a m i c z n i e p o z a e k r a n e m .
W skazów ka M e t o d a ta k o rz y sta z tego, że o k re śla n ie u k ła d u m o ż e b y ć w y k o n y w a n e na w e t w n ie w id o c z n y m kontene rze .
p r a w i d ł o w o s k o n f ig u r o w a ć k o m p o n e n t y w k o n t e n e r z e , w r a z z k o n t r o lą p o p r a w n o ś c i S w in g . J e d n a k w y k o n y w a n i e t e g o w n o r m a l n y s p o s ó b s p o w o d u j e , że u ż y t k o w n i k b ę d z ie w i d z ia ł k o m p o n e n t y u s t a w ia n e n a e k r a n ie p r z e d u r u c h o m i e n i e m p r z e j ś c ia 6.
d a n e n a t e m a t k o m p o n e n t ó w , a n a s t ę p n ie u r u c h o m i ć a n im a c ję . N a l e ż y p a m ię t a ć , że p r z e j
N a s z c z ę ś c ie is t n ie ją s p o s o b y w y k o n a n i a k o n t r o l i p o p r a w n o ś c i u k ł a d u S w i n g b e z p o w o d o w a n i a a k t u a liz a c j i w i d o c z n e j p r z e z u ż y t k o w n i k a n a e k r a n ie . W
P o w p r o w a d z e n i u z m i a n u k ł a d u d la d r u g i e g o e k r a n u b ib lio t e k a m o ż e o d c z y t a ć p o t r z e b n e
c z a s ie u r u c h a m i a n i a
b i b l i o t e k i w y p r ó b o w a l i ś m y d w a p o d e j ś c ia i o b a d z ia ła ją c a ł k ie m n ie ź le .
Ukrywanie w widoku P o d e jś c ie to k o r z y s t a ze s z k la n e g o p a n e lu o k n a d o u k r y c i a s z c z e g ó łó w u k ła d u . P o r o z p o c z ę c i u p r o c e s u p r z e j ś c ia b ib li o t e k a a u t o m a t y c z n i e o d c z y t u j e d a n e z n a j d u j ą c e s ię n a e k r a n ie i t w o r z y o b r a z b ę d ą c y z d ję c ie m e k r a n u . P r z y p o m i n a t o d e k o r a c je f ilm o w e z n a m a lo w a n y m z a m k ie m , k t ó r y z w ię k sz e j o d le g ło ś c i m o ż e u d a w a ć r z e c z y w is t y z a m e k . N a s t ę p n ie r y s u j e m y te n o b r a z n a s z k l a n y m p a n e lu r a m k i, c o p o w o d u j e , że w i d o c z n y je st t y lk o s z k l a n y e k ra n . O b r a z je st n ie p r z e z r o c z y s t y , w ię c n ic n ie p r z e ś w itu je . N a s t ę p n ie b ib lio t e k a p r z e o r g a n iz o w u j e o k n o a p lik a c ji z g o d n ie z u k ła d e m n a n a s t ę p n y m e k ra n ie . U k ł a d te n je st t w o r z o n y d y n a m ic z nie , a le je st u k r y t y p r z e d u ż y t k o w n i k ie m p r z e z n ie p r z e z r o c z y s t y s z k l a n y p a n e l. Z p u n k t u w i d z e n i a u ż y t k o w n i k a a p lik a c j a sta le w y ś w ie t la p i e r w s z y e k r a n 7.
ś c ie je st w y k o n y w a n e s z y b k o , d z ię k i c z e m u n ie o t r z y m u j e m y n i e o c z e k iw a n y c h w y n i k ó w , t a la c h j a k k l ik a n i e p r z e z u ż y t k o w n i k a o b r a z u p r z y c i s k u w c z a s ie a n im a c j i i b r a k u r e a k c ji te g o k o m p o n e n t u .
Anim ow anie zm ian układu D r u g i e p y t a n ie , j a k ie m o ż e z a d a ć p r o g r a m i s t a S w in g , b r z m i: „ W j a k i s p o s ó b a n i m u j e m y u k ła d , k t ó r y z m i e n i a s ię m i ę d z y e k r a n a m i ? ” . P r o b l e m t e n w y d a j e s ię s z c z e g ó l n ie z ł o ż o n y w p r z y p a d k u s t o s o w a n ia m e n e d ż e r ó w u k ła d u , p o n ie w a ż to o n e k o n t r o lu j ą p o ło ż e n ie i w y m i a r y k o m p o n e n t ó w . P o d o b n i e j a k n ie m o ż e m y p o z y c j o n o w a ć k o m p o n e n t ó w w s p o s ó b b e z w z g lę d n y d la k o n k r e t n y c h ( r ó ż n y c h o d n u l 1 ) m e n e d ż e r ó w u k ł a d u i o c z e k iw a ć , że n a r z u c o n e p r z e z n a s p o ło ż e n ie z ła m ie o g r a n ic z e n ia n a r z u c a n e p r z e z m e n e d ż e r a u k ła d u , m o ż e m y m ie ć k ł o p o t y z a n im o w a n ie m p o ło ż e n ia k o m p o n e n t ó w p o m i ę d z y e k r a n a m i, je że li a n im a cja b ę d z ie m u s ia ł a s p e łn ia ć o g r a n ic z e n ia u k ła d u . S p o s ó b r o z w ią z a n ia te g o p r o b l e m u je st d o s y ć p r o s t y i p o le g a n a o d łą c z e n iu u k ł a d u n a d w ó c h e k r a n a c h n a c z a s a n im a c j i k o m p o n e n t ó w G U I . R o z w i ą z a n i e m je st u r u c h o m i e n i e a n im a c j i p r z e jś c ia w o s o b n y m k o n te n e rz e , k t ó r y istn ie je w y łą c z n ie w c z a s ie d z ia ła n ia a n im a c ji. K o n te n e r t e n k o r z y s t a z z e r o w e g o lu b b e z w z g lę d n e g o m e n e d ż e r a u k ła d u , w ię c w s z y s t k ie k o m p o n e n t y w e w n ą t r z n ie g o m ogę b y ć p r z e s u w a n e i s k a l o w a n e w d o w o l n y s p o s ó b . W c z a s ie a n im a c j i k o n t e n e r t e n je st w i d o c z n y p r z e z u ż y t k o w n i k a z a m ia s t o r y g i n a l n e g o k o n t e n e r a
6 P ra w d o p o d o b n ie n a z w a łb y m ta ki efekt „ b łę d e m ”, a n ie „ a n im o w a n y m p rze jście m ”.
a p lik a c ji. P o z a k o ń c z e n i u p r z e j ś c ia k o n t e n e r a n i m a c j i je st z a s t ę p o w a n y p r z e z f a k t y c z n y
7 M e ta fo ra dekoracji film ow ej tu zaw odzi. T ło u k ry w a w szy stk o z tyłu akcji film ow ej, a sz k la n y e k ra n u k ry w a w szystk o z przodu. M o ż e m y w ięc p o ró w n a ć tę technikę d o ku rtyn y, k tó ra u k ry w a te c h n ik ó w zm ieniających dekoracje p o m ię d z y scena m i. Je d n a k k u rt y n a jest p o p ro st u za sło n ą sceny, a m y w y św ie tla m y o b ra z z w y
k o n t e n e r a p lik a c ji, k t ó r y z a w ie r a te r a z u k ł a d d r u g i e g o e k r a n u . P r z e łą c z e n ie k o n t e n e r a je st
g lą d e m sam ej sceny. T a k w ię c jest to je d n o cze śn ie k u rt y n a i dekoracja.
kt
'lilT
R o z d z ia ł 1 8 .
B ib l io t e ic a A n i m a t e d T r a n s i t i o n s
p r z e z r o c z y s t e d la u ż y t k o w n i k a 8, p o n i e w a ż z d e f in ic j i k o n t e n e r a n im a c j i w y g lą d a n a p o
19
c z ą t k u a n im a c j i d o k ła d n i e tale s a m o j a k k o n t e n e r a p lik a c ji n a p ie r w s z y m e k ra n ie , a n a k o ń c u a n im a c j i — d o k ła d n i e j a k k o n t e n e r a p lik a c j i n a d r u g i m e k ra n ie .
Przyspieszanie Sw ing — wydajność O p r ó c z w s k a z ó w e k d o t y c z ą c y c h w y d a jn o ś c i, p r z e d s t a w ia n y c h w całej k s ią ż c e , j e d n ą z m e t o d z a p e w n ia j ą c y c h b ib lio t e c e A n i m a t e d T r a n s i t i o n s o d p o w ie d n i ą w y d a j n o ś ć je st z a s t o s o w a n i e o b r a z ó w p o ś r e d n i c h p r z e d s t a w io n y c h w r o z d z ia le 5., „ W y d a j n o ś ć ” .
bogatego interfejsu użytkownika
W skazów ka N ie m a p o tr z e b y p o n o w n ie ry s o w a ć k o m p o n e n t u w c z a s ie a n im a c ji, je ż e l i w y g lą d a o n id e n ty c z n ie w k a ż d e j ra m c e . W t a k im p r z y p a d k u m o ż e m y r y s o w a ć o b r a z k o m p o n e n t u . W k o ń c u le k k ie k o m p o n e n t y S w in g s ą i t a k w w ię k s z o ś c i o b r a z a m i. Je ż e li b ę d z ie m y k o r z y s t a ć z o b ra z ó w , ic h k o p io w a n ie z a m ia s t p o w tó r n e g o r y s o w a n ia s k o m p lik o w a n y c h k o m p o n e n t ó w p o z w o li u z y s k a ć z n a c z n y p r z y r o s t w y d a jn o ś c i i b a r d z ie j p ły n n e p r z e jś c ia .
N i e k t ó r e e fe kty , t a k ie j a k s k a lo w a n ie , b ę d ą u n ie m o ż liw ia ć t o p o d e jśc ie , p o n ie w a ż n i e b ę d z ie m o ż l iw e z a p e w n ie n ie f u n k c j i d a n e g o e fe k tu . P r z e d s t a w il iś m y w c z e ś n ie j n ie k t ó r e p r o b l e m y z w ią z a n e ze s k a lo w a n ie m o b r a z ó w k o m p o n e n t ó w o r a z i c h r e n d e r o w a n ie m . J e d n a k w ie le e fe k tó w , t a la c h j a k Move, m o ż e z s u k c e s e m k o r z y s t a ć z o b r a z ó w p o ś r e d n ic h .
T
J L w o r z e n i e d o b r z e w g lą d a j ą c y c h i ła t w y c h w u ż y c i u a p lik a c j i w y m a g a s p o r o p r a c y .
W p o p r z e d n i m r o z d z ia l e p r z e d s t a w il i ś m y w ie d z ę t e c h n ic z n ą , k t ó r a b ę d z ie p o t r z e b n a d o
Podsumowanie
z b u d o w a n i a t a k ic h a p lik a c ji, a le p r o g r a m o w a n i e to n i e w s z y s t k o . W n a r o d z i n a c h b o g a t e g o in t e r f e js u u ż y t k o w n i k a n ie z w y k le w a ż n ą r o lę p e ł n i p r o j e k t o w a n ie w y g lą d u .
B ib l i o t e k a A n i m a t e d T r a n s i t i o n s p o z w a la z r e a liz o w a ć ś w ie t n ie w y g lą d a j ą c e i p r o s t e e fe k t y p r z y b a r d z o m a ł y m n a k ła d z ie p r a c y . N a w e t z r e a liz o w a n ie w ł a s n y c h efektów wymaga n i e w ie l k ie g o w y s i łk u , w z a le ż n o ś c i o d te g o , c o b ę d z i e m y p r ó b o w a ć o s ią g n ą ć . W a r t o z a p o z n a ć się z b ib lio t e k ą A n i m a t e d T r a n s i t i o n s d o s t ę p n ą n a w it r y n ie W W W
k s ią ż k i, p o b a w i ć się
d e m o n s t r a c j a m i i u r u c h o m i ć te p r z e jś c ia . R u s z m y się!
K s ią ż k a ta n ie p r e t e n d u je j e d n a k d o r o li p o d r ę c z n ik a p r o j e k t o w a n ia in t e rf e js u u ż y t k o w n ik a . M o ż e m y j e d n a k p o k a z a ć , w j a k i s p o s ó b z b u d o w a l i ś m y p r o g r a m A e r it h , k t ó r y j u ż p o k a z y w a l i ś m y n a k i l k u - r y s u n k a c h w p o p r z e d n i c h r o z d z ia ła c h . M a m y n a d z ie ję , ż e d o s t a r c z y m y C z y t e l n i k o w i w s k a z ó w e k , k t ó r e p o m o g ą m u w y k o n a ć p r z e jś c ie z p r o j e k t u n a s z k ic o w a n e g o n a p a p ie r z e d o d z ia ła j ą c e g o p r o g r a m u Java.
8 „P rze zro czy ste d la u ż y tk o w n ik a ” o z n a c z a tu ta j „ n ie w id o c z n e d la u ż y tk o w n ik a ” i n ie je s t to w n ic z y m zw iązan e z p r z e z r o c z y s t o ś c ią g r a fik i c z y S w in g . O c z y w iś c ie , m o ż n a b y u ż y ć i n n y c h s łó w , c o p o z w o liło b y w y r a z ić s e n s w b a r d z i e j je d n o z n a c z n y s p o s ó b .
Aerith
P r z e c ią ż a n ie ję z y k a n ie je s t re a liz o w a n e w s y s te m a ty c z n y s p o s ó b . G d y b y ś m y m o g li o z n a c z a ć s ło w a m o d y f ik a t o r e m f i n a l , u n ik n ę lib y ś m y w ie lu p o m y łe k . N ie s te ty , z p o w o d u z a c h o w a n ia z g o d n o ś c i w s te c z n ie m o ż e m y z m ie n ić a n i u s u n ą ć z n a c z e n ia b e z r u jn o w a n ia is tn ie ją c y c h a p lik a c ji, ta k ic h ja k k s ią ż k i c z y p r z e m ó w ie
A p lik a c j a A e r i t h p o w s t a ła w f ir m ie S u n M i c r o s y s t e m s j a k o p r o g r a m d e m o n s t r a c y j n y n a
n ia . B y ć m o ż e c z a s n a w p ro w a d z e n ie ję z y k a d e fin io w a n e g o w b a r d z ie j p e łn y i s p ó jn y s p o s ó b , k t ó r y m o ż e m y
J a v a O n e 2 0 0 6 , n a j w ię k s z ą n a ś w ie c ie k o n f e r e n c j ę d o t y c z ą c a j ę z y k a Java, k t ó r a c o r o k u o d
n a z w a ć „ p o ls k im 2 . 0 ” . P r ó b a w y k o n a n ia t a k ie j z m ia n y b y ła w y k o n a n a k ilk a s e t l a t t e m u w A m e r y c e , a le
b y w a się w S a n F r a n c is c o . P o m y s ł e m n a t e n p r o g r a m b y ł o p o k a z a n ie h y b r y d y ( m ashupl)
z m ia n y te , taicie j a k u p r o s z c z e n ie w y m o w y k ilk u s łó w , n a p r z y k ła d w y m ia n a „ c o lo u r ” h a p r o s ts z y „ c o ło r ” , są te ra z u w a ż a n e za n ie w ie lk ie o p ty m a liz a c je i u ła tw ie n ia , d a ją c e w w y n ik u c o n a jw y ż ej w e rs ję „ a n g ie lsk i 1 .0 .1 ” . P o t r z e b u je m y ja k n a js z y b c ie j b a r d z ie j ra d y k a ln y c h i p r z y d a tn y c h z m ia n .
1 C h e t c h c i a ł n a z w a ć A e r it h „ s m a s h u p ”, o d s łó w „ S w in g m a s h u p ”.
R o z d z ia ł 1 9 .
P r o j e k t p r z e p ł y w u s t e r o w a n i a n a p a p ie r z e
N a r o d z i n y b o g a t e g o i n t e r f e j s u u ż y t k o w n ik a
u s ł u g s ie c i W W W w b o g a t y m k lie n c ie o r a z p r z e d s t a w ie n ie w y n i k ó w w t a k i s p o s ó b , a b y d o t r z e ć d o m o ż l i w ie n a jw ię k s z e j lic z b y p r o g r a m is t ó w . Z e s p ó ł c h c ia ł r ó w n ie ż , a b y a p lik a c ja b a r d z o d o b r z e w y g lą d a ła , b y p o k a z a ć , j a k fa j n y m o ż e b y ć S w in g . N a d a p lik a c j ą A e r i t h p r a c o w a ło o d d w ó c h d o t r z e c h o s ó b w c ią g u d w ó c h t y g o d n i, a p o n a d 8 0 % p r a c y w y k o n a n o w c ią g u p ie r w s z e g o t y g o d n ia 2. P o d s t a w o w y z e s p ó ł s k ła d a ł s ię z n a s t ę p u j ą c y c h o s ó b : R i c h a r d B a ir , J o s h u a M a r i n a c c i o r a z ja, R o m a i n G u y . B a r d z o n a m p o m o g l i 3
® P o b r a ć k o d A e r i t h p r z y u ż y c i u S u b v e r s i o n (http://'subversion, tigris.org): svn ch eck o u t h t t p s : / / a e r it h . d e v . j a v a . n e t / s v n / a e r it h / t r u n k a e r it h (n a z w a u ż y t k o w n ik a : g u e st). ® O t w o r z y ć w N e t B e a n s k a t a lo g aerith/ j a k o p r o je k t. ® P o p r a w i ć u s z k o d z o n e o d w o ła n i e ( p o t r z e b n e b ę d z ie w s k a z a n ie in s t a la c j i J a v a S E 6 w e w ł a ś c iw o ś c ia c h p r o je k t u ) .
c z ło n k o w ie z e s p o łó w S w i n g i J a v a 2 D , w t y m C h e t H a a s e , C h r i s C a m p b e ll o r a z S c o t t V io le t . • K l i k n ą ć p r z y c i s k Run. T a k i k r ó t k i c y k l p r o d u k c y j n y b y ł m o ż l i w y d z ię k i p r a c o m w y k o n a n y m w c z e ś n ie j p r z e z z e s p ó ł o r a z z a p r e z e n t o w a n y m w tej k s ią ż c e . W i ę k s z o ś ć e f e k t ó w w iz u a ln y c h , ta la c h j a k o d b ic ia
U w aga
i c ie n ie o r a z b ib lio t e k i w s p o m a g a ją c e , ta k ie j a k T i m i n g F r a m e w o r k , b y ła j u ż d o stę p n a . P o p r z e
N a z w a u ż y tk o w n ik a ?
c z y t a n iu tej k s ią ż ld C z y t e ln ik b ę d z ie n a tej sa m e j p o z y c ji, c o m y p r z e d r o z p o c z ę c ie m p r a c y
W c z a sie u r u c h a m ia n ia A e r ith w y m a g a p o d a n ia n a z w y u ż y tk o w n ik a F lic k r (http://www.flickr.com).
n a d p r o g r a m e m A e r i t h 4 5.
Z p o w o d u o g r a n ic z e ń c z a so w y c h 6 A e r ith d z ia ła ty lk o n a k o n c ie F lic k r , k tó r e z a w ie ra c o n a jm n ie j p ię ć z b io r ó w z d ję ć lu b a lb u m ó w . Je ż e li C z y te ln ik n ie p o s ia d a k o n t a n a w it iy n ie F lic k r lu b je ż e li
P o u d a n e j p r e z e n t a c ji n a k o n f e r e n c j i J a v a O n e 2 0 0 6 z a d e c y d o w a n o w f ir m ie S u n M i c r o s y s
p o s ia d a n e k o n t o n ie s p e łn ia w y m a g a ń , m o ż n a u ż y ć k o n t a romai nguy.
t e m s o u d o s t ę p n i e n iu k o d u ź r ó d ł o w e g o n a lic e n c j i B S D , k t ó r y je st d o s t ę p n y p o d a d r e s e m https://aerith. dev.java.net. W a r t o z w r ó c ić u w a g ę , że A e r i t h n ie jest z a k o ń c z o n ą a p lik a cją . P r o g r a m te n z o s ta ł w y t w o r z o n y w b a r d z o k r ó t k i m c z a s ie j a k o c z y s t e d e m o t e c h n o lo g ii. Z te g o p o w o d u a p lik a c ja m a s p o re n ie d o s k o n a ło ś c i. J e d n a k je st to ś w ie tn a d e m o n s t r a c ja w ie lu e fe k tó w b o g a t e g o in te rfe jsu u ż y t
Organizacja kodu W s z y s t k i e k l a s y z a w ie ra ją c e a n im a c je i e fe k ty w iz u a l n e z n a jd u ją się w n a s t ę p u j ą c y c h d w ó c h p a ld e ta c h :
k o w n ik a , ja k ie z o s t a ły p r z e d s t a w io n e w tej k s ią ż c e , j a k r ó w n i e ż w ie lu in n y c h d o s k o n a ł y c h t e c h n o lo g ii J a v a i S w in g , w ię c je st w a r t b liż s z e g o p o z n a n ia .
® c o m .su n . j a v a o n e . a e r i t h . g 2 d , w k t ó r y m z n a j d u j ą się ld a s y p o m o c n i c z e o b s łu g u j ą c e g r a fik ę , n a p r z y k ł a d n a r z ę d z ia d o r z u c a n i a c ie n i.
Uruchamianie programu Aerith
® com. s u n . j a v a o n e . a e r i t h . u i , k t ó r y z a w ie r a c a ł y k o d G U I .
A b y u r u c h o m i ć A e r it h , n a le ż y w y k o n a ć n a s t ę p u j ą c e o p e ra c je : ® P o b r a ć i z a in s t a lo w a ć Ja v a S E 6 lu b n o w s z y (http://java.sun.com łu b http://ja.va.com).
Projekt przepływu sterowania na papierze
® P o b r a ć i z a in s t a lo w a ć b ib lio t e k ę J O G L ( http://jogl.dev.java.net) w k a t a lo g u
P r o j e k t o w a n i e a p lik a c j i n a p a p ie r z e je st p i e r w s z ą c z y n n o ś c i ą , j a k ą n a l e ż y z r o b i ć p r z e d
r o z s z e r z e ń J a v a S E 6 ( C:\Program Files\Java\jrel.6.0\lib\ext w W i n d o w s ,
r o z p o c z ę c ie m k o d o w a n ia . C h o ć b r z m i to n a t u r a l n ie d la w ię k s z o ś c i; p r o c e s p r o j e k t o w a n ia
/Library/Java/Extensions w M a c O S X ) .
n a p a p ie r z e p e ł n i i n n ą r o lę w t w o r z e n i u b o g a t y c h in t e r f e j s ó w u ż y t k o w n i k a n i ż t y p o w y c h G U I a p lik a c ji.
® P o b r a ć i z a in s t a lo w a ć p r o g r a m N e t B e a n s 5.5 lu b n o w s z y (http://wvsw.netbeans.org).
R o z p o c z ę c ie o d p r o j e k t u n a p a p ie r z e n ie o z n a c z a , że m u s i m y r y s o w a ć d i a g r a m y U M L p r z e d 2 T e n p ie rw s z y t y d z ie ń m ia ł b a r d z o k r ó t k ie n o c e . 3 O r a z p iz z a o d n a s z e g o k ie r o w n ik a , J e f f a D i n k i n s a . 4 W
rz e c z y w is to ś c i C z y te ln ik m o ż e k o r z y s ta ć z le p sz e g o A P I , p o n ie w a ż w ie le e le m e n tó w A e r ith b y ło n a
w c z e ś n ie js z y m e ta p ie r o z w o ju n iż o b e c n ie .
n a p i s a n i e m k o d u . O z n a c z a t o t y lk o , że n a le ż y n a s z k i c o w a ć o g ó l n e f u n k c j e i p r z e p ł y w st e r o w a n i a w a p lik a c j i, a b y u z y s k a ć le p s z y o s ą d , c o u ż y t k o w n i k b ę d z ie m i a ł z a m i a r r o b ić . P r o j e k t o w a n ie n a p a p ie r z e p o m a g a z id e n t y f ik o w a ć m ie js c a , w k t ó r y c h n a l e ż y d o d a ć e fe k t y w iz u a l n e o r a z w ja ld s p o s ó b n a le ż y to z r o b ić .
5 M a m y n a d z ie ję , ż e C z y t e ln ik w c z a s ie t w o r z e n ia s w o je j a p l i k a c ji b ę d z ie s p a ł le p ie j n iż m y w c z a s ie p i s a n ia A e r it h .
6 O r a z b r a k u s n u , k o f e in y i p izzy .
R o z d z ia ł 1 9 .
N a r o d z i n y b o g a t e g o i n t e r f e j s u u ż y t k o w n ik a
N a r y s u n k a c h 19.1 o r a z 1 9 .2 p r z e d s t a w io n y je st n a r y s o w a n y n a p a p ie r z e p r z e p ły w s t e r o w a n ia w A e r it h .
t
p
\ńjt> ’
•' i »
I.IÍ..U' î
t f/m m uSSA JŁ«-
. - ,-n n n
R y s u n e k 19.3. P rz e n ik a n ie p o m ię d z y e k ra n a m i P o o p r a c o w a n iu p r z e p ły w u s t e r o w a n ia w a p lik a c ji n a p a p ie r z e m o ż n a p r z e jś ć d o n a s t ę p n e g o k r o k u — w iz ji. ¡, V ^ I ' 1"- ' >L ~ ' U " ■
R y s u n e k 1 9 .1 . D e fin i o w a n ie f u n k c ji A e r it h
Uw aga W ty m k r o k u o d ło ż y m y p a p ie r i ółów elc i sk o rz y st a m y z ap lik a cji edycji grafiki. A d o b e P h o t o s h o p jest p r a w d o p o d o b n ie je d n y m z najczęściej u ży w a n y c h , ale istnieją ró w n ie ż in n e m o żliw o ści, n ie k tó re bezpłatne, a,n ie k tóre nie. P o n iże j p rz e d sta w io n a jest k ró t k a lista aplikacji, któ re w a rto w y p ró b o w a ć , jeżeli n ie m a m y lice ncji A d o b e P h o to sh o p . ® T h e G I M P d la L in u k sa , bezpłatny, http://www.gimp.org ° Se a sh o re d la M a c O S X , bezpła tny, http://seashore.sourceforge.net • C o re l P a in t S h o p P r o dla W in d o w s , ko m e rc y jn y , http://www.paintshoppro.com o P a in t . N E T d la W in d o w s , be zpła tny, http-J/www.getpaint. net » P h o to s h o p E le m e n ts d la W in d o w s i M a c O S X , ko m e rc y jn y , http://www.adobe.com o P ix e l Im a g e E d ito r d la W in d o w s , L in u x i M a c O S X , ko m e rcyjny, http://www.kanzehberger.com/ ® Inlcscap e dla W in d o w s , L in u x i M a c O S X , be zpłatny, http://www.inkscape.org F a k t y c z n y p r z e p ły w , s t e r o w a n ia , z d e f in i o w a n y n a r y s u n k u 19.2, je st in t e re s u ją c y , p o n i e w a ż u z m y s ła w ia , że ż a d n e d w a „ e k r a n y ” n ie są p o k a z y w a n e w t y m s a m y m czasie. W s k a z u j e ró w n ie ż ,
D o k u m e n t wizji s k ła d a się z s z a b l o n u j e d n e g o lu b d w ó c h e k r a n ó w a p lik a c ji, k t ó r e b ę d ą
że u ż y t k o w n i k m u s i p r z e jś ć p r z e z „ L o b b y ” lu b in a cz e j g ł ó w n y e k ra n , z a n im b ę d z ie m ó g ł g d z ie
s t a n o w ił y w z ó r d la d a ls z e g o p r o j e k t o w a n ia w iz u a l n e g o . W i z j a n ie je st s z a b lo n e m , k t ó r y
k o l w ie k p rz e jś ć . T a k ie p o d e jś c ie p o w o d u j e , że A e r i t h je st a p lik a c j ą p o s ia d a j ą c ą j e d n o o k n o ,
b ę d z ie m y f a k t y c z n ie im p le m e n t o w a ć . Jej z a d a n i e m je st p r z e d s t a w ie n ie z e s p o ło w i p o m y s ł u
k t ó r e d z ia ła p o d o b n i e d o k r e a t o r a .
n a k o ń c o w y p r o d u k t . Z te g o p o w o d u p r z y t w o r z e n iu n ie trz e b a z w ra c a ć z b y t d u że j u w a g i n a u ż y t e c z n o ś ć , ła t w o ś ć im p le m e n t a c j i i i n n e w a ż n e e le m e n t y rz e c z y w is t e j im p le m e n t a c ji.
G d y u ż y t k o w n i k p r z e c h o d z i n a i n n y e k ra n , n o w a z a w a r t o ś ć z a stę p u je sta rą , c o p o z w a la n a m s k o r z y s t a ć z a n i m o w a n y c h p r z e j ś ć p o m i ę d z y e k r a n a m i. G d y p r z e c h o d z i m y n a p r z y k ł a d
W p r o j e k c ie A e r t h s p o r z ą d z i łe m d w a r y s u n k i w iz ji. P i e r w s z y ( r y s u n e k 1 9 .4 ) b y ł p r z e w i
z Lobby d o li s t y a lb u m ó w , o d t w a r z a n e je st a n im o w a n e p r z e n ik a n ie , j a k je s t to p o k a z a n e n a
d z ia n y j a k o e k r a n p o w it a ln y . P o m i m o te g o , że w k o ń c o w e j w e r s j i a p lik a c j i n ie m a e k r a n u
r y s u n k u 19.3.
p o w it a ln e g o , r y s u n e k te n z a w ie r a k lu c z o w e e le m e n t y k o ń c o w e g o p r o j e k t u — c ie m n y sc h e m a t k o lo r ó w , o d b ic ia , ła d n e f o t o g r a f ie i g r a d ie n t y .
R o z d z ia ł 1 9 .
N a r o d z i n y b o g a t e g o in t e r f e j s u u ż y t k o w n ik a
M a k ie t y
R y s u n e k 1 9 .4 . W iz ja p r o g r a m u A e r it h — e k r a n p o w ita ln y
D r u g i r y s u n e k w iz j i ( r y s u n e k 1 9.5) m a r e p r e z e n t o w a ć e k r a n w y b o r u a lb u m u . K o ń c o w y p r o jekt, n ie m a n ic w s p ó ln e g o z t y m r y s u n k ie m , ale r ó w n ie ż w t y m p r z y p a d k u są -w y k o r z y s ta n e k l u c z o w e e le m e n t y p r o je k tu . W a r t o p o r ó w n a ć t e n r y s u n e k z k o ń c o w y m w y g lą d e m a p lik a c ji, p r z e d s t a w io n y m n a r y s u n k u 19.6, i s p r ó b o w a ć z n a le ź ć p o d o b ie ń s t w a .
R y s u n e k 1 9 .6 . K o ń c o w a w e r s ja e k r a n u w y b o r u a lb u m u
Projektowanie ekranu na papierze P r z e p ły w s t e r o w a n ia o r a z w iz j a p o w i n n y d a ć n a m w y s t a r c z a ją c o d u ż o in f o r m a c j i, „aby r o z p o c z ą ć p r o j e k t o w a n ie k o l e j n y c h e k r a n ó w . T e r a z m o ż n a z a c z ą ć s ię m a r t w i ć o u ż y t e c z n o ś ć im p le m e n t a c j i i z w ią z a n e z n ią p r o b le m y . K a ż d y e k r a n n a le ż y z a p r o j e k t o w a ć n a p a p ie rz e . N i e m a p o t r z e b y je sz c z e w y b ie r a ć k o l o r ó w a n i m y ś le ć n a d k a ż d y m s z c z e g ó łe m . J a k je st t o p o k a z a n e n a r y s u n k u 19.7, p r o j e k t e k r a n u - n a p a p ie r z e p o w i n i e n d a ć n a m p r e c y z y jn e in f o r m a c j e n a te m a t w y g lą d u ta ld e g o e k ra n u . J e d n a k p o z o s t a w i a m y c z ę ść sz c z e g ó łó w . N a p r z y k ł a d p r z e d s t a w io n y p r o j e k t n ie z a w ie r a in f o r m a c j i, że p a s e k n a w i g a c y j n y n a g ó r z e e k r a n u m u s i b y ć w y p e ł n i o n y g r a d ie n t e m . G d y k a ż d y e k r a n je st j a s n o z d e f i n i o w a n y n a p a p ie rz e , m o ż n a p r z e j ś ć d o o s t a t n ie g o k r o k u p r z e d im p le m e n t a c ją . R y s u n e k 1 9 .5 . W i z ja e k r a n u w y b o r u a lb u m u
W t y m m o m e n c i e n ie p o w i n n i ś m y z a j m o w a ć się s p o s o b a m i im p le m e n t a c j i a p lik a c ji, w ię c m o ż n a e k s p e r y m e n t o w a ć ze w s z y s t k im i p r o je k t a m i, ja k ie p r z y j d ą n a m d o g ło w y . W iz j a p o z w a la w y r a z ić n a s z ą k r e a t y w n o ś ć . S z c z e g ó ła m i im p le m e n t a c j i a p lik a c ji b ę d z ie m y z a j m o w a ć
Makiety
się w k o le j n y c h k r o k a c h . N a r a z ie tr z e b a się t y lk o u p e w n ić , ż e n a s z e o b r a z y o d z w ie r c ie d la ją n a s z e p o m y s ł y i p o d o b a j ą się i n n y m lu d z io m .
W t y m o s t a t n im k r o k u m u s i m y w r ó c ić d o p r o g r a m u e d y c ji g r a f ik i. M a k i e t a o d z w ie r c ie d la
G d y w iz j a je st g o t o w a , m o ż e m y w r ó c i ć z p o w r o t e m d o p a p ie r u .
k ie e le m e n t y p r o j e k t u o r a z in f o r m a c j e w y m a g a n e d o z a im p l e m e n t o w a n ia a p lik a c ji.
w y g lą d k a ż d e g o z e k r a n ó w , j a k ie g o o c z e k u j e m y o d k o ń c o w e g o p r o je k t u . Z a w i e r a w s z y s t
553
R o z d z ia ł 1 9 .
N a r o d z i n y b o g a t e g o in t e r f e j s u u ż y t k o w n ik a
Od m a k i e t y d o k o d u
W r z e c z y w is t o ś c i i m p le m e n t a c j a n i g d y n ie b ę d z ie o d z w ie r c ie d la ła w s t u p r o c e n t a c h m a k ie ty . N i e k t ó r e e le m e n t y p r o j e k t u m o g ą b y ć z b y t t r u d n e d o z a im p le m e n t o w a n ia , j a k r ó w n ie ż z r ó ż n y c h p o w o d ó w m o g ą p o w s t a ć n ie w ie lk ie r ó ż n ic e . N a p r z y k ła d a lg o r y t m r y s o w a n ia g r a d ie n t u w A d o b e P h o t o s h o p je st i n n y n i ż w ś r o d o w i s k u Ja va i n ie b ę d z ie m y w sta n ie u t w o r z y ć w ie r n e j k o p i i te g o g r a d ie n t u z a p o m o c ą J a v a 2 D . W k o ń c o w e j im p le m e n ta c ji, p o k a z a n e j n a r y s u n k u 1 9.9, e fe k t o ś w ie t le n ia z a s ł o w e m Lobby w p a s k u n a w ig a c j i z o s t a ł u s u n ię t y , a r o z m y c i e t y t u ł u Tasks je st b a r d z ie j su b te ln e .
N a r y s u n k u 1 9 .8 p i z e d s t a w i o n a je st m a k ie t a e k r a n u L o b b y . J a k w id a ć , w y k o r z y s t a n y z o s t a ł p r o j e k t n a p a p ie r z e , j a k r ó w n i e ż e le m e n t y p r o j e k t u z w iz ji. C i e m n y te m a t k o lo r u , o d b ic ia o r a z g r a d i e n t y p o c h o d z ą z r y s u n k ó w w iz ji. J e d n a k t r z e b a z w r ó c ić u w a g ę , że w m a k ie c ie z o s t a ły d o d a n e n o w e e le m e n t y p r o j e k t u o r a z s z c z e g ó ły . N a p r z y k ła d p o r a z p ie r w s z y n a t y m r y s u n k u p o j a w ia się r o z m y t y t y t u ł Select a Task.
R y s u n e k 1 9 .9 . I m p le m e n t a c ja n ie j e s t w 1 0 0 p r o c e n t a c h z g o d n a z m a k ie tą
P o n a r y s o w a n i u m a k i e t y m o g ą w y n i k n ą ć r ó w n i e ż i n n e w ię k s z e r ó ż n ic e . Jeżeli s p o j r z y m y n a r y s u n e k 19.9, m o ż e m y z a u w a ż y ć c a ł y n o w y o b s z a r n a d o le e k ra n u . M e c h a n i z m w y b o r u a l b u m ó w z o s t a ł d o d a n y n a p ó ź n ie j s z y m e ta p ie p r o je k t u , b e z w c z e ś n ie js z e g o a k t u a liz o w a n ia m a k ie t y . P o m i m o t e g o m a k ie t a d a je w s z y s t k i e n ie z b ę d n e in f o r m a c j e d o w y t w o r z e n ia te g o e k r a n u .
makiety do koidu
-,v-y '
. :j|j
Im p le m e n t a c j a m a k i e t y w k o d z i e je st n a j t r u d n ie j s z ą i c z ę sto n a jb a rd z ie j fr u s t ru ją c ą c z ę śc ią t w o r z e n ia b o g a t e g o in t e r f e j s u u ż y t k o w n ik a . P o n i e w a ż w e w c z e s n y c h fa z a c h p r o j e k t o w a n ia p o z w a la m y sz a le ć n a sz e j w y o b r a ź n i, m o ż e to s p o w o d o w a ć , że p ro je k t b ę d z ie b a i d z o t iu d n y R y su n ek 1 9 .8 . M ak ie ta ek ranu L o bb y narysow an a za p o m o cą A d o b e P h o to sh o p
d o im p le m e n t a c j i w rz e c z y w ist e j a p lik a c ji Java. J e d n o je st p e w n e — b ę d z ie m y p o t r z e b o w a li s p o r o w ł a s n y c h k o m p o n e n t ó w / . Is tn ie je j e d n a k k il k a m e t o d p o z w a la ją c y c h n a u p r o s z c z e n ie te v n n r o c e s u .
R o z d z ia ł 1 9 .
N a r o d z i n y b o g a t e g o in t e r f e j s u u ż y t k o w n ik a
O d m a k ie t y d o k o d u
Zastosow anie warstw K a ż d y z a a w a n s o w a n y p r o g r a m e d y c ji g r a f i k i u m o ż l i w i a s t o s o w a n ie w a r s t w . W a r s t w y są u m ie s z c z a n e j e d n a n a d r u g ie j, c o p o z w a la w id z ie ć w a r s t w y z n a jd u ją c e się p o n iż e j p o p r z e z p r z e z r o c z y s t e p ik se le . D z i ę k i z a s t o s o w a n iu w a r s t w m o ż n a r o z d z ie lić p o s z c z e g ó ln e e le m e n t y p ro je k tu . Z a le t y ta k ie g o r o z w ią z a n ia są d w o ja k ie . P o p ie r w s z e , m o ż n a ła t w o w y o d r ę b n i ć e le m e n t z o b ra z u . Jeżeli n a r y s u j e m y n a p r z y k ła d p r z y c is k , m o ż n a w y e k s p o r t o w a ć g o d o z e w n ę t r z n e g o p lik u , k t ó r y b ę d z ie z a ła d o w a n y p r z e z n a s z ą a p lik a c ję Java. P o d r u g ie , w y iz o lo w a n ie e le m e n t ó w p o z w a la p r a c o w a ć je d n o c z e ś n ie n a w ie lu p ro je k ta c h . Jeżeli p o w ie lim y ele m e n t, a n a s t ę p n ie z m i e n im y je g o w y g lą d , b ę d z ie m y m o g li u k r y w a ć lu b p o k a z y w a ć p o s z c z e g ó ln e w a r stw y , a b y sp ra w d z ić , j a k te w a r ia n t y w y g l ą d u w s p ó ł g r a j ą z c a ł y m p r o je k t e m . N a r y s u n k u 1 9 .1 0 p r z e d s t a w io n y je st p r o j e k t a p lik a c ji A e r i t h z c z a r n y m tłe m . T ł o to z o s ta ło n a r y s o w a n ie n a w a r s t w ie nazwanej Alternate Background, k t ó r ą m o ż n a z o b a c z y ć n a p a le c ie w a r s tw , w p r a w y m d o l n y m n a r o ż n i k u r y s u n k u . G d y w a r s t w a z a w ie r a ją c a c z a r n e tło z o s t a n ie w y łą c z o n a , p o j a w ia się in n e tło. T o n o w e tło, p o k a z a n e n a r y s u n k u 1 9.11, je st n a r y s o w a n e z a p o m o c ą g r a d ie n t u , o d c z a r n e g o p r z e z n ie b ie s k i d o b ia łe g o , n a w a r s t w ie o n a z w ie Background.
R y s u n e k 1 9 .1 1 . Ja ś n ie js z e tło p o ja w ia s ię , g d y u k r y je m y w a rs tw ę z a lte r n a ty w n y m t łe m
P r z e d z d e c y d o w a n i e m o u ż y c i u c ie m n e g o tła m o g ł e m p r z e łą c z a ć te tła w d o w o l n y m m o m e n c ie , p o n i e w a ż z n a j d o w a ły się o n e n a o s o b n y c h w a r s t w a c h . A b y z r o z u m ie ć w a g ę w a r s t w p r z y p r o je k t o w a n iu A e r it h , p r o p o n u j e m y w r ó c ić d o r y s u n k u 1 9 .7 i s p r ó b o w a ć z g a d n ą ć , ile w a r s t w p r o g r a m u P h o t o s h o p z o s t a ło u ż y t y c h p r z y p r o j e k t o w a n iu te g o e k r a n u . P r a w i d ł o w ą o d p o w i e d z i ą je st 4 7 . U ż y ł e m 4 7 w a r s t w d o t w o r z e n ia te g o p r o s t e g o r y s u n k u i w s z y s t k ie te w a r s t w y są p o k a z a n e n a r y s u n k u 19.12. K a ż d y e le m e n t p r o j e k t u m a w ł a s n ą w a r s t w ę . N a p r z y k ł a d z a d a n ie m a c z t e r y w a r s t w y — j e d n ą n a ik o n ę , j e d n ą n a o d b ic ie ik o n y , j e d n ą n a t y t u ł z a d a n ia i je d n ą n a o p is z a d a n ia . W a r s t w y ' o fe ru ją n a j w ię k s z ą e la s t y c z n o ś ć w p r o j e k t o w a n iu i im p le m e n t a c j i in t e rfe jsu u ż y t k o w n ik a . N a p r a w d ę w a r t o ic h u ż y w a ć
Tryby m ieszania A p lik a c j e d o e d y c ji g r a f ik i o b s łu g u ją c e w a r s t w y p o z w a la ją w y b ie r a ć s p o s ó b m ie s z a n ia w a rstw . T r y b m ie s z a n ia w a r s t w d e f in iu j e s p o s ó b łą c z e n ia p i k s e l i z t y m i, k t ó r e z n a j d u j ą się p o n iż e j. N a r y s u n k u 1 9.8 z a s ł o w e m „ L o b b y ” w i d o c z n y je st o p r a c o w a n y p r z e z e m n i e e fe k t o ś w ie R y su n ek 1 9 .1 0 . C zarn e tło zn ajd u je się n a w arstw ie o nazw ie A lte rn a te B a ck g ro u n d
t le n io w y u t w o r z o n y z a p o m o c ą u s t a w ie n ia t r y b u m ie s z a n ia Overlay n a w a r s t w ie z a w ie r a jącej b ia ł y g r a d ie n t . T e n e le m e n t p r o j e k t u n ie z o s t a ł d o d a n y d o k o ń c o w e j im p le m e n t a c ji, p o n ie w a ż m o ż e b y ć z b y t t r u d n y d o z a p r o g r a m o w a n i a w t a k k r ó t k i m cz a sie .
N a r o d z in y b o g a t e g o in t e r f e j s u u ż y t k o w n ik a
t
Ti— f .
rtw.*
SI"
|v:n. “ '
-I M m i
i) op*>»|T?i3 i*(i u V ] ł o|
' ‘ _____ '
' lr'5.T**
__
r fil w*. p *™ .*
n p . . .
* : •'
i
2
l'■ ] j
iji-
1
r
jP-.
f' j 21]"’*'
□
s O 1" " 1 »■
W
■•i U
—
a = n . ¥
.
i-
Pr... n o Ji vi j Lc^łJ* -BEHEM
.v i .1 I Oj a ft.: ■t : -u i .i1
M
| jj, t
A,-
a o.\ I T ««>
■OH
^ * - "
n
"i *-}' ■>p ;;,
!,|
_,-WJ
*«!
v 11*r^-T*S7-1 O
'—
■
> | J § » E 3 -" " -
r
p P j £m*ma
ej.n*
if!
,s"[» ta ««»-•*.
-
1 1
o : | Vl(
3 1 1 3 .
_ *■
—
V
r k ? T l_
p b -
*H
U i ' “ "-” [ I M -
r ¡¿l!
„ f v r „„
*,V
4L ^
j* r*1 ; ^
"■
□ 'P I jrU w "H "
□ ■ c a -
-----
‘ v '* ,i Js 'I-
urur.____ :*3
“ ■* ‘J V H J a
-m *
.1 i U.-I
,
'„‘»'i*'__ ¡i ■'2'1’
A l e . .. ja n i e j e s t e m a r t y s t ą !
_
R o z d z ia ł 1 9 .
f r ] 3 .~ 1>.«i iWjOi i ft.1^ . -a I
.*>1 T Ć5 :1 V
..
3 f □ r»-
-
0
F.
0 -"."
*:
f
: : :
T i!3 itf
....
u
,1" 'T ¿2
P r o w a d n ic e są j e d n y m z n a s z y c h n a j le p s z y c h n a r z ę d z i. P o p ie r w s z e , p o m a g a j ą o d t w o r z y ć
( 3 0 '
u k ła d sia tki, k t ó r y m o ż e b y ć p o w ie lo n y z a p o m o c ą z a r z ą d c y u k ła d u w ję z y k u Java. D o d a t k o w o
f f w
; tfTETTp.l '.-ar 'J T T
R y s u n e k 1 9 .1 3 . W ie le p r o w a d n ic u ż y w a n y c h d o z b u d o w a n ia te g o r y s u n k u
i a.?an ».i j j'SiTji ¡7
R y s u n e k 1 9 .1 2 . 4 7 w a rs tw e k r a n u L o b b y
P o n i e w a ż p la t f o r m a J a v a S E n ie o fe ru je o d p o w i e d n i k ó w w i ę k s z o ś c i t r y b ó w m i e s z a n ia d o s t ę p n y c h w a p lik a c ja c h e d y c ji g r a f ik i7, n ie w a r t o z n i c h k o r z y s t a ć . Je że li n ie m o ż n a się j e d n a k
p o m a g a j ą w m i e r z e n i u o d le g ło ś c i m i ę d z y e le m e n t a m i. P o m i a r y te m u s z ą b y ć d o k ła d n i e z a n o t o w a n e i p o n o w n i e u ż y t e p r z y p i s a n i u k o d u in t e r f e j s u u ż y t k o w n i k a w j ę z y k u Java. U w aga G d z ie s ą p r o w a d n ic e ?
b e z n i c h o b e jść , m o ż n a w r ó c i ć d o r o z d z i a ł u 6., „ P r z e z r o c z y s t o ś ć ” i z a p o z n a ć s ię z k la s ą
W p r o g r a m a c h d o e d y c ji g r a fik i p r o w a d n ic e s ą n a jc z ę ś c ie j u k r y te ja k o f u n k c ja o n a z w ie ruler.
B le n d C o m p o site , k t ó r a u d o s t ę p n ia 3 1 c z ę sto s t o s o w a n y c h t r y b ó w , k t ó r y c h m o ż n a u ż y ć ja k o
Je ż e li a p lik a c ja n ie m a t a la c h fu n k c ji, m o ż n a s k o r z y s ta ć z z e w n ę tr z n y c h a p lik a c ji d o u tw o rz e n ia
o b ie k t ó w C o m p o si t e w o b ie k c ie G ra p h i cs2 D .
p r o w a d n ic . W s y s te m ie M a c O S X m o ż n a z a in s ta lo w a ć a p lik a c ję X S c o p e ( http://iconfactory.com/
K-*-software/xscope), k t ó r a p o z w a la s k o r z y s t a ć z p r o w a d n ic s y s t e m o w y c h o r a z i n n y c h r ó w n ie p r z y d a t n y c h n a r z ę d z i. U ż y t k o w n ic y W in d o w s m o g ą w y p r ó b o w a ć p r o g r a m S c r e e n C a lip ie r s
Stosowanie prowadnic
( http://www.seoconsultants.com ) lu b D e s k to p R u le r s ( http://www.desktopruler.com).
P r o w a d n ic e to lin ie p i o n o w e i p o z io m e , k t ó r e m o ż n a n a ło ż y ć n a n a s z r y s u n e k w c e lu p o m o c y p r z y w y r ó w n y w a n i u e le m e n t ó w i m ie r z e n iu o d le g ło ś c i. N a r y s u n k u 1 9 .1 3 p r z e d s t a w io n y je st je d e n z r y s u n k ó w p r o j e k t o w y c h a p lik a c ji A e r i t h w r a z z n a ło ż o n y m i p r o w a d n ic a m i. M o ż n a p o r ó w n a ć g o z r y s u n k i e m 19.5, n a k t ó r y m z a m ie s z c z o n y je st s a m r y s u n e k .
Ale... ja nie jestem artystą! R ó w n ie ż ja n i m n ie je ste m . T w o r z e n ie e fe k to w n ie w y g lą d a ją c y c h a p lik a c ji n ie w y m a g a d u ż y c h u m ie j ę t n o ś c i r y s o w a n ia a n i w y k s z t a łc e n ia a rt y s t y c z n e g o . N a r y s u n k u 1 9 .1 4 p o k a z a n o m o je n a jle p sz e r y s u n k i n a p a p ie r z e 8. A b y r y s o w a ć w ła s n e i k o n y n ie tr z e b a b y ć m is t r z e m r y s o w a n ia .
7 M o ż n a u s ły s z e ć p lo t k i, ż e z e s p ó ł Ja v a 2 D p r a c u je n a d im p l e m e n t a c ją n i e k t ó r y c h c z ę s t o s p o t y k a n y c h
W w ię k s z o ś c i p r z y p a d k ó w m o ż n a s o b ie p o r a d z ić , m a ją c n ie w ie lk ie u m ie j ę t n o ś c i p la s ty c z n e .
t r y b ó w m ie s z a n ia , a b y w J D K 7 f u n k c ja ta b y ła z n a c z n ie ła tw ie js z a w u ż y c iu . Je d n a k n a ra z ie z a le c a m y s to s o w a n ie p r z e d s ta w io n e j tu p o r a d y .
8 N a b r a łe m t r o c h ę u m ie ję tn o ś c i n a w s z y s tk ic h le k c ja c h w s z k o le .
559
R o z d z ia ł 1 9 .
N a r o d z in y b o g a t e g o i n t e r f e j s u u ż y t k o w n ik a
W ybó r ł a d n y c h k o lo r ó w
C h o ć s z u k a n ie in s p ir a c j i w r ó ż n y c h ź r ó d ła c h je st d o b r y m p o m y s łe m , n a le ż y p a m ię t a ć o k o n se k w e n c ji. Z a w s z e n a le ż y a d a p t o w a ć in s p ira c je d o w ł a s n y c h a p lik a c ji i p r o je k t ó w , a b y m ia ły o n e s p ó j n y i s o l i d n y w y g lą d . Z b y t w ie le a p lik a c ji k o r z y s t a z j e d n e g o lu b w ie lu e le m e n t ó w p r o j e k t u z i n n y c h a p lik a c ji, n ie a d a p t u ją c ic h d o r e s z t y in t e rfe jsu . W y n i k i m o g ą b y ć n ie n a jle p sz e . P o d o b n i e n a le ż y z w r a c a ć s z c z e g ó ln ą u w a g ę n a s z c z e g ó ły 10. N a l e ż y u p e w n i ć się, że k a ż d y p ik s e l z n a jd u je się w e w ł a ś c iw y m m ie jsc u , i b y ć g o t o w y m d o w a lk i ze s w o i m z e s p o łe m p r o g r a m is t ó w , je ż e li n ie je s t 11.
Wybór ładnych kolorów K o l o r y są w a ż n ą c z ę ś c ią p r o j e k t u g r a f ic z n e g o , a le i c h w y b ó r je st c z ę s t o t r u d n y . O ile n ie je s t e ś m y p r a w d z i w y m i a r t y s t a m i, n i e u m i e m y n a t u r a l n i e w y b ie r a ć k o l o r ó w . N a sz c z ę ś c ie is t n ie je k i l k a n a r z ę d z i p o m a g a j ą c y c h n a m w t y m t r u d n y m z a d a n iu . N a r z ę d z i a te n ie t y lk o o f e r u j ą g o t o w e d o u ż y c i a p a le t y k o l o r ó w , a le r ó w n i e ż m o g ą s p r a w d z ić , k t ó r e k o l o r y w s p ó ł g r a j ą z i n n y m i. P r z y k ł a d y t a k ic h n a r z ę d z i są p o k a z a n e n a r y s u n k a c h 1 9 .1 5 o r a z 1 9.16. Umitled
000
*
-.§á'
i i i '. ' t
>
;, .
' ° ( r ;m5ńo~TA
, a ' 1 3
W eb P a g e H e a d e r
fci,— '- S T iT ? 0 U , « . 0 J HÜ1
R y s u n e k 1 9 .1 4 . B r a lc w s p a n ia ły c h u m ie ję tn o ś c i p la s ty c z n y c h n ie o z n a c z a ,
Si CC
CCi-ss ;
üi< thenylc changer belowto change the ługgcjted ulicm«* »tyl«!
.
Co'í.-Vj'vd fiW JM07..K4
M
r,C6ÍM
1 j «1 íS«íO£
r
i i
-- ,r.
asióos
t
że n ie m o ż n a p r o je k t o w a ć ś w ie tn y c h in t e r f e js ó w
P r o j e k t o w a n i e d o b r z e w y g lą d a j ą c y c h a p lik a c j i m o ż e b y ć w r z e c z y w i s t o ś c i d o s y ć p r o s t e . T r z e b a się t y lk o s t o s o w a ć d o n a s t ę p u j ą c y c h z a sa d : 1 . K r a d n i j p o m y s ły , s k ą d się t y lk o da. 2 . Z w r a c a j u w a g ę n a s z c z e g ó ły . 3. B ą d ź k o n se k w e n tn y.
■¡■.'frrjr-':
-
o-
«can
W M W W W lM i
R y s u n e lc 1 9 .1 5 . C o lo r S c h e m e r S tu d io d la M a c O S X s u g e r u je z b ió r k o lo r ó w w s p ó łg r a ją c y c h z p o d s ta w o w y m w y b r a n y m k o lo r e m
In s p i r a c j ę m o ż n a c z e r p a ć z e s p r a w d z o n y c h w z o r c ó w . P r o d u k t y f i r m y A p p le , w ię k s z o ś ć a p lik a c j i M a c O S X 9 c z y te ż n a j n o w s z e p r o d u k t y f i r m y M i c r o s o f t , t a k ie j a k W i n d o w s V i s t a i O f f ic e 2 0 0 7 są ś w ie t n y m i ź r ó d ł a m i in s p ir a c ji.
1Je ż e li m a s z p e w n e sk rz y w ie n ie o b s e s y jn o -k o m p u ls y jn e , p r a w d o p o d o b n ie b ę d z iesz w ty m d o b ry . In ż y n ie ro w ie p o w in n i s z c z e g ó ln ie d o b r z e n a d a w a ć s ię d o te g o z a d a n ia . Je ż e li o g lą d a łe ś o d c in e k Hitlerek od zup se r ia lu K ro n ik i Seinfelda , to p r a w d o p o d o b n ie b ę d z ie s z w ied z ia ł, ja k
9 Je ż e li n a d a l n ie m a s z k o m p u te r a z M a c O S X , k u p g o ja k n a jp rę d z e j. O p ła c i się t o T o b i e i T w o im ld ie n to m .
n a z y w a ła m n ie r e s z ta z e s p o łu w c z a s ie p r o g r a m o w a n ia A e r ith .
R o z d z ia ł 1 9 .
N a r o d z i n y b o g a t e g o i n t e r f e j s u u ż y t k o w n ik a
K s ią ż k i n a t e m a t p r o je k t o w a n ia
i
o o o
C o lo r S c h e m e A n a ly z e r
, Background Colon
Książki na temat projektowania
, Compatible Text Colors: :
? l'F3W P r z e d s t a w io n e w s k a z ó w k i n ie z a s t ą p ią d o b re j k s i ą ż k i n a t e m a t p r o j e k t o w a n ia in t e r f e js u
jH| #54A4DE I #BBD9CE
IQ
#F6E896
u ż y t k o w n ik a lu b p r o j e k t o w a n ia g r a fic z n e g o . P o n iż e j w y m ie n i o n e s ą lesiążlei, k t ó r e m o ż e m y
I
I #EBF4FA
j
#FAF1C3
p o le c ić .
I
I #BEDF5D
j [jj] «7E4D3
1 I #D6EB9A
p ] #F1EFE2
I
® C o o p e r A la n , R e i m a n n R o b e rt , About Face 2.0: The Essentials o f Interaction Design, W ile y 2003.
e ltc t ? background color to r ee which o f vour cav olors would bp o c r suited to use a r a tpxt rolo -
® T id w e l l J e n n ife r , D esigning Interfaces: Patterns f o r Effective Interaction Design, O ’R e i l l y 2 0 0 5 .
0
R e v e r s e te x t/ b a c k g r o u n d c o lo r s
' ■■■»•■•■■I................. *.. *
o M u l l e t K e v i n , S a n o D a r r e ll, D esigning Visual Interfaces: Comm unication O riented Techniques, P r e n t ic e H a l l 1 99 4 .
R y s u n e k 1 9 .1 6 . C o lo r S c h e m e r S tu d io m o ż e r ó w n ie ż o k r e ś lić , c z y k o lo r y t e k s t u są z g o d n e z d a n y m t le n i
® J e ff J o h n s o n , GUI Bloopers: D o n ’ts and D o ’s f o r Software Developers and Web
D o s t ę p n e są r ó ż n e n a r z ę d z ia w s p o m a g a j ą c e w y b ó r k o lo r ó w , ale k i lk a z n ic h m o ż e m y p o le c ić .
Designers, M o r g a n K a u f m a n n 2 0 0 0 . ® S n y d e r C a r o l y n , Paper Prototyping: The Fast a nd Easy Way to Design and Refine
o C o l o r S c h e m e r S t u d io d la W i n d o w s i M a c O S X , k o m e r c y j n y ,
User Interfaces, M o r g a n K a u f m a n n 2 0 0 3 .
http:// www. colorschemer. com ® W i t r y n a C o l o r S c h e m e r O n lin e , b e z p ła tn a , http://www.colorschemer.com/online.html
® R a s k i n Jef, The H um ane Interface: New Directions fo r Designing Interactive Systems, A d d is o n - W e s le y 2000.
® W i t r y n a A d o b e k u le r , b e z p ła t n a , http://kuler.adobe.com ® W i l l i a m s R o b i n , The N on-D esigner’s Design Book, P e a c h p it P r e s s 2 0 0 3 . • W i t r y n a C O L O U R l o v e r s , b e z p ła t n a , http://www.colourlovers.com e S p o l s k y Joel, User Interface Design fo r Program m ers, A p r e s s 2 0 0 1 . W i t r y n y A d o b e k u l e r o r a z C O L O U R l o v e r s o f e r u j ą s e t k i w y s o k ie j j a k o ś c i p a le t k o lo r ó w , Je ż e li m a m y o g r a n i c z o n y b u d ż e t i n ie w ie le c z a s u n a p r z e c z y t a n ie t y c h k s ią ż e k , n a p o c z ą t e k
z k t ó r y c h m o ż n a s k o r z y s t a ć w e w ł a s n y c h p r o je k t a c h .
w a r t o r o z w a ż y ć p r z e c z y t a n ie k s i ą ż k i D esigning Visual Interfaces, n a p is a n e j p r z e z K e v i n a
\JL/
M u l l e t a i D a r r e l la S a n o . T a m a ła k s i ą ż k a m o ż e w y d a w a ć s ię p r z e s t a r z a ła 12, p o n ie w a ż z o
W sk azów k a
s t a ła w y d a n a w r o k u 1 9 9 4 , ale m a t e r ia ł t e n je st n a d a ł a k t u a ln y i m o ż n a się z n ie j n a u c z y ć
Z b y t w ie le k o lo r ó w N ie z a le ż n ie o d te g o , w j a k i s p o s ó b b ę d ą w y b ie r a n e k o lo r y d la a p lik a c ji, t r z e b a z a p a m ię ta ć w a ż n ą
w s z y s t k ie g o , c o t r z e b a w ie d z ie ć n a t e m a t p r o j e k t o w a n ia in t e r f e j s u u ż y t k o w n ik a .
r e g u łę — n a le ż y k o r z y s ta ć z m o ż liw ie n ie w ie lu k o lo r ó w . T r z y lu b c z t e r y t o d o b r e r o z w ią z a n ie , p ię ć lu b s z e ś ć — d o p u s z c z a ln e .
\ I /
W skazów ka
-( I J —
W y b ó r k o lo r u d la g r a d i e n t u
fi
W w ię k sz o ś c i p rz y p a d k ó w w g r a d ie n ta c h n a le ż y k o r z y s ta ć z k o lo r ó w z b liż o n y c h
d o s ie b ie . P o d o b
n e k o lo r y d a ją s u b t e ln ie js z e g r a d ie n ty , k t ó r e s ą b a r d z ie j e s te ty c z n e n iż g r a d ie n ty w y k o r z y s tu ją c e k o lo r y z n a c z n ie o d s ie b ie o d d a lo n e .
12 W ię k s z o ś ć r y s u n k ó w w te j k s ią ż c e je s t w y d r u k o w a n a w s k a li s z a r o ś c i, p o n ie w a ż p r z y k ła d o w e in t e r f e js y u ż y tk o w n ik a f a k ty c z n ie d z ia ła ły w s k a li s z a r o ś c i, a n ie d la te g o , że d r u k w k o lo r z e j e s t d ro ż sz y .
R o z d z ia ł 1 9 .
N a r o d z i n y b o g a t e g o in t e r f e j s u u ż y t k o w n ik a
Podsumowanie T w o r z e n i e b o g a t y c h in t e r f e j s ó w u ż y t k o w n i k a w y m a g a z a r ó w n o d o b r e g o p r o j e k t u w s t ę p n e g o , j a k i n a r z ę d z i d o z a im p le m e n t o w a n ia te g o p r o je k t u . P r o j e k t o w a n ie d o b r e g o in t e rf e js u w i z u a l n e g o n i g d y n ie b y ł o p r o s t e , a le in f o r m a c j e z a w a r t e w t y m r o z d z ia le p o w i n n y p o m ó c
Zakończenie
u n i k n ą ć n i e k t ó r y c h p r o b l e m ó w , r o z w i a ć c z ę ś ć m i t ó w i p o z w o l i ć o s i ą g n ą ć le p s z e w y n i k i . N a r z ę d z i a p r z e d s t a w io n e w p o z o s t a ł y c h r o z d z i a ła c h k s i ą ż k i p o w i n n y u m o ż l i w i ć re a liz a c ję t e g o p r o je k t u .
Z V t a m y n a d z ie ję , że n a s z a p o d r ó ż p o t e c h n ik a c h b u d o w a n i a b o g a t y c h in t e r f e j s ó w u ż y t k o w n i k a b y ła c ie k a w a . C o w a ż n ie js z e , m a m y n a d z ie ję , że p o z w o l i ł a o n a C z y t e l n i k o w i n a u c z y ć się w y s t a r c z a j ą c o d u ż o , a b y m ó g ł z a s t o s o w a ć n ie k t ó r e z t y c h t e c h n i k w a p lik a c ja c h . J e s te ś m y n ie t y lk o t w ó r c a m i a p lik a c ji. J e s t e ś m y r ó w n ie ż u ż y t k o w n i k a m i i o c z e k u j e m y d n ia , w k t ó r y m w ię c e j p r o g r a m i s t ó w b ę d z ie k o r z y s t a ć z t y c h t e c h n ik w c e lu d o s t a r c z e n ia le p sz y c h , b a r d z ie j e f e k t y w n y c h i z a b a w n y c h a p lik a c ji. T a m , g d z ie b y ł o t o m o ż l iw e , p r ó b o w a l i ś m y o d w o ł a ć s ię d o i n n y c h p u b l i k a c j i i z a s o b ó w . J e d n a k u z n a liś m y , że p r z y d a t n a b y ła b y b a r d z ie j r o z b u d o w a n a ic h lista, p o z w a la ją c a n a d a ls z ą e k s p lo r a c j ę p r o g r a m o w a n i a b o g a t y c h in t e r f e j s ó w u ż y t k o w n ik a .
Projekty C h o c i a ż w tej k s ią ż c e s k u p i a l i ś m y s ię n a in t e r f e j s a c h A P I b ę d ą c y c h c z ę ś c ią p o d s t a w o w e j b ib lio t e k i Id a s ś r o d o w i s k a J a v a lu b n a r z ę d z ia c h n a p i s a n y c h n a p o d s t a w ie t y c h p o d s t a w o w y c h b ib lio t e k , is t n ie je r ó w n i e ż w ie le i n n y c h p o d e j ś ć i b ib lio t e k , z k t ó r y m i w a r t o się z a p o z n a ć . W y m i e n i l i ś m y tu ta j k i l k a z n ic h , a le je st t o t y l k o m a ła p r ó b k a . W y s t a r c z y p o s z u k a ć , a z n a j d z ie się z n a c z n ie w ię c e j k o le j n y c h . Biblioteka Tim ing Fram ew ork. N a w i t i y n i e W W W
k s ią ż k i, http://filthyrichclients.org,
u d o s t ę p n io n a je st je d n a z w e r s ji T i m i n g F r a m e w o r k , k t ó r a p a s u je d o p r z y k ła d ó w u ż y t y c h w k sią ż c e . N a w it r y n ie p r o j e k t u T i m i n g F r a m e w o r k , http://timingframework.dev.java.net, m o ż e b y ć d o s t ę p n a i n n a w e rsja , p o n ie w a ż w r a z z je g o r o z w o j e m d o d a w a n e są n o w e fu n k c je . Je że li k t o ś b ę d z ie c h c ia ł k o r z y s t a ć z T i m i n g F r a m e w o r k i n ie b ę d z ie p o t r z e b o w a ł w e r s ji zw ią z a n e j z z a w a r to ś c ią k s ią ż k i, p o w i n i e n s k o r z y s t a ć z n a jn o w sz e j w e rsji, d o stę p n e j n a w i t i y n i e java. net.
Z a k o ń c z e n ie
W it r y n y a u to r ó w
Biblioteka A nim ated Transitions. P o d o b n i e j a k b ib lio t e k a T i m i n g F r a m e w o r k , s t a t y c z
Z a m i a s t w s k a z y w a ć k o n k r e t n e b ł o g i i a r t y k u ły , t a k j a k r o b i l i ś m y to w k s ią ż c e , p r z e d s t a
n a w e r sja b ib lio t e k i A n i m a t e d T r a n s it i o n s je st u m ie s z c z o n a n a w it r y n ie W W W k s ią ż k i,
w i m y tu taj łd łk a o g ó l n y c h m ie jsc , w k t ó r y c h m o ż n a s z u k a ć w a r t o ś c i o w y c h tre śc i.
w ię c w p o m y s ła c h z tej k s i ą ż k i m o ż n a w y k o r z y s t a ć z tej w e r s ji b ib lio te k i. W m ię d z y c z a s ie p r o j e k t b ę d z ie z n a j d o w a ł s ię n a w ła s n e j w it r y n ie , p r a w d o p o d o b n i e n a java.net, w ię c w r a z ie p o t r z e b y m o ż e b y ć r ó w n ie ż r o z w ij a n y . N a w i t r y n ie W W W k s i ą ż k i z n a jd u je się łą c z e d o w i t r y n y p r o j e k t u , w ię c t a m n a le ż y s z u k a ć d a ls z y c h i n f o r m a c j i o tej b ib lio te c e . SwingLabs. P r o j e k t S w in g L a b s , d o s t ę p n y n a w it r y n ie http://swinglabs.dev.java.net, je st ż ł o b k ie m d la p r z y s z ły c h f u n k c j i d o łą c z a n y c h d o p o d s t a w o w e j b ib lio t e k i S w in g . W p r o je k c ie t y m m o ż n a z n a le ź ć w ie le p e r e łe k d la p r o g r a m i s t ó w S w in g , o d n o w y c h i e k s c y t u j ą c y c h k o m p o n e n t ó w S w i n g d o b ib li o t e k u ż y t k o w y c h u ła t w ia j ą c y c h p r o g r a m o w a n ie .
http://javadesktop.org. Jest to ś w ie t n y z a s ó b d la w s z y s t k ic h z a in t e r e s o w a n y c h b ib lio t e k ą S w in g . W i t r y n a z a w ie r a list ę a d r e s ó w U R L b lo g ó w , a r t y k u łó w , f o r ó w , p r o j e k t ó w i a p li k a c ji in t e r e s u j ą c y c h d la p r o g r a m i s t y Java. http://java.sun.com . W i ę k s z o ś ć p r o g r a m i s t ó w J a v a z n a tę w it iy n ę , p r z y n a j m n ie j z p o b ie r a n ia J D K . J e d n a k z n a jd u je się n a n ie j z n a c z n ie w ię c e j, w t y m fo ra , a r t y k u ły , p o r a d y t e c h n ic z n e i o g ó ln e in f o r m a c j e d la w s z y s t l d c h p r o g r a m i s t ó w Java. Je st to d o b r y p u n k t d o c e lo w y d la o s ó b c h c ą c y c h p o z n a ć p o d s t a w o w e k o n c e p c j e s t o s o w a n e w Java.
N ie k t ó r e z e fe k t ó w i n a r z ę d z i z a s t o s o w a n y c h w tej k s ią ż c e p o c h o d z ą z tej w i t r y n y i b ę d ą
http://java.net. Jest to w i t r y n a s p o łe c z n o ś c i Java, p o d o b n a d o javadesktop.org, ale p r z e
p r a w d o p o d o b n i e z in t e g r o w a n e z S w in g L a b s. W a r t o z a p o z n a ć się z p r o j e k t e m S w in g L a b s,
z n a c z o n a d la całej s p o łe c z n o ś c i Java, tw o r z ą c e j a p lik a c je p u lp it u , j a k r ó w n i e ż in n e .
a b y s p r a w d z ić , c z y m o ż e o n p o m ó c w p r o g r a m o w a n i u p r z y u ż y c i u S w in g .
http://filthyrichclients.org. W i t i y n a W W W p o ś w i ę c o n a k s ią ż c e z a w ie r a w s z y s t k ie p r o
JOGL. Ł ą c z n i k J a v a d o OpenGL, d o s t ę p n y n a w it iy n ie http://jogl.dev.java.net, je st b ib lio t e
g r a m y d e m o n s t r a c y jn e , j a k r ó w n ie ż b ib lio t e ld T i m i n g F r a m e w o r k o r a z A n i m a t e d T r a n
k ą u m o ż liw ia j ą c ą a p lik a c j o m J a v a k o r z y s t a n i e z 3 D A P I O penG L z a k c e le r a c ją s p r z ę t o w ą
s it io n s w y k o r z y s t y w a n e w p r z e d s t a w ia n y c h tu ta j p r z y k ła d a c h . M o ż n a t a m r ó w n i e ż
g r a f ik i, k t ó r ą b ib lio t e k a ta z a p e w n ia n a w ię k s z o ś c i p la t f o r m . N i e m i e l i ś m y m o ż l i w o ś c i
z n a le ź ć in f o r m a c j e n a te m a t i n n y c h m a t e r ia łó w z w ią z a n y c h z k s ią ż k ą , w t y m łą c z a d o
p o ś w ię c ić z b y t w ie le c z a s u n a J O G L , ale a p lik a c je b a r d z o b o g a t e g r a fic z n ie m o g ą k o r z y s t a ć
w ię k s z e j il o ś c i m a t e r ia łó w d o t y c z ą c y c h t w o r z e n ia b o g a t y c h in t e r f e j s ó w g r a f ic z n y c h .
z f u n k c j i tej b ib lio t e ld . W a r t o s p r a w d z ić b ie ż ą c y s t a n te g o p r o j e k t u o r a z p r o g r a m y d e m o n s t r a c y j n e d o s t ę p n e n a w it r y n ie , a b y z o b a c z y ć , c o m o ż n a z r o b ić p r z y u ż y c i u J O G L . Aerith. P r o j e k t A e r i t h , z n a j d u j ą c y się n a w it r y n ie http://aerith.dev.java.net, je st in t e r e s u j ą c y m p r z y k ł a d e m p o k a z u j ą c y m p r z e d s t a w io n e t u e f e k t y u m i e s z c z o n e w a p lik a c ji. A e r i t h je st r ó w n i e ż ś w i e t n y m p r z y k ł a d e m i n t e g r a c j i s t a n d a r d o w y c h u s ł u g s i e c i o w y c h z b o g a t ą a p lik a c j ą S w in g . I tak dalej. Is t n ie j e je s z c z e w ie le i n n y c h p r o j e k t ó w i z a s o b ó w o p r ó c z t y c h k i l k u p r z e d s t a w i o n y c h w k s ią ż c e . Z a m i a s t w y p r ó b o w y w a ć tu ta j je w s z y s t k ie , n a w i t r y n i e W W W k s i ą ż k i u m i e ś c i l i ś m y list ę p r o j e k t ó w i w it r y n , in t e r e s u j ą c y c h z p u n k t u w id z e n ia b o g a te g o in t e rfe jsu u ż y t k o w n i k a (http://filthyrichclients.org). W a r t o z a jrz e ć n a w it r y n ę w c e lu p r z e j r z e n ia n a j n o w s z e j listy.
Witryny autorów
'
J e ż e li k t o ś b ę d z ie z a i n t e r e s o w a n y p r z e c z y t a n i e m w ię k s z e j i l o ś c i t e k s t u a u t o r ó w , o c z y w i ś c ie p r z y z a ło ż e n i u , ż e i c h p a l c d z a g o j ą s ię p o ś l ę c z e n i u n a d r ę k o p i s e m , m o ż n a z a jr z e ć d o i c h b lo g ó w . http://curious-creature.org. B l o g R o m a i n a z i n f o r m a c j a m i o w s z y s t k i m — o d d e m o n s t ra c ji e f e k t ó w w S w i n g d o p i ę k n y c h f o t o g r a fii. http://weblogs.java.net/blog/chet. B l o g C h e t a n a t e m a t ś r o d o w i s k a Java, z i n f o r m a c j a m i t e c h n i c z n y m i i a r t y k u ł a m i n a t e m a t D e s k t o p Ja v a , g r a f ik i, w y d a j n o ś c i itp . C z a s a m i m o ż n a t a m z n a le ź ć d o w c i p y t e c h n ic z n e .
Witryny Java O p r ó c z p r o j e k t ó w i b ib li o t e k is t n ie je r ó w n i e ż w ie le i n n y c h ś w ie t n y c h m ie jsc , w k t ó r y c h
http://chetchat.blogspot.com. T e n b l o g n ie m a n i c w s p ó l n e g o z j ę z y k ie m Java. Jest to h u m o r y s t y c z n y b l o g C h e t a . J e ż e li b ę d z i e m y m i e l i d o ś ć j ę z y k a J a v a i b ę d z i e m y s z u k a ć c z e g o ś z a b a w n e g o , w a r t o t a m za jrze ć.
m o ż n a z n a le ź ć w ię c e j in f o r m a c j i n a t e m a t m e c h a n i z m ó w o p is a n y c h w k s ią ż c e . T a m , g d z ie
http://www.progx.org. T e n b l o g c z a s a m i m a c o ś w s p ó l n e g o z j ę z y k ie m Java. C z a s a m i.
b y ł o to w ła ś c iw e , p r z e d s t a w ia liś m y c z ę ś ć z n ic h , a le d o s t ę p n y c h je st z n a c z n ie w ię c e j m a t e
N i e z b y t c z ę sto . W r z e c z y w is t o ś c i d o s y ć r z a d k o . Je st t o f r a n c u s k i b l o g R o m a i n a z d u ż ą
r ia ł ó w n i ż t y c h k i l k a p r z y k ła d ó w , k t ó r e m o g l i ś m y z a m ie ś c ić . W s z c z e g ó ln o ś c i ś r o d o w i s k o
lic z b ą zd ję ć. Je ż e li k t o ś z n a fr & n c u sld , m o ż e z n a le ź ć t a m c ie k a w e m a t e r ia ły .
Ja v a w f ir m ie S u n i p o z a n ią b y ło w o s t a t n ic h la ta c h b a r d z o a k t y w n e w p i s a n i u b lo g ó w i a rt y k u łó w , j a k r ó w n i e ż p r o w a d z e n i u p r o j e k t ó w , z k t ó r y c h k i l k a p r z y w o ła liś m y .