piątek, 9 stycznia 2009

Pierwszy MIDlet v2.0 -> LWUIT incoming!

W czasach średniowiecznych opisałem tutaj jak napisać prosty midlet na urządzenie mobilne. Przedstawiłem to na standardowych kontrolkach z MIDP 2.0. Dziś chciałbym pokazać jak napisać pierwszy MIDLet ale już w dużo bardziej rozbudowanej i wszechstronnej bibliotece - Lightweight UI Toolkit (LWUIT).
Co nam daje ta biblioteka ? Oto główne korzyści:
- model MVC podobny do swingowego
- aplikacja wygląda i działa identycznie na każdym urządzeniu
- dużo większa liczba kontrolek
- layouty jak w swingu (BoxLayout, GridLayout itd...)
- Look and Feel oraz bardzo łatwa ich zmiana nawet podczas działania aplikacji
- różnego rodzaju animacje i efekty przejścia
- wszystkie komponenty UI mogą być w łatwy sposób modyfikowane (nie są oznaczone jako final - można dziedziczyć)
- okienka modalne
- obsługa ekranów dotykowych
- internacjonalizacja
- zmiana czcionek
Hmmm... chciałem tylko kilka wymienić a tu się dość spora lista zrobiła ;P Jak wygląda LWUIT w akcji ? Możecie zobaczyć na filmiku poniżej:

Już się wszystkim podoba ? Mnie bardzo! W połączeniu z licencją GPL jeszcze bardziej ^^
No to czas coś napisać. Najpierw ściągnijmy bibliotekę : link. I tworzymy nowy projekt w ulubionym środowisku. Ja będę korzystać z NetBeans. Dodajemy klasę typu MIDlet do projektu, dodajemy bibliotekę LWUIT.jar oraz katalog resources do którego wrzucamy plik z motywem (link). Motyw pochodzi z przykładowego projektu LWUITDemo rozprowadzanego razem z biblioteką.
Najpierw pokażę cały kod a później omówię najważniejsze elementy.
LWUITDemo.java
package com.blogspot.wookasz.lwuitdemo;

import com.sun.lwuit.Command;
import com.sun.lwuit.Display;
import com.sun.lwuit.Form;
import com.sun.lwuit.Label;
import com.sun.lwuit.animations.CommonTransitions;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.layouts.BorderLayout;
import com.sun.lwuit.plaf.UIManager;
import com.sun.lwuit.util.Resources;
import javax.microedition.midlet.MIDlet;

public class LWUITDemo extends MIDlet {
private static final String THEME_FILE = "/businessTheme.res";
public void startApp() {
try {
// inicjalizacja ekranu
Display.init(this);

// otwarcie i wczytanie motywu
Resources r = Resources.open(THEME_FILE);
UIManager.getInstance().setThemeProps(r.getTheme(r.getThemeResourceNames()[0]));

// tworzenie formatek
final Form firstForm = new Form("Pierwsza formatka");
firstForm.setLayout(new BorderLayout());
Label label1 = new Label("Hello world!");
label1.getStyle().setBgTransparency(100);
firstForm.addComponent(BorderLayout.CENTER, label1);

final Form secondForm = new Form("Druga Formarka");
secondForm.setLayout(new BorderLayout());
Label label2 = new Label("and Hello LWUIT !!");
label2.getStyle().setBgTransparency(100);
secondForm.addComponent(BorderLayout.CENTER, label2);

// przypisanie animacji przejść
firstForm.setTransitionInAnimator(
CommonTransitions.createSlide(CommonTransitions.SLIDE_HORIZONTAL,
false, 1000));
secondForm.setTransitionInAnimator(
CommonTransitions.createSlide(CommonTransitions.SLIDE_HORIZONTAL,
true, 1000));

// dodawanie przycisków
Command goBtn = new Command("Wciśnij mnie!", 1) {
public void actionPerformed(ActionEvent evt) {
secondForm.show();
}
};
firstForm.addCommand(goBtn);

Command backBtn = new Command("Powrót!", 1) {
public void actionPerformed(ActionEvent evt) {
firstForm.show();
}
};
secondForm.addCommand(backBtn);
// przycisk wyjścia
Command exitCmd = new Command("Wyjście", 2) {
public void actionPerformed(ActionEvent evt) {
destroyApp(true);
notifyDestroyed();
}
};
firstForm.addCommand(exitCmd);
secondForm.addCommand(exitCmd);

// wyświetlenie formatki pierwszej
firstForm.show();
} catch (Exception ex) {
ex.printStackTrace();
}
}

public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
}

