Nieoficjalny tutorial pisania apletów Pointui
Autor: Krzysztof Śmiałek Dzień: 2009-07-10 Godzina: 19:23:29 [Dodaj komentarz (5)]
Czym właściwie jest aplet? Z ogólnego punktu widzenia, aplet jest niewielką aplikacją uruchamianą wewnątrz innego programu. Zazwyczaj aplety są kompilowane do postaci bibliotek dynamicznych lub uruchamiane w interpreterze specjalnie stworzonego języka.
Aplety Pointui to niewielkie programiki widoczne na głównym ekranie i zazwyczaj realizujące jedno zadanie, w szerszym lub węższym zakresie. Użytkownik może je przełączać przez przesuwanie palcem po ekranie w lewo lub prawo. W darmowej wersji Pointui, na której się tu skupię, użytkownik może mieć równocześnie załadowane sześć niezależnych apletów. Domyślnie z programem dostarczane jest pięć: Messaging, Slideshow, Tasks, Today i World. Oczywiście użytkownik może mieć w urządzeniu dowolną ilość apletów, lecz tylko sześć z nich może być równocześnie dostępne. W wersji płatnej liczba ta została zwiększona do dziewięciu, poza tym dostępne są różne zaawansowane funkcje, np. obsługujące GPS, oraz dodatkowe ekrany: do tworzenia struktury QuickLaunch, wprowadzania tekstu oraz wizytówki. Wszystkie funkcje wersji darmowej są dostępne również w płatnej.
Pointui ma wbudowany interpreter stworzonego na potrzeby apletów języka Pointui C Script. Bazuje on na C#, lecz został wyposażony w ograniczoną ilość typów danych oraz w szereg specyficznych dla środowiska funkcji. Aplety nie wymagają kompilacji, ich kod jest interpretowany z plików tekstowych z rozszerzeniem .cs. Dzięki temu można je tworzyć w Visual Studio (dla którego społeczność stworzyła SDK), jak również bezpośrednio na PDA, przy użyciu programów takich jak Notepad lub MobilePad. W pierwszym wypadku dostępna jest piaskownica (ang. sandbox), która umożliwi uruchamianie kodu w Pointui oraz uproszczone debugowanie. Wersja na PDA nie umożliwia wyszukiwania błędów (chociaż często byłaby to przydatna funkcja), lecz mamy ją zawsze pod ręką i możemy kodować w każdej wolnej chwili (warto wyposażyć się w wygodną klawiaturę ekranową, ja używam HTC Compact Qwerty).
Na początek trochę teorii
Aplety są zapisane w ścieżce instalacyjnej Pointui w podfolderze AppletRibbon, czyli domyślnie \Program Files\Home2\AppletRibbon. Każdy aplet ma swój folder o nazwie, która staje się później jego nazwą. W tym folderze znajduje się plik o tej samej nazwie oraz z rozszerzeniem .cs, a w pliku klasa dziedzicząca z klasy Applet, o nazwie postaci [nazwa]Applet. Na przykład aplet HelloWorld jest tworzony przez klasę HelloWorldApplet, znajdującą się w pliku HelloWorld z folderu HelloWorld.
Kompletny opis tworzenia apletów można znaleźć w dokumentacji na stronie programu – http://www.pointui.com. Warto się z nim zapoznać, by poznać możliwości języka, lecz mimo wszystko najlepiej uczyć się z autopsji. W razie potrzeby będę objaśniał pewne kwestie, lecz dla osoby znającej chociaż w podstawowym stopniu C++, C# lub choćby Delphi albo PHP pisanie apletów na pewno nie będzie stanowiło problemu.
Aby uniknąć późniejszych frustracji, należy koniecznie wspomnieć o ograniczeniach języka. Przede wszystkim, nie możemy korzystać z tablic. Jedyna podobna do nich struktura DataTable nie może być zapisywana przez programistę, a jedynie przez wbudowane funkcje. Jej obsługę dodano, aby uprościć obsługę danych ściąganych z systemu, jak np. listy wiadomości, zadań, plików itp. – i trzeba przyznać, że faktycznie nieźle sprawdzają się w tym celu.
Typy danych Integer (int) oraz bool są kompatybilne – to znaczy typ int możemy zapisywać i odczytywać jako bool i odwrotnie. Wartość true jest reprezentowana przez liczby różne od zera, a false właśnie przez zero. Jeśli zapiszemy do zmiennej bool liczbę różną od zera, to przy odczycie zawsze otrzymamy tą liczbę, a niekoniecznie 1.
Dostępna jest konwersja int na String, lecz nie zawsze działa ona tak, jak powinna. Proste przypisanie liczby lub wartości zmiennej liczbowej do tekstowej nie sprawia problemów, lecz jeśli funkcja operuje na "żywej zmiennej" całkowitej przekazywanej w parametrze, to w przypadku podania zmiennej tekstowej nie otrzymamy poprawnych danych. Podobnie, w przypadku łączenia ciągów znaków operatorem + nie otrzymamy poprawnych rezultatów, np. w przypadku przypisania String s = "x" + 1 + "x" nie otrzymamy ciągu x1x – w miejscu jedynki znajdziemy monstrualną liczbę. Sposobem na rozwiązanie problemu jest wcześniejsze przypisanie jedynki do zmiennej tekstowej, wtedy zostanie ona zinterpretowana jako tekst i łączenie ciągów zadziała.
Język udostępnia tylko jeden rodzaj pętli – while, lecz wobec braku tablic nie jest to wielkie ograniczenie, gdyż zazwyczaj nie zachodzi potrzeba użycia innych rodzajów. Typ DataTable jest przystosowany do przetwarzania w pętlach while.
UWAGA: Pointui w wersji 2.1.0 ma ulepszoną konwersję typów danych, więc problemy ze zmiennymi tekstowymi nie będą występować wcale lub w ograniczonym stopniu. Mimo wszystko, należy stosować opisaną przeze mnie metodę, by zachować kompatybilność ze starszymi wersjami. Ta wersja obsługuje też pętle typu for. Dodano również prosty debuger, w skutek czego większość bezproblemowych apletów przestała działać, a ich twórcy pracują obecnie nad stosownymi poprawkami. Zaletą tego rozwiązania jest gwarancja poprawnego działania zarówno w bieżącej wersji, jak w starszych.
Silnik skryptowy został napisany pod kątem używania w nim obrazów w formacie JIF. Mają one podobne właściwości jak PNG (chodzi głównie o zapis kanału alfa), lecz wymagają mniejszej mocy obliczeniowej. W apletach ze skomplikowaną grafiką ma to duże znaczenie. Inne formaty (m. in. JPG) też są obsługiwane, lecz na dłuższą metę mogą powodować problemy (i faktycznie powodują), należy więc korzystać z formatu JIF gdy to tylko możliwe.
Jeszcze jedna ważna rzecz: wielkość liter również odgrywa rolę, lecz za wyjątkiem nazw plików.
Nasz pierwszy aplet
Jak to zwykle bywa, zaczniemy od prostego apletu HelloWorld. Będzie on wyświetlał na ekranie napis "Hello World", a później rozbudujemy go również o tło i otwieranie naszej ulubionej strony internetowej pda.pl. Zaczynamy od utworzenia folderu (przypominam o nazewnictwie) oraz pustego pliku tekstowego w środku. Gdy już to zrobimy, wprowadzamy przykładowy kod:
//Pointui C Script /* Hello World Applet example by Krzychu Written for pda.pl */ class HelloWorldApplet : Applet { Label hello; void Load() { hello.SetAlign("Center", "Center"); hello.SetFont("Font.Title"); hello.SetText("Hello World!"); Controls.Add(hello); hello.SetBounds(0, 0, GetWidth(), GetHeight()); } void AppGotFocus() { RedrawScreen(); } void AppLostFocus() { RedrawScreen(); } void Activated() { RedrawScreen(); } void Deactivated() { RedrawScreen(); } void RedrawScreen() { Controls.Clear(); Controls.Add(hello); } }Teraz przeanalizujemy go linijka po linijce
//Pointui C Script /* Hello World Applet example by Krzychu Written for pda.pl */Pierwszy komentarz umożliwia jednoznaczne określenie, czy dany plik .cs jest faktycznie apletem Pointui, czy może zwykłym plikiem Visual Studio, który trafił tu przypadkowo. Reszta jest opcjonalna, zazwyczaj umieszcza się tutaj opis apletu i dane autora. Niektórzy dodają changelog i informacje o licencji.
class HelloWorldApplet : Applet { [...] }Informujemy interpreter, że tutaj zaczyna się nowa klasa. Będzie ona miała nazwę HelloWorldApplet i będzie dziedziczyła z klasy Applet. Pamiętaj o nazewnictwie! Inaczej silnik nie załaduje apletu.
Przejdźmy teraz do kodu wewnątrz klasy.
Label hello;Jesteśmy w miejscu, gdzie deklaruje się zmienne. Łatwo tutaj popełnić błąd, więc bądź ostrożny. Jeśli już przy deklarowaniu zmiennej zdefiniujesz ją (przypiszesz wartość), interpreter zgłosi błąd i aplet nie zadziała. Łączenie definicji z deklaracjami nie jest możliwe dla zmiennych globalnych dla klasy, jedynie dla lokalnych zmiennych funkcji.
Również elementy interfejsu graficznego są zmiennymi, na ekran ładuje się je przy pomocy obiektu Applet.Controls.
Jest to dobry moment, by wspomnieć o zdarzeniach, które w Pointui C Script zostały uproszczone. Są po prostu funkcjami o stosownej nazwie. Jeśli potrzebne Ci zdarzenie wywoływane np. przy ładowaniu apletu, tworzysz funkcję Load(), a silnik sam ją wywoła w odpowiednim momencie. Lista wszystkich dostępnych zdarzeń znajduje się w dokumentacji.
void Load() { hello.SetAlign("Center", "Center"); hello.SetFont("Font.Title"); hello.SetText("Hello World!"); Controls.Add(hello); hello.SetBounds(0, 0, GetWidth(), GetHeight()); }Skorzystaliśmy właśnie ze zdarzenia Load() klasy Applet. Jest ono wywoływane w momencie dodania apletu lub jego ładowania przy uruchamianiu Pointui. Pojawia się w każdym aplecie. Przeanalizujmy kod tego zdarzenia.
hello.SetAlign("Center", "Center");Odwołujemy się do funkcji SetAlign klasy Label. Przyjmuje ona dwa parametry. Pierwszy oznacza wyrównanie tekstu w poziomie i może przyjmować trzy wartości tekstowe:
- Left
- Center
- Right
Drugi parametr decyduje o rozmieszczeniu w pionie i również przyjmuje trzy wartości:
- Top
- Center
- Bottom
Jeśli powierzchnia etykiety będzie większa, niż to wymagane, tekst zostanie wyrównany według tych ustawień. Jeśli będzie zbyt mała, zostanie ucięty. W naszym wypadku chcemy rozciągnąć element na cały ekran tak, by tekst wyśrodkował się na powierzchni apletu.
hello.SetFont("Font.Title");Funkcja SetFont ustala wielkość czcionki etykiety na podstawie pierwszego parametru, który musi być typu String. Dostępne są cztery rozmiary:
- Font.Small
- Font.Medium
- Font.Large
- Font.Title
My skorzystamy z ostatniej opcji.
hello.SetText("Hello World!");Kolejna użyta przez nas funkcja to SetText. Powoduje ona zmianę napisu na etykiecie. Jeśli podany w parametrze tekst będzie zbyt długi, by zmieścić go w obszarze etykiety, zostanie on przycięty.
Controls.Add(hello);Controls jest obiektem klasy Screen, z której dziedziczy Applet. Controls samo w sobie jest typu ControlCollection, które znów dziedziczy z Collection. Na pierwszy rzut oka jest to skomplikowane, a im dłużej się nad tym zastanawiamy, tym bardziej utwierdzamy się w przekonaniu, że to faktycznie jest skomplikowane. W każdym razie Collection oraz klasy pochodne służą do gromadzenia różnego typu danych. Controls magazynuje elementy graficzne, które mają być aktualnie wyświetlane na powierzchni rysowania. Mamy tutaj trzy główne funkcje:
- Add(Object object)
- Remove(int index)
- Clear()
Pierwsza dodaje nowy widoczny element, druga "zdejmuje" z ekranu już istniejący, a trzecia czyści ekran. Żaden element nie jest wyświetlany, zanim zostanie dodany do kolekcji Controls. Od razu mówię, że dodawanie obiektu, który nie zawsze ma być widoczny, w instrukcji warunkowej nie jest dobrym pomysłem. Lepiej dodawać go zawsze, a później ukrywać funkcją SetVisible, której dokładny opis znajduje się w dokumentacji klasy Control (nie mylić z Controls).
hello.SetBounds(0, 0, GetWidth(), GetHeight());Jest to właściwie linijka kluczowa dla działania naszego programu. Nawet jeśli dodamy kontrolkę do Controls, nie będzie ona wyświetlana do momentu ustawienia jej na pozycji przy pomocy funkcji SetBounds. Funkcję tą posiada każdy element interfejsu – dziedziczy ją z klasy Control. Dwa pierwsze parametry to współrzędne X i Y położenia lewego górnego narożnika (wszystkie kontrolki są prostokątami), natomiast dwie kolejne to odpowiednio szerokość i wysokość elementu.
Funkcje GetWidth i GetHeight są dziedziczone z klasy Screen przez Applet. Zwracają szerokość i wysokość powierzchni apletu. Uwaga! O ile funkcje Device.GetScreenWidth oraz Applet.GetWidth będą zwracać te same wartości (choć właściwie też nie zawsze), to funkcja Device.GetScreenHeight zwróci fizyczną wysokość ekranu w pikselach (240, 320, 400, 480, 640, 800), natomiast Applet.GetHeight wysokość powierzchni przeznaczonej na wyświetlanie apletu (160, 320). Z drugiej strony nic nie stoi na przeszkodzie, by rysować poza tą powierzchnią, lecz efekt może być mało estetyczny.
Aby uprościć trochę pracę, informuję od razu: orientacja ekranu nie zmienia wielkości powierzchni apletu, jej proporcji ani sposobu rozmieszczania elementów. Silnik sam o wszystko zadba. Cwana bestia, nie? Dodam też, że dla ekranów QVGA powierzchnia ma wymiary 240x160 px (uwaga, nietypowa proporcja). Radzę zostawić pięć pikseli marginesu z każdej strony, a już na pewno po bokach, efekt będzie dużo lepszy,
Z ostatniej chwili: Pointui w wersji 2.1.0 ma domyślnie powiększoną powierzchnię rysowania, ze względu na wyrównanie czterech dolnych przycisków do dołu (wcześniej do środka). Użytkownik może jednak przywrócić im wcześniejszą pozycję, a wtedy nasz aplet może wyglądać nieestetycznie, jeśli nie przewidzimy takiej sytuacji przy projektowaniu. Wysokość powierzchni apletu zmienia też włączenie pełnego ekranu w ustawieniach Pointui.
Właściwie nasz aplet nie musi mieć więcej funkcji, by sprawnie działać, lecz mimo to użyję kilku, które na pewno przydadzą się w przyszłości – korzysta z nich każdy użyteczny aplet.
void AppGotFocus() { RedrawScreen(); } void AppLostFocus() { RedrawScreen(); } void Activated() { RedrawScreen(); } void Deactivated() { RedrawScreen(); }Są to kolejne cztery zdarzenia. Jak widać, wszystkie wywołują funkcję RedrawScreen, którą omówię później. AppGotFocus następuje w momencie, gdy użytkownik wraca z innej aplikacji na pulpit, natomiast AppLostFocus, gdy inny program jest uruchamiany. Activated jest wywoływane w momencie zmiany apletu na nasz lub powrotu na pulpit z aktywnym naszym apletem, podczas gdy wcześniej widoczne było menu lub inny ekran Pointui. Deactivated występuje, gdy użytkownik zmieni aplet na inny lub wywoła jakiś ekran, czy to wbudowany, czy to pochodzący od apletu. Ekrany i zarządzanie nimi omówię później.
void RedrawScreen() { Controls.Clear(); Controls.Add(hello); }Oto drugi kluczowy fragment kodu, legendarny RedrawScreen. Czego nie ma w tej funkcji, nie istnieje. Poważnie, bo to ona jest używana do montowania elementów na ekranie po odświeżeniu. Generalnie za każdym razem, gdy trzeba coś zmienić na ekranie, kod kończy się wywołaniem tej funkcji. Z definicji ma ona wyczyścić kontrolki (Controls.Clear()), a następnie załadować je ponownie. Jeśli aplet bardzo się rozrośnie, należy koniecznie udostępnić mniejsze funkcje wykonujące drobne zadania. Chodzi o to, że jeśli potrzebna nam tylko drobna aktualizacja, to nie ma sensu przerysowywać całego ekranu, ponieważ w tym czasie aplet nie reaguje na działania użytkownika. Aby go nie denerwować, używamy drobnych funkcji, a cały RedrawScreen wywołujemy tylko po włączeniu apletu (Activated()) i uaktywnieniu Pointui (AppGotFocus()).
Teraz załaduj aplet do PDA i sprawdź, czy działa. Jak na początek to całkiem sympatyczny, prawda? Tylko że... bezużyteczny!
Obrazki
Obsługa grafiki jest oczywiście banalna, bo co tu może być skomplikowanego? Powiedziałbym wręcz, że nawet prosta etykieta wymaga więcej pracy. Na początek weźmy jakiś obrazek, na przykład nasze sztandarowe logo pda.pl. Wyskalujemy je na dwa rozmiary: 240x160 i 480x320 (dla QVGA i VGA). Pliki zapiszemy jako logo_240.png oraz logo_480.png, a następnie skonwertujemy do formatu JIF (narzędzie i plik wsadowy w dokumentacji). Teraz czytaj uważnie, bo przed tobą uniwersalna instrukcja pisania apletów, które zadziałają poprawnie w każdej rozdzielczości! Dodamy kilka linijek do naszego kodu, który teraz wygląda tak:
//Pointui C Script /* Hello World Applet example by Krzychu Written for pda.pl */ class HelloWorldApplet : Applet { Label hello; Image bg; void Load() { String width = Device.AutoScaleValue(GetWidth()); bg.Surface.LoadFromFile("logo_"+width+".jif"); Controls.Add(bg); bg.SetBounds(0, 0); hello.SetAlign("Center", "Center"); hello.SetFont("Font.Title"); hello.SetText("Hello World!"); Controls.Add(hello); int pad = GetHeight() – Device.AutoScaleValue(40); hello.SetBounds(0, pad, GetWidth(), Device.AutoScaleValue(40)); } void AppGotFocus() { RedrawScreen(); } void AppLostFocus() { RedrawScreen(); } void Activated() { RedrawScreen(); } void Deactivated() { RedrawScreen(); } void RedrawScreen() { Controls.Clear(); Controls.Add(bg); Controls.Add(hello); } }Po pierwsze wyjaśniam, cóż to jest Device oraz AutoScaleValue. Device to globalny obiekt udostępniający funkcje, które umożliwiają manipulację urządzeniem i ściąganie danych o sprzęcie, tj. wymiary ekranu, orientację wraz z możliwością obracania, głośność systemową i dzwonka z regulacją itd. Natomiast AutoScaleValue to funkcja służąca do tworzenia interfejsów na różne wielkości wyświetlaczy. Przyjmuje ona wartość int i ją też zwraca, ale odpowiednio zmanipulowaną: dla urządzeń QVGA i WQVGA nie zmieni jej, ale dla VGA i WVGA pomnoży ją przez dwa. W ten sposób wszystkie różnice wielkościowe zostaną wyrównane.
W tym przykładzie chciałem przesunąć etykietę niżej, by nie zasłaniała loga, więc ustawiłem pewien górny margines, a wysokość zmniejszyłem o ten właśnie margines – dzięki temu etykieta nie wykroczy poza powierzchnię apletu. Dzięki Device.AutoScaleValue nie muszę tworzyć skomplikowanych instrukcji warunkowych, silnik zmienia wartości za mnie.
bg.Surface.LoadFromFile("logo_"+width+".jif");Ta linijka powoduje wczytanie pliku na powierzchnię kontrolki Image. Proste jak budowa cepa, prawda? Jeśli chciałbyś dodatkowo przeskalować grafikę, możesz dodać dwa opcjonalne parametry typu int, które będą oznaczać nowe wymiary. Umieściłem kod ładujący obraz nad kodem etykiety, by jej nie zasłonić. Oczywiście można by skorzystać z funkcji zmieniających kolejność elementów – tylko po co, skoro tak jest prościej?
Może zauważyłeś, że funkcja SetBounds otrzymała teraz tylko dwa parametry. Otóż elementy typu Image podczas dodawania do Controls skalują się same, więc nie trzeba ustawiać wymiarów (choć można).
Wyjaśnię jeszcze jedną rzecz: dlaczego utworzyłem zmienną pad, zamiast zwyczajnie podać bardziej skomplikowany parametr funkcji. Otóż wbrew temu, co twierdzi dokumentacja, silnik ma problemy z kolejnością wykonywania działań (wstawiaj nawiasy gdzie tylko możesz, a unikniesz później problemów – niełatwo znaleźć taki błąd) oraz interpretacją skomplikowanych parametrów funkcji. Dlatego lepiej najpierw przeliczyć wszystko podczas przypisania do zmiennej, a dopiero później podać gotowy wynik.
Kwestia zmiennej width była już wyjaśniana, ale mimo to powtórzę: łączenie wartości String z int operatorem + nie działa, za to z konwersją int na String już tak.
Załaduj obrazki oraz nowy kod do pamięci urządzenia, a następnie usuń i dodaj ponownie swój aplet, by go przeładować (tak jest najszybciej). Jak się podoba logo naszej ulubionej strony na pulpicie? A może zrobimy link do naszej ulubionej strony?
Systemowy wiersz poleceń
Cel jest prosty: chcemy, by po tapnięciu loga otworzyła się w domyślnej przeglądarce strona http://pda.pl. Najlepiej do realizacji tej funkcji nada się kolejny element interfejsu, jakim jest przycisk. Przyciski umożliwiają ładowanie grafik, lecz nie skorzystamy z tej funkcji. Zainteresowanych odsyłam ponownie do dokumentacji języka.
Oto kod zmodyfikowanego apletu z obrazkiem:
//Pointui C Script /* Hello World Applet example by Krzychu Written for pda.pl */ class HelloWorldApplet : Applet { Label hello; Image bg; Button link; void Load() { String width = Device.AutoScaleValue(GetWidth()); bg.Surface.LoadFromFile("logo_"+width+".jif"); Controls.Add(bg); bg.SetBounds(0, 0, GetWidth(), GetHeight()); hello.SetAlign("Center", "Center"); hello.SetFont("Font.Title"); hello.SetText("Hello World!"); Controls.Add(hello); int pad = GetHeight() – Device.AutoScaleValue(40); hello.SetBounds(0, pad, GetWidth(), Device.AutoScaleValue(40)); link.OnClick = link_click; Controls.Add(link); Link.SetBounds(0, 0, GetWidth(), GetHeight()); } void link_click(Control sender, int x, int y) { Process.Start("http://www.pda.pl"); } void AppGotFocus() { RedrawScreen(); } void AppLostFocus() { RedrawScreen(); } void Activated() { RedrawScreen(); } void Deactivated() { RedrawScreen(); } void RedrawScreen() { Controls.Clear(); Controls.Add(bg); Controls.Add(hello); Controls.Add(link); } }Wątpliwości może budzić ta linijka:
link.OnClick = link_click;Użyliśmy tutaj innego sposobu deklarowania zdarzeń, który nie wymaga ingerencji w strukturę klasy. Moglibyśmy co prawda utworzyć klasę pochodną od Button, której zdarzenie OnClick otwierałoby odpowiednią stronę, lecz takie rozwiązanie tylko niepotrzebnie obciążałoby silnik i zajmowało cenną pamięć. Zamiast tego konfigurujemy zdarzenie OnClick obiektu link typu Button, by zostało zastąpione funkcją link_click z klasy apletu.
Jak widać, funkcja link_click przyjmuje trzy argumenty. Pierwszym jest przycisk, który wywołał zdarzenie. Kolejne dwa to współrzędne kliknięcia. Gdyby zaszła taka potrzeba, programista może wykorzystać je w treści funkcji.
Process jest obiektem globalnym, który zarządza procesami oraz udostępnia systemowy wiersz poleceń w wykorzystanej przez nas funkcji Start. Jej pierwszym argumentem jest ścieżka, która ma być otwarta, natomiast drugi (opcjonalny) to argumenty dla uruchamianego programu, jak na przykład nazwa pliku do otwarcia. Dopieszczanie detali
Wszystko pięknie się prezentuje, równie dobrze działa, jesteśmy z siebie zadowoleni. Ale czy nie byłoby miło zobaczyć napis "Hello World!" w swoim ojczystym języku? W tym fragmencie pokażę, jak pobrać z ustawień regionalnych język użytkownika oraz załadować tłumaczenia z pliku XML.
Silnik skryptowy został wyposażony w wygodny system tłumaczeń ładowanych z plików XML. Plik ten ma taką strukturę:
<terms> <term name="oryginalnyTekst1">przetłumaczonyTekst1</term> <term name="oryginal2">tłumaczenie2</term> <term name="oryginal3">TłUmAcZeNiE3!!</term> </terms>Po wczytaniu tego pliku, silnik będzie umożliwiał przy pomocy pewnej funkcji sprawdzenie, czy dany tekst znajdował się w pliku, oraz jego ewentualną zamianę. Utwórzmy najpierw plik o nazwie POLISH.xml:
<terms> <term name="Hello World!">Dzień doberek!</term> </terms>Teraz zmodyfikujemy tylko funkcję zdarzenia Load tak, by miała następującą postać:
void Load() { String lang = Device.GetPrimaryLanguage(); Terms.LoadFromFile(lang+".xml"); String width = Device.AutoScaleValue(GetWidth()); bg.Surface.LoadFromFile("logo_"+width+".jif"); Controls.Add(bg); bg.SetBounds(0, 0, GetWidth(), GetHeight()); hello.SetAlign("Center", "Center"); hello.SetFont("Font.Title"); hello.SetText(Terms.Get("Hello World!")); Controls.Add(hello); int pad = GetHeight() – Device.AutoScaleValue(40); hello.SetBounds(0, pad, GetWidth(), Device.AutoScaleValue(40)); link.OnClick = link_click; Controls.Add(link); Link.SetBounds(0, 0, GetWidth(), GetHeight()); }Język użytkownika pobieramy za pomocą funkcji Device.GetPrimaryLanguage() i zapisujemy w zmiennej lang. Następnie ładujemy plik XML o odpowiedniej nazwie, np. POLISH.xml. Zmieniła się jeszcze jedna linijka:
hello.SetText(Terms.Get("Hello World!"));Terms.Get szuka tłumaczenia w załadowanym przez Terms.LoadFromFile pliku. Jeśli je znajdzie, zwraca je, w przeciwnym wypadku zwraca oryginalny tekst. Podsumowanie
Podsumowanie
W ten prosty sposób napisaliśmy aplet do Pointui. Czy okazało się to trudne? Myślę, że nie. Zachęcam Was do zainteresowania się tym tematem, bo możliwości języka są naprawdę duże. Jeśli ten artykuł wzbudzi zainteresowanie, to kto wie – może napiszę drugą część? Chyba już nawet wiem o czym...
[Dodaj komentarz (5)] - [Mini URL]
|
|||
|
|
|||
- Tygodniowy netcast w języku angielskim: WinMo World.
- RSSy: newsy i recenzje.
- Sprawdź jak możesz pomóc pda.pl: jakpomoc.pda.pl.
- Śledź nas na Twitterze lub Blipie.
- Obejrzyj wszystkie filmy pda.pl na Vimeo. Większość nagrań jest w 720p.
- Ruttensoft CloudFiles dla Windows Phone 7 już niebawem!
- HTC Desire Z z rdzeniem Scorpion taktowany na 800 MHz
- TomTom 1.5 dla iPhone jest już do kupienia
- Smartphonowi giganci pokazali na co ich stać - na nic
- Można już oficjalnie testować klawiaturę Swype
- Program dla WP7 w 90 sekund w Expression Blend
- Zarządzaj LiveJournal w biegu pod Windows Mobile
- Microsoft wymaga drobnych zmian od programisty - Adobe żadnych!... napewno?
- SlideIT - czyli coś podobnego do Swype
- ThickButtons - czyli ciekawa klawiatura, która pomaga szybciej pisać
Autor: nantael Kiedy: 2009-07-15 20:56:42
Super! Jezeli można to poproszę o zrobienie jakiegoś kursu, pokazującego więcej możliwości...
Autor: Mateusz Kiedy: 2009-07-16 21:05:42
Mógłbym machnąć kontynuację, ale nie teraz, bo w planach mam inny artykuł, i nie dla przeciętnego odbiorcy. To pisałem dla ludzi, którzy nie mieli wcześniej do czynienia z programowaniem apletów. Chciałem wszystko klarownie wytłumaczyć i pokazać z przykładami. Jest trochę rzeczy, które mógłbym jeszcze opisać, ale raczej nie w tym stylu, bo wyszłaby epopeja. Najbardziej pasowałoby mi coś w stylu:
- co chcemy osiągnąć
- jak to można rozwiązać
- najlepsze rozwiązanie + kod
Ale to nadawałoby się raczej na stronę o innym profilu, bardziej techniczną i poświęconą programowaniu. Rzeczy do omówienia jest sporo, choćby korzystanie z FlowStacka, tworzenie własnych klas i kontrolek albo obsługa INI i XMLa. Decyzja należy do Dawida.
Autor: KrzychuSmialek Kiedy: 2009-07-18 15:07:57
Dawid proponuje by @krzychu postawił sobie bloga. Napisał kontynuacje bardziej techniczna i wysłał do mnie linka. Wtedy ja umieszczę początek artykułu a reszta będzie do przeczytania na stronie Krzycha.
Wtedy każdy byłby zadowolony :) @krzychu jak Ci pasuje daj kiedyś znać jak machniesz taki artykuł.
Autor: DawidGatti Kiedy: 2009-07-18 18:39:55
Z tym blogiem to jest jakaś myśl, ale szybko wyczerpałyby mi się tematy i wszystko by zdechło. Kiedyś z resztą robiłem taką próbę, nie za bardzo to wyszło. Jak wiadomo, strona istnieje, dopóki jest aktualizowana. W momencie kiedy przestaje, ludzie na nią nie wchodzą, bo nie mają po co.
Chyba, żebym napisał coś pośredniego - na pewno byłoby więcej tekstu a mniej treści, ale mogłoby tu pasować. XMLa bym wtedy odpuścił, czyli w grę wchodzi FlowStack, INI i kontrolki. Tak czy inaczej, to na później. Teraz piszę co innego, powiedzmy - dla szerszego grona odbiorców.
Autor: KrzychuSmialek Kiedy: 2009-07-19 15:06:02
Podstrony
Najnowsze recenzje
Najpopularniejsze newsy
- •Tak będzie wyglądać HTC Desire HD
- •Wszystko co chciałeś wiedzieć o HTC Spark, Ace, Bee i Lexicon + zamieszanie z HD2
- •Dwa filmy o nadchodzących smartphonach HTC - Schubert i Desire HD
- •HTC Evo do kupienia na Allegro ale czy warto?
- •HTC T8788 z Windows Phone 7 - innowacja?
- •Dwie nowe oferty Play Online, dla zwykłych ludzi i studentów
- •4444 to liczba bestii z nadgryzionym białym logiem
- •Wyciek na temat Samsung, HTC i LG: 1 Android 2 Windows Phone 7
- •4299 PLN za iPhone 4 z 16 GB - czy to możliwe?
- •Jaki przeprowadzić test by odróżnić AMOLED od SLCD
Najnowsze komentarze
- •Ta informacja okazała się dla mnie bardzo istotna, dzięki. ...
- •a nie doczytałem :) co za polityka nie dość ze za darmo to ...
- •Czytając to zdanie: "Jeśli do piątku podasz swojego maila ...
- •no ok, zapisalem sie i dostalem odpowiedz dziekuje za wpis oraz ...
- •Android może się podniecać taką gierką, a na iPhona już ...
- •Zapisałem się, teraz tylko czekać na odpowiedź zostaje... ...
- •HTC się wycofało ze swojej obietnicy HD2 nie spełnia minimalnych ...
- •Może jeszcze być tak, że to ten sam sprzęt, tylko z nowym ...
- •Patrząc na zdjęcia nasuwa się pytanie. Czy HTC porzuciło ...
- •"Generalnie Apple stworzyła własną wersję Xbox Live." Czyli ...







