segunda-feira, 26 de maio de 2008

FishEyeList com LWUIT

Ola pessoal,

Continuando com minhas experiências com a biblioteca LWUIT, fiz agora um outro tipo de menu: um FishEyeList !!
Ou seja, conforme você alterna entre os itens da lista, o ícone correspondente fica maior, dando um destaque e indicando que item está selecionado. Esse tipo de lista ficou muito conhecida com o uso de Ajax e também com iPhone. E agora, você vai poder ter essa lista, fácil... fácil... na sua aplicação Java ME! ;-)



A lista
Esse tipo de menu em relação ao apresentado antes tem uma vantagem, usar menos imagem. Isso porque para dar o efeito de que a imagem está maior que a "normal" não é necessário gerar outra, mas sim utilizar o método image.sclaed(nova_larga, nova_altura).

O exemplo
Esse exemplo também foi todo feito em uma única classe MIDlet, FishEyeListMIDlet, e que tem o método montaFishEyeList que é chamado no startApp para que seja exibido o Form com o menu. E as ações dos botões são tratadas no actionPerformed, como vc já está se acostumando a ver aqui nesse blog! ;-)

montaFishEyeList( )
É o método que monta o menu com a FishEyeList. Para que ele faça a montagem, o método recebe 2 parametros:

  • Image[] icone: Array com os ícones a serem utilizados nos botões.
  • String[] label: Strings com os labels a serem utilizados nos botões.
No inicio do método há a criação do Form e a definição da figura de fundo. Também nesse ponto é definido o layout para o Form, que nesse caso será utilizado o layout BoxLayout e com a orientação no eixo Y, ou seja, cada item adicionado será colocado em uma linha dando a "impressão" de uma lista. O código relativo a essa parte se encontra abaixo:
Form fishEyeForm = new Form("FishEye List");
fishEyeForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
try {
fishEyeForm.setBgImage(Image.createImage("/background.png"));
} catch (IOException e) {}
Depois disso, é a hora de adicionar os botões e definir o comportamento de cada um. Isso será feito dentro de um loop que irá percorrer cada item dos arrays recebidos e em cada iteração serão executadas as seguintes ações:
  • Criação de um novo botão, com o texto e a imagem do array (utilizando o indice do loop). A forma de instanciar o novo botão é new Button(label[i], icone[i]).
  • Quando um botão é selecionado, o LWUIT coloca automaticamente uma cor indicando a seleção do botão. Para isso não acontecer e "atrapalhar" o comportamento usamos o método setBgTransparency(0).
  • O comportamento do botão precisa ser controlado por alguém e nesse caso, o midlet do exemplo é quem implementa a interface ActionListener e que deverá ser passado como parametro para o método addActionListener.
  • O efeito de FishEye (aumento da imagem) é feito alterando a imagem que é exibida quando o item está selecionado, através do método setRolloverIcon, e nesse caso aumentando o tamanho da imagem. No exemplo o aumento é de 30% da imagem utilizando o método scaled da imagem passada.
  • Além disso, o ícone também tem seu tamanho diminuido em 20% quando é clicado. Isso também é feito com o método scaled sendo passado para o método setPressedIcon.
  • O normal de um botão é ter sua borda desenhada para melhorar a visualização do componente. Porém, como estamos utilizando em um menu e o foco é a imagem a ser mostrada, a borda pode não ser desenhada. Para providenciar isso, iremos utilizar o método setBorderPainted(false).
O código do loop e criação do botão segue abaixo:
//criando os botões
Button b = null;
for ( int i = 0; i < icone.length; i++ ) {
b = new Button(label[i], icone[i]);
b.getStyle().setBgTransparency(0);
b.addActionListener(this);
b.setRolloverIcon(icone[i].scaled((int)(icone[i].getWidth()*1.3),
(int)(icone[i].getHeight()*1.3)));
b.setPressedIcon(icone[i].scaled((int)(icone[i].getWidth()*0.8),
(int)(icone[i].getHeight()*0.8)));
b.setBorderPainted(false);
fishEyeForm.addComponent(b);
}
Tratando o uso do botão
Pessoal, nesse ponto para não perder muito tempo e não extender muito o post, veja esse mesmo tópico no post anterior, pois essa parte é exatamente igual a anterior! ;)

Download e código completo
Para facilitar, todo o código do exemplo pode ser baixado em um ZIP, clicando AQUI, e dentro da pasta deployed é possível encontrar o JAR e JAD da aplicação para você ver o exemplo funcionando ou até instalar no seu celular.

[]s
Neto

sábado, 24 de maio de 2008

Ola pessoal,

Continuando no assunto da biblioteca LWUIT, resolvi fazer um menu e assim comparar também com o menu em canvas que fiz a um tempo aqui e que é o post mais acessado... disparado!!! :)
O menu também será bem simples, como foi o seu antecessor. Seu comportamento será da seguinte forma: na navegação há mudança na imagem indicando que o item está selecionado e quando clicado é disparado alguma ação, no nosso exemplo um Alert ("convencional"). Abaixo, imagens de como ficou:


As imagens do menu
Para deixar o menu com uma visualização melhor, para cada opção eu escolhi um icone e criei uma outra imagem com uma iluminação para dar impressão de que está apagado. Então, a cada vez que um icone é selecionado a imagem que foi indicada na criação do botão é trocada pela imagem que parece "acesa".
O único cuidado com essa prática é a questão de desempenho, pois se você escolher muitos ícones e icones muito grandes o desempenho pode cair muito e ao invés de ajudar, apenas piorar.

O exemplo
Para ilustrar, o exemplo consiste em apenas um MIDlet que contém um método chamado montaMenuForm( ) e que é chamado no startApp para retornar o Form que será exibido para o usuário. As imagens são carregadas no construtor.

montaMenuForm( )
É o método responsável por montar o Form com o menu e retornar para que ele seja exibido. Esse método recebe três parametros:

  • Image[] icones: Array com todos os icones que serão utilizados quando o itens estão selecionados.
  • Image[] iconesOff: Array com todos os icones que serão utilizados na criação do botão e quando o mesmo não está selecionado.
  • String[] label: Array de String para o label do botão.
Dentro do método, no inicio há a criação do Form, definição do background e configuração do layout a ser utilizado. No exemplo foi definido que será exibido 4 icones por linha e a quantidade de linhas do menu foi calculado de acordo com o número de itens do array, o trecho do código é o seguinte:
//Criando form
//Criação do Form
Form menu = new Form("Menu LWUIT");
try {
//definindo background
menu.setBgImage(Image.createImage("/background.jpg"));
} catch (IOException e) {}

//Montagem do layout
//4 colunas
int cols = 4;
//Calculando quantidade de linhas
int rows = (int)Math.floor(icones.length/4);
//Layout de exibição em grids
menu.setLayout(new GridLayout(rows,cols));
Depois de montado o layout, é hora de adicionar os botões e definir o comportamento de cada botão. Para isso será feito um loop pelo array de imagens e em cada interação serão executadas as seguintes ações:
  • Criação de um novo botão, com o texto e a imagem do array de imagens "não-selecionadas" (utilizando o indice do loop). A forma de instanciar o novo botão é new Button(label[i], iconesOff[i]).
  • Definir a imagem que será exibida quando o item do menu estiver selecionado, através do método setRolloverIcon passando como parametro a imagem do array de imagens selecionadas, também de acordo com o indice do loop.
  • Definir a imagem que é exibida quando o item é clicado, através do método setPressedIcon passando como parametro a imagem do array de imagens selecionadas, também de acordo com o indice do loop.
  • Quando um botão é selecionado, o LWUIT coloca automaticamente uma cor indicando a seleção do botão. Para isso não acontecer e "atrapalhar" o comportamento usamos o método setBgTransparency(0).
  • O normal de um botão é ter sua borda desenhada para melhorar a visualização do componente. Porém, como estamos utilizando em um menu e o foco é a imagem a ser mostrada, a borda pode não ser desenhada. Para providenciar isso, iremos utilizar o método setBorderPainted(false).
  • E por fim, o comportamento do botão precisa ser controlado por alguém e nesse caso, o midlet do exemplo é quem implementa a interface ActionListener e que deverá ser passado como parametro para o método addActionListener.
O código do loop e criação do botão segue abaixo:
//Criando botões e adicionando ao grid
for ( int i = 0; i < icones.length; i++ ) {
b = new Button(label[i], iconesOff[i]);
//imagem para exibir ao selecionar botão
b.setRolloverIcon(icones[i]);
//imagem para exibir ao clicar no botão
b.setPressedIcon(icones[i]);
//Removendo o fundo de seleção do botão
b.getStyle().setBgTransparency(0);
//alinhamento e posição do texto do botão
b.setAlignment(Button.CENTER);
b.setTextPosition(Button.BOTTOM);
//não desenhar borda no botão
b.setBorderPainted(false);
//indicando o listener do botão
b.addActionListener(this);
//adicionando o botão ao form
menu.addComponent(b);
}
Tratando o uso do botão
Quando o usuário clica no botão é necessário tratar esse botão. Esse tratamento é feito através do método actionPerformed na classe que implementar a interface ActionListener. No nosso exemplo isso é feito no midlet da aplicação.
A programação desse método pode ser feita conforme cada programador desejar, o importante nesse ponto é identificar qual botão foi clicado e ai direcionar corretamente o usuário. O método recebe o objeto ActionEvent que permite que através do método getSource() seja recuperado o objeto que originou a chamada, e no nosso caso o botão cliclado.
Com o botão clicado, para distinguir qual botão foi clicado usaremos o texto que foi indicado na criação do botão através do método getText() e ai então, exibir um Alert. Nesse caso, customize qual ação deseja tomar. Um trecho desse método segue abaixo:
public void actionPerformed(ActionEvent evt) {
//Obtendo botão que disparou o evento
Button b = (Button) evt.getSource();
//Verificando pelo titulo qual botão é
if ( b.getText().equals("Bluetooth")) {
Alert a = new Alert("Selecionado", "Bluetooth", null, AlertType.INFO);
javax.microedition.lcdui.Display.getDisplay(this).setCurrent(a);
} else if ( b.getText().equals("Pesquisar")) {
Alert a = new Alert("Selecionado", "Pesquisar", null, AlertType.INFO);
javax.microedition.lcdui.Display.getDisplay(this).setCurrent(a);
}
//Continua comparações
//definindo focus
menu.setFocused(b);
}
Download e código completo
Para facilitar, todo o código do exemplo pode ser baixado em um ZIP, clicando AQUI, e dentro da pasta deployed é possível encontrar o JAR e JAD da aplicação para você ver o exemplo funcionando ou até instalar no seu celular.

Conclusão e comparação
Bom, quem já viu o outro exemplo e esse agora pode de cara perceber que esse tem um melhor acabamento e é muito mais facil de ser criado e customizado. Porém, o overhead causado pela quantidade de imagens necessárias e pela inclusão da biblioteca LWUIT. Para ver isso, basta comparar o tamanho das duas aplicações.
Mas, na minha opinião, se for um menu pequeno e com imagens não tão complexas, o uso vale a pena!! E além disso, você pode estudar e fazer o menu de uma forma que atenda melhor suas necessidades!

[]s
Neto

terça-feira, 20 de maio de 2008

Uma pequena análise da LWUIT

Ola pessoal!!

Essa semana eu tive a oportunidade de escrever um artigo sobre essa interessante biblioteca e para ilustrar o artigo acabei montando uma aplicação de exemplo e então consegui tirar algumas conclusões e vou dar algumas opiniões aqui para vocês! :)

Nova forma de programar
Como os próprios autores declararam no site do projeto, a LWUIT foi feita pensada no Swing, então a forma de utilizar alguns componentes é bem parecida com seus "similares" no Swing, como por exemplo um Button. Abaixo, um exemplo onde se cria um botão e define a chamada de um método estático qualquer quando um botão é clicado:

Button botao = new Button("Processar");
botao.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
//chamada para um método qualquer...
}});
Para alguns que não possuem muita vivência com Swing (como é o meu caso), algumas coisas podem soar estranhas, mas considero ser apenas questão de costume pois apesar de diferente são bem simples.

Novos recursos interessantes
Algumas das principais funcionalidades que o LWUIT oferece, podem ser consideradas como novas versões de funcionalidades já existentes no pacote javax.microedition.lcdui. Porém, a biblioteca traz algumas novidades como por exemplo: caixa de diálogo, abas, transição entre telas, novas opções de fonte, criação de temas. Além de automatizar (facilitando também é claro) alguns comportamentos, como por exemplo o scrol de uma tela.
Acima imagens retiradas da aplicação demo fornecida pelo projeto.

Estabilidade
É claro que por se tratar de um "lançamento" ainda há alguns pequenos ajustes a serem feitos. Como é o caso do TabbedPane que aceita um Component como paramêtro e então, eu resolvi criar um Form com diversos componentes e colocar esse Form dentro de uma aba. Compilou, executou e foi exibido corretamente, mas quando tentei usar não conseguia entrar na aba que eu queria e a navegação pelas abas ficava completamente perdida.
O que fazer então? Mandei um e-mail na lista de users do projeto e recebi a resposta de que realmente isso não funciona, e que eles iriam colocar uma exception de illegalargument no caso de alguém tentar fazer a mesma coisa, já que eu não era o primeiro a perguntar sobre isso.
Enfim, a melhor coisa a fazer é entrar em contato com o pessoal e repassar os problemas e assim ajudarmos a biblioteca a evoluir!!

Ferramenta deskotp
Como dito antes, é possivel se criar temas para o LWUIT e isso é feito através de uma aplicação desktop bem simples de usar, onde você vai configurando cada tipo componentes a ser utilizado e seu estilo. Permitindo assim um alto nivel de acabamento da sua aplicação.

Performance
É claro que a performance em alguns casos deixa a desejar, porém isso acontece principalmente se você sobrecarregar sua aplicação com tudo que o LWUIT lhe oferece. Mas você pode fazer a mescla de componentes LWUIT e componentes high level.
Por exemplo: Pode ser feito um menu utilizando um Form com o Layout grid e com diversos botões, e após isso, utilizar os forms (ou lists) comuns e sua aplicação continuará "leve".

Conclusão
É uma biblitoeca que me surpreendeu, assim como a mais pessoas, e que com certeza colaborará com a melhoria da qualidade das interfaces e na facilidade do desenvolvimento. Mas, deve ser utilizado com muito cuidado, pois pode comprometer a sua aplicação. Tente sempre testar em dispositivos reais para ter uma noção desse comprometimento. E é claro, contribua enviando sugestões e notificando possiveis bugs. Pois assim, ela vai sendo "polida" e cada vez mais melhorada!

E atenção, estou preparando um menu utilizando um Form com Button e que teria o comportamento similiar a um menu que publiquei a muito tempo atrás aqui e que é o post mais acessado. E assim, poderemos comparar a facilidade e agilidade no desenvolvimento. Aguardem!!!

[]s
Neto

sábado, 17 de maio de 2008

Usando StringItem para fazer listagens.

Ola pessoal,

Algumas vezes queremos fazer algumas listagens em nossos Forms, ou mesclar conteúdo e permitir uma navegação pelos itens e a sua seleção e o uso da lista compromete a usabilidade ou simplesmente não funciona!
Por exemplo, aqueles que já tiveram a oportunidade de usar o JustJava mobile no ano passado (com a grade horária) ou já deu uma olhada no CoSMo (que "nasceu" do JustJava Mobile), viram que na listagem das palestras do dia é possível clicar em uma determinada palestra e ver o detalhe dessa palestra, como nas figura abaixo:

O problema nesse caso é que os nomes dos locais e o título das palestras poderia ser grande, e como eu não confio muito no comportamento do List em diferentes dispositivos, a solução intuitiva era usar StringItem !!
Mas ai eu tinha um problema: Como "descobrir" em qual palestra o usuário clicou para exibir o detalhe corretamente?
No List (ou ChoiceGroup) seria fácil, já que eu tenho o indice selecionado. Então, o mais fácil era ter um indice próprio para que eu pudesse recuperar o registro certo no RMS, nesse caso o próprio ID no RMS.

Criando um novo "StringItem"
Bom, nesse caso então a minha idéia foi criar um novo componente que extendia de um StringItem, portanto eu tinha todo o comportamento já conhecido, e adicionar um atributo de código "escondido", para poder armazenar o ID e depois usar. E a nova classe que criei ficou assim:


public class HiddenIdStringItem extends StringItem {
private int hiddenId;

public HiddenIdStringItem(String label, String text) {

//Uso normal como se fosse um simples StringItem...
super(label, text);
}

public HiddenIdStringItem(int toHiddenId, String label,
String text) {

//construtor da superclasse
super(label, text);
//salvando o ID que se deseja "esconder"
this.hiddenId = toHiddenId;
}

public HiddenIdStringItem(String label, String text,
int appearanceMode) {

//Uso normal como se fosse um simples StringItem...
super(label, text, appearanceMode);
}

public int getHiddenId() {
return hiddenId;
}

public void setHiddenId(int sessionId) {
this.hiddenId = sessionId;
}
}


Como habilitar o click?
Para que o usuário possa clicar no seu novo componente, basta você usar o método setDefaultCommand (no seu item do tipo HiddenIdStringItem), passando como parâmetro algum comando e depois o método setItemCommandListener (também no seu item), passando a instância de uma classe que implementa a interface ItemCommandListener, para que alguém "trate" esse comando que você adicionou.
A classe que implementa a interface, deverá então implementar o método commandAction que recebe o comando associado ao seu item e qual item que se trata. No nosso caso, um item do tipo HiddenIdStringItem. Então, você faz o cast adequado (de item para HiddenIdStringItem) e pode utilizar o método getHiddenId para obter o id que você associou quando criou o componente.

Vantagens
  • Utilizando esse componente você evita problemas com Lists e Choice Groups.
  • Você não precisa ficar comparando o label ou o text para saber qual item é aquele.
  • Ja herda todo o comportamente conhecido do StringItem.
Cuidados:
  • Adicionar o comando e seu listener corretamente.
  • Utilizar os layouts corretamente para não ter surpresas desagradáveis com a exibição dos itens na tela.
Bom pessoal, espero que isso possa ajudar alguém ou que facilite a vida de seus usuários! ;-)

[]s
Neto

quinta-feira, 8 de maio de 2008

Melhore o visual da sua aplicação com LWUIT !!

Ola pessoal,

Eu já tinha lido uma prévia do projeto LWUIT no blog do Terrence na "Mobile & Embedded Community" e já tinha me deixado empolgado, pois até o título do post era promissor: "Em Breve: Swing para mobile, mas melhor" (em tradução livre). E não era para menos, deem uma olhada nos screenshots que divulgaram:


E hoje, durante o JavaOne, o pessoal do projeto apresentou o primeiro release dessa biblioteca que promete melhorar e muito o visual dos aplicativos em Java ME. Além disso, é um projeto apoiado pela Sun (interno) e que está sob a licença GPL, porém com o classpath exception, ou seja, você pode usá-lo tranquilamente em aplicações fechadas.
Tem algumas features interessantes:

  • Swing-like MVC
  • Layouts
  • Suporte look-and-feel e temas
  • Fontes
  • Suporte Touch screen
  • Animações e transições
  • Integração 3D
  • Suporte I18N/L10N (internacionalização)
  • Performance moderada e baixo footprint.
  • Multi-plataforma (MIDP/CDC/FP/PBP)
  • Compatibilidade com SVG (scalable vector graphics)
