Componentes Personalizados com CustomItem

Transcrição

Componentes Personalizados com CustomItem
Componentes Personalizados com CustomItem
Ricardo da Silva Ogliari
Introdução
Devido ao crescente uso da plataforma Java 2 Micro Edition na programação para
pequenos dispositivos, a necessidade de alguns componentes especiais surgiu ao
natural, muitos deles não inclusos na API da MIDP (Mobile Information Device Profile),
como por exemplo, gráficos e tabelas. Atualmente, podemos usar a classe Canvas
para criarmos interfaces gráficas mais elaboradas, porém não pdoemos utilizar utilizar
um Canvas junto com os outros Itens gerenciáveis pela classe Form.
Contudo, uma das novas características presente na versão 2.0 da MIDP, é a
inclusão de uma classe chamada CustomItem, que habilita o desenvolver a criar seus
próprios componentes personalizados, além disso, as interfaces gráficas baseadas em
um Form ganham mais interatividade, isto porque, é possível unir um CustomItem com
os Itens presentes na MIDP.
Nos próximos tópicos deste artigo, o leitor verá o conhecimento básico
necessário para construir seus primeiros componentes, como estudo de caso, será
desenvolvido uma projeto chamado JMTable, que objetiva implementar uma tabela
semelhante aquela encontrada nos pacotes gráficos Swing e AWT.
Custom Item
Semelhante ao que ocorre com uma classe derivada de Canvas, para implementar um
componente personalizado deve-se ter ao menos uma classe que estenda da classe
CustomItem e implemente alguns métodos de forma obrigatória, sendo eles:
getMinContentHeight(),
getMinContentWidth(),
getPrefContentHeight(),
getPrefContentWidth() e paint(). Além disso, o construtor da classe criada, deve ter
uma referência ao construtor da sua classe pai, sendo ela o CustomItem, passando
uma String que será o rótulo do componente, assim como ocorre com todos os Itens.
A listagem 1 mostra o esqueleto da classe JMTable.
public class JMTable extends CustomItem{
public JMTable (){
super("Tabela");
}
protected int getMinContentHeight() {}
protected int getMinContentWidth() {}
protected int getPrefContentHeight(int param) {}
protected int getPrefContentWidth(int param) {}
protected void paint(Graphics graphics, int param, int param2) {
}
Listagem 1 – Esqueleto da classe JMTable
Os métodos getMinContentHeight() e getMinContentWidth() especificam a
altura e largura mínima do componente, em contrapartida, os métodos
getPrefContentHeight() e getPrefContentWidth() servem para configurar a altura e
largura preferencial. O método paint() é o mais importante dos métodos que devem ser
estendidos, pois é onde “desenhamos“ o que o componente exibirá na tela do celular,
da mesma forma que especificamos o que uma classe Canvas exibirá. A única
diferença entre no paint() das duas abordagens citadas anteriormente, são os
http://www.javafree.org/
A voz Java no Brasil – Pág. 1
parâmetros, no CustomItem é passado uma instância de um objeto Graphics, a largura
e a altura do componente.
Estudo de caso: JMTable
O objetivo deste estudo de caso é a criação de um componente que exibirá
uma tabela no display do dispositivo, por isso o nome escolhido foi JMTable, em
referência ao JTable do Swing; o 'M' é de Mobile. A figura 1 demonstra o componente
em uso no emulador do software Wireless Toolkit. No Form estão inseridos um
StringItem especificando de qual tabela seriam os dados, no caso da leitura ter sido
feita em um RecordStore, e abaixo aparece o JMTable.
Figura 1 - Componente JMTable no emulador do Wireless Toolkit.
A análise do código começará pelo construtor da classe, veja a listagem 2. O
construtor foi modificado para receber as colunas e os dados que a tabela deve
mostrar, também, recebe por parâmetro o tamanho da fonte e a largura do display do
dispositivo, o último parâmetro é necessário porque desejamos que a tabela preencha
toda a parte horizontal do dispositivo, como mostra a figura 1.
No corpo do construtor são atribuídos os parâmetros recebidos para as
variáveis globais, em seguida, com o auxílio do operador ternário definimos a fonte
conforme o seu tamanho, recebido no construtor. A altura é calculada levando em
conta o tamanho da fonte que será aplicada no cabeçalho da tabela, somando com a
multiplicação entre a quantidade de dados e a altura da fonte aplicada nos dados
tabela.
http://www.javafree.org/
A voz Java no Brasil – Pág. 2
public JMTable(Vector colunas, Vector dados, int tam_fonte, int largura)
{
super("");
this.largura = largura;
this.colunas = colunas;
this.linhas = dados;
this.tam_fonte = tam_fonte;
fonte = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN,
(tam_fonte==0 ? Font.SIZE_SMALL : tam_fonte == 1 ?
Font.SIZE_MEDIUM:Font.SIZE_LARGE));
fonteCols = Font.getFont(Font.FACE_MONOSPACE,
Font.STYLE_BOLD, (tam_fonte==0 ? Font.SIZE_SMALL : tam_fonte ==
1 ? Font.SIZE_MEDIUM:Font.SIZE_LARGE));
}
altura = fonte.getHeight()+(fonteCols.getHeight()*linhas.size());
Listagem 2 – Construtor da classe JMTable
A definição das dimensões mínimas e das dimensões preferidas são mostradas
na listagem 3, ambas são configuradas com a variável largura, que foi recebida por
parâmetro no construtor, a mesma representa o tamanho horizontal da tela do
dispositivo. A altura mínima é definida com a altura da instância de Font, chamada
fonte, que é aplicada nos nomes das colunas, ou seja, o tamanho mínimo mostrará ao
menos o cabeçalho da tabela; por sua vez, a altura preferida é a variável altura que foi
definida ainda no construtor.
protected int getMinContentHeight() {
return fonte.getHeight();
}
protected int getMinContentWidth() {
return largura;
}
protected int getPrefContentHeight(int param) {
return altura;
}
protected int getPrefContentWidth(int param) {
return largura;
}
Listagem 3 – Definição dos tamanhos
Para melhor compreensão da explicação do principal e maior método da classe
JMTable, o método paint(), de uma olhada rápida na listagem 4. As duas primeiras
linhas servem para pintar a área de visualização do item com branco, isso é
importante porque nem todas as JVM´s fazem este trabalho automaticamente,
portanto, para garantir portabilidade é indicado fazer este procedimento.
As linhas 4 e 5 pintam a área do cabeçalho, que terá uma cor
acinzentada. Da linha 6 até a linha 12, é feito do desenho das bordas da tabela e das
linhas verticais, as linhas 13 à 17 pintam as linhas horizontais. É importante analisar a
http://www.javafree.org/
A voz Java no Brasil – Pág. 3
definição
do
traçado
setStrokeStyle(g.DOTTED).
pontilhado
na
linha,
utilizando
o
método
protected void paint(Graphics g, int w, int h) {
1 g.setColor(255, 255, 255);
2 g.fillRect(0, 0, w-1, h-1);
3
4 g.setColor(200, 200, 200);
5 g.fillRect(0, 0, w, fonte.getHeight());
6 g.setColor(0, 0, 0);
7 g.drawLine(0, fonte.getHeight(), w, fonte.getHeight());
8 for (int i = 1; i < colunas.size(); i++)
9 {
10
g.drawLine((w/colunas.size())*i, 0, (w/colunas.size())*i, h-1);
11 }
12 g.drawRect(0, 0, w-1, h-1);
13 g.setStrokeStyle(g.DOTTED);
//desenha linhas horizontais entre as linhas da tabela
14 for (int i = 1; i < linhas.size(); i++)
15 {
16 drawLine(0, fonteCols.getHeight()+(fonte.getHeight()*(i)), w,
fonteCols.getHeight() + (fonte.getHeight()*(i)));
17 }
18 g.setFont(fonteCols);
20 for (int i = 1; i <= colunas.size(); i++)
21 {
22
g.drawString (colunas.elementAt( i-1 ).toString(), (
(w/colunas.size())/2 ) * I + ( w / colunas.size() / 2 * (i - 1) ),
fonteCols.getHeight(), Graphics.HCENTER|Graphics.BOTTOM);
23 }
24 g.setFont(fonte);
25 for (int i = 0; i < linhas.size(); i++)
26 {
27
if (i == indice)
28
g.setColor(0, 0, 255);
29
else if (i == indice_marc)
30
g.setColor(255, 0, 0);
31
else
32
g.setColor(0, 0, 0);
33
String[] dados = (String[]) linhas.elementAt(i);
34
for (int j = 1; j <= colunas.size(); j++)
35
{
36
g.drawString(dados[j-1], ((w/colunas.size())/2)*j +
(w/colunas.size()/2*(j-1)), fonteCols.getHeight() +
(fonte.getHeight()*(i+1)), Graphics.HCENTER|Graphics.BOTTOM);
37
}
38 }
}
Listagem 4 – Definição do método paint
O intervalo de linhas, que começa na 18 e vai até a 23, desenha os nomes dos
cabeçalhos, e o restante do código desenha as linhas da tabela com seus respectivos
valores. O conjunto de if-else presente na linha 28 até a linha 32 testa se o índice de
http://www.javafree.org/
A voz Java no Brasil – Pág. 4
navegação, que é controlado pelas setas direcionais up e down, está encima de um
dos itens, ou ainda, se um dos itens está marcado, nenhuma das situações ocorrendo
o último else é chamado e então, é usada a cor padrão, o preto. Para entender as
variáveis indice e idice_marc olhe o código completo.
O último método usado na classe JMTable a ser detalhado é o traverse(), que
também é de grande importância, ele é usado para gerenciar o controle do foco, tanto
quando o item ganha, mas também quando deve perder. Por padrão este método
retorna false, ou seja, qualquer uma das teclas direcionais aplicada sobre o item fará
com que o componente perca o foco, porém redefinimos o método para não deixar
que isso acontecesse. A listagem 5 ilustra o método traverse().
protected boolean traverse(int dir, int viewportWidth, int viewportHeight,
int[] visRect_inout )
{
switch ( dir )
{
case Canvas.UP:
return testaParaCima();
case Canvas.LEFT:
return testaParaCima();
case Canvas.DOWN:
return testaParaBaixo();
case Canvas.RIGHT:
return testaParaBaixo();
case NONE:
// do nothing: just a form layout reflow
return true;
}
}
return false;
}
Listagem 5 – Definição do método traverse
Dos parâmetros recebidos pelo método traverse, o mais importante é
justamente o primeiro, que indica o código da tecla que foi pressionada, por este
motivo, no corpo do método é usado à cláusula switch para sabermos o que deve ser
feito. As tecla direcionais UP e LEFT chamam o método testaParaCima(), que retorna
um valor booleano, indicando se o usuário está em um índice válido, ou, se por
exemplo, ele está no primeiro índice da tabela e usou UP, neste caso, o foco deve ser
perdido.
Da mesma forma as teclas DOWN e RIGHT chamam o método
testaParaBaixo() retornando um valor true se o índice for válido, ou, se o usuário
estiver no último elemento e pressionar DOWN o item deverá perder o foco. O caso
NONE é se houve alguma atualização automática da área de desenho do CustomItem
pela JVM, o que retornará sempre true.
Por fim, a figura 1 mostra um menu com três sub-menus: adicionar, remover e
editar. Estes Command's são inseridos diretamente ao CustomItem, mais uma
característica presente na MIDP 2.0, pois na sua versão anterior, os Command's só
podiam ser inseridos diretamente a um objeto da classe Form ou Canvas. As ações
respectivas estão nos métodos adicionar() e remover() da classe JMTable.
http://www.javafree.org/
A voz Java no Brasil – Pág. 5
Conclusão
Como visto ao longo do artigo, a classe CustomItem pode ser muito útil para
construção de novos componentes que tenham uma interface mais amigável, e porque
não, construir componentes extremamente úteis que podem ser disponibilizados em
forma de código aberto. Indo um pouco além, pode-se criar componentes para gráficos
semelhantes ao JfreeChart, para relatórios, e assim por diante. O que fica implícito
neste artigo é que, com esta nova ferramenta disponível na MIDP 2.0, a imaginação
dos desenvolvedores pode ser usada para o desenvolvimento de melhores
componentes de GUI, melhorando a qualidade e a abrangência de sistemas J2ME.
Sobre o autor
Ricardo da Silva Ogliari é formando em Ciência da Computação pela
Universidade de Passo Fundo – RS. Desenvolveu sistemas mobile para empresas do
Rio Grande do Sul, atualmente trabalha como desenvolvedor de aplicações
direcionadas a telefones celulares na Kwead.com de São Paulo. Também, foi
palestrante dos eventos JustJava 2005 e EJES (Encontro Java do Espírito Santo)
2005, além de ministrar alguns cursos sobre a tecnologia J2ME.
http://www.javafree.org/
A voz Java no Brasil – Pág. 6
This document was created with Win2PDF available at http://www.win2pdf.com.
The unregistered version of Win2PDF is for evaluation or non-commercial use only.
This page will not be added after purchasing Win2PDF.

Documentos relacionados