Pierwsza instrukcja inicjalizuje ekran, musi być ona wywołana przed wyświetleniem pierwszej formatki. Jako parametr należy podać obiekt dziedziczący po klasie MIDlet.
Następne dwie linie
Resources r = Resources.open(THEME_FILE);
UIManager.getInstance().setThemeProps(r.getTheme(r.getThemeResourceNames()[0]));
Załatwiają za nas całe wystylizowanie aplikacji:) Pierwszy wczytuje zbiór danych w którym znajduje się nasz motyw. W drugim go ustawiamy jako aktualny, szybkie i proste:) W jednym zbiorze może znajdować się wiele motywów dlatego odwołujemy się do tablicy w r.getThemeResourceNames()[0].
final Form firstForm = new Form("Pierwsza formatka");
firstForm.setLayout(new BorderLayout());
Label label1 = new Label("Hello world!");
label1.getStyle().setBgTransparency(100);
firstForm.addComponent(BorderLayout.CENTER, label1);
Tworzymy pierwszą formatkę. Parametrem jest napis jaki ma się pojawić na górnej belce, tak samo jako w standardowym formie. Następnie dla tej formatki ustawiamy layout typu BorderLayout, zgodnie z tym layoutem będą rozmieszczane wszystkie konponenty. W następnie dodajemy jeden komponent (napis) i dodajemy go na środek. Wcześniej jednak ustawiamy jego tło na całkowicie przezroczyste żebyśmy mogli widzieć tło aplikacji jakie jest zdefiniowane w motywie. W layoucie BorderLayout środkowa jego część zawsze zajmuje największą możliwą przestrzeń, gdybyśmy nie przypisali przezroczystego tła napisowi, nie zobaczylibyśmy tła aplikacji. Podobnie postępujemy z drugą formatką.
firstForm.setTransitionInAnimator(
CommonTransitions.createSlide(CommonTransitions.SLIDE_HORIZONTAL,
false, 1000));
Przypisujemy animacje dla sytuacji gdy formatka ma się pojawić. Trwać ona będzie 1000ms oraz będzie przesuwać się w stronę lewą. Podobnie tworzymy dla drugiej formatki, tylko animacja tam będzie przesuwać się w prawo.
Command goBtn = new Command("Wciśnij mnie!", 1) {
public void actionPerformed(ActionEvent evt) {
secondForm.show();
}
};
firstForm.addCommand(goBtn);
Podczas tworzenia przycisków możemy od razu zdefiniować jaka akcja ma się wykonać podczas jego przyciśnięcia. Robimy to tworząc metodę actionPerformed dla tego przycisku. Co prawda nie jest to za bardzo zgodne z modelem MVC ale dla drobnych akcji takie podejście chyba nie jest aż tak złe. Akcja która zdefiowaliśmy wyświetla drugą formatkę. Oczywiście pojawia się ona z efektem przejścia który przypisaliśmy jej wcześniej.
Dalej w kodzie przypisujemy kolejne przyciski o dość zrozumiałym działaniu, by na końcu wyświetlić pierwszą formatkę metodą show().
Uruchamiamy!

U mnie działa:) Zachęcam do przetestowania na telefonie, nie powinno być problemów raczej.
Należy pamiętać, że jeśli użyjemy efektu przejścia jakim jest np. Transition3D.createRotation(int, bool) to jest wymagane od urządzenia obsługa 3D (pakiet javax.microedition.m3g).

To by było na tyle mojego bardzo krótkiego wstępu do Lightweight UI Toolkit. Zachęcam do zapoznania się z API - bardzo proste i rozbudowane zarazem. Ja z pewnością napisze jeszcze trochę tutaj na ten temat. Pracuję już z LWUIT kilka miesięcy i trochę ciekawostek się nazbierało do opisania ^^

Zapraszam do komentowania!

Linki:
Projekt NetBeans przykładu z wpisu: download
Strona domowa - https://lwuit.dev.java.net/
Oficjalne forum - http://forums.java.net/jive/forum.jspa?forumID=139
Blog - http://lwuit.blogspot.com/

6 komentarzy:

  1. No artykuł ciekary, ale sposób prezentacji na blogu kodu i reszzta tych wąskich kolumienek do bani :)

    OdpowiedzUsuń
  2. od dłuższego czasu przymierzam się do poszerzenia trochę pola na posty, to by poprawiło znacznie czytelność kodu. Muszę to zrobić w końcu ;-)

    dzięki za komentarz !

    OdpowiedzUsuń
  3. Ciekawy art panie. Szkoda ze teraz tak mało czasu żeby się za to zabrać. W wolnej chwili na pewno spróbuje.

    OdpowiedzUsuń
  4. Jak sobie poradzić z polskimi znakami, bo coś nie bardzo chcą działać ??

    OdpowiedzUsuń
  5. sprawdź kodowanie projektu. Ustaw gdzie możesz na UTF-8

    pozdr!

    ps. szczerze mówiąc też miałem problemy z kodowaniem ;)

    OdpowiedzUsuń
  6. Jak zrobić aby w polu TextField można było wpisywać polskie znaki bez klikania na T9 ?

    OdpowiedzUsuń