Eu acabei de ler o tutorial que eles publicaram e estou fazendo uma pequena aplicação para controle de despesas pessoais e irei utilizar LWUIT para testar e posteriormente implementar também no projeto CoSMo. Então, assim que concluir esse pequeno aplicativo eu posto aqui uma avaliação, tutorial e o aplicativo para vocês usarem e testarem!!

Para saber mais, visitem o site do projeto LWUIT !

Abraços
Neto Marin

quinta-feira, 1 de maio de 2008

Tooltip para listas.

Ola pessoal,

Seguindo a idéia de apresentar alguns problemas que encontrei no desenvolvimento JME e soluções que utilizei, segue uma funcionalidade que pode ser incorporada a listas e ajudar o seu usuário durante a utilização da sua aplicação. Trata-se de um "tooltip" que é exibido quando o usuário fica um determinado tempo parado "em cima" de um determinado item da lista.

A idéia
A idéia era que quando o usuário ficasse um tempo parado em um item da lista fosse exibido algo onde pudesse ser exibida alguma explicação para o usuário sobre esse item que ele esta "selecionando". Alguns celulares Nokia possuem esse recurso e quando bem utilizado pode trazer um alto grau de usabilidade!

O Exemplo
No exemplo que vou mostrar aqui (e que o código está disponivel), eu optei por utilizar um Alert. Mas, fica ao gosto do fregues! =) E se achar que fica melhor utilizar um Ticker, ou um CustomItem e mostrar um aviso no meio da tela, fique a vontade, eu mostrarei o trecho que você deve alterar! ;-)
A aplicação está dividida em 3 classes (ListTooltipMIDlet, ListSelectionListener e TooltipTimer) que terão o seu funcionamento básico explicado abaixo.

ListSelectionListener
Essa classe, que implementa a interface Runnable, recebe como parametro para seu construtor a instância do Display atual da aplicação e a lista que terá suas ações "controladas" e o tooltip exibido. Essa classe é feita como uma thread pois ela tem que ficar o tempo todo verificando a mudança de seleção da lista.
Sua tarefa consiste básicamente em um loop (eterno) dentro do corpo do método run, que a cada interação é verificado se o indice de seleção da lista foi alterado desde a ultima execução. Caso o indice tenha sido alterado (o usuário mudou de opção dentro da lista), a variável de controle é atualizada, o schedule antigo de exibição é cancelado e uma nova instância da classe TooltipTimer é criada e schedulada para 2 mil milisegundos, ou seja, 2 segundos. Em seguida, a thread recebe o comando de sleep de 500 milisegundos (meio segundo).

TooltipTimer
Essa classe, que extende de uma TimerTask, assim como a ListSelecionListener recebe como parametro do seu construtor a instância do Display e da lista. Essa classe será executada 2 segundos após ela ter sido schedulada na classe ListSelectionListener e caso não tenha seu timer cancelado.
Sua tarefa a ser executada está dentro do método run e, nesse caso, é mostrar um alert com um texto. É justamente esse ponto que você deve alterar caso deseje que ele faça uma ação diferente, como por exemplo atualizar um ticker da sua List, chamar um novo form ou o que você achar interessante! =)

ListTooltipMIDlet
Bom, essa midlet nada mais é que apenas uma simples classe para poder fazer o exemplo funcionar. Aqui eu somente criei uma lista com alguns itens (que chamei de itens), exibi e depois fiz a utilização das classes que criei aqui, através da seguinte linha:

Thread t = new Thread(new ListSelectionListener(Display.getDisplay(this),
itens));
t.start();

Fiquem a vontade para usar o código, modificar ou até ignorar !! =)

Downloads

Projeto completo (Eclipse) com código fonte, clique aqui!
Aplicação exemplo (.jar), clique aqui!

[]s
Neto