Swing Application Framework (JSR-296) - Parte 2
Este blog deixou de ser mantido, mas o autor continua escrevendo aqui. Não deixe de assinar o novo feed!
Na primeira parte desse artigo, foram apresentadas as motivações e os objetivos para criação e uso da JSR-296, o gerenciamento de ciclo de vida e inicialização de aplicativos, o armazenamento do estado da GUI entre sessões e persistência local com o Swing Application Framework. Nessa continuação, será apresentada a injeção de recursos e a definição, gerenciamento e binding de Action’s.
Injeção de Recursos
A classe application.ResourceMap, segundo sua documentação, pode ser utilizada para “injetar” recursos nas propriedades dos componentes Swing e em campos de objetos. O método injectComponents [dessa classe] usa a propriedade name de java.awt.Component para relacionar o nome de recursos com propriedades. O método injectFields [de ResourceMap] "injeta" valores dos recursos nos campos anotados com @Resource.
Ou seja, é através da propriedade name que é feito o binding entre uma certa propriedade do objeto e o recurso a ser injetado nessa propriedade. Os recursos são definidos em arquivos de propriedades. ResourceMap é acessada através do método getResourceMap de ApplicationContext.
Por exemplo, no método startup abaixo há injeção de uma string (o recurso) na propriedade title de JFrame.
-
-
protected void startup() {
-
final ApplicationContext ac = ApplicationContext.getInstance();
-
-
final ResourceMap resourceMap = ac.getResourceMap(getClass());
-
resourceMap.injectComponents(mainFrame);
-
}
-
O método startup faz parte da subclasse concreta de Application, denominada OhMyApplication (veja a parte 1 desse artigo), presente no pacote gui. Nesse exemplo, o método injectComponents injeta recursos definidos no arquivo de propriedades OhMyApplication.properties, presente no pacote gui.resources:
-
-
Application.name = OhMy
-
Application.id = OhMy-2.0
-
Application.title = OhMy-2.0
-
Application.version = 2.0
-
Application.vendor = Rafael Fiume
-
Application.vendorId = RFiume
-
Application.homepage = http://rfiume.blogspot.com/
-
Application.description = Pequeno sistema de informação gerencial.
-
Application.lookAndFeel = com.jgoodies.looks.plastic.PlasticXPLookAndFeel
-
-
# Essa expressão será injetada na propriedade title de JFrame
-
mainFrame.title = ${Application.name}-${Application.version}
-
mainFrame é o valor da propriedade name (i.e. obtido através de getName) do objeto mainFrame, e title é o nome da propriedade de JFrame na qual queremos injetar o recurso - nesse caso, uma string com o título da janela.
Injeção de Recursos com Fuse
Com a injeção de recursos do Swing Application Framework é possível injetar cores (java.awt.Color), fontes (java.awt.Font), ícones (javax.swing.ImageIcon), imagens (java.awt.Image), atalhos do teclado (javax.swing.KeyStroke), strings (java.lang.String), mensagens formatadas (java.text.MessageFormat), além dos tipos primitivos da linguagem Java e seus respectivos wrappers boolean, byte, short, int, long, float e double em propriedades e campos de componentes Swing.
Se precisar de injeção de recursos para outros tipos de dados, além dos citados acima, e para componentes SWT, utilize o projeto Fuse.
Observação: injeção de recursos é uma forma de IoC, assim como o é a injeção de dependência.
@Actions
Actions, em Swing, definem o comportamento do software sob o ponto de vista de seus usuários, implementando o padrão Command (GoF). São implementados a partir da interface javax.swing.Action ou da classe abstrata javax.swing.AbstractAction (mais sobre Actions em How to Use Actions e Using the Swing Action Architecture).
Com o Swing Application Framework, é possível implementar javax.swing.Action ao anotar um método com @Action. O framework irá utilizar esse método anotado para definir o método actionPerformed de javax.swing.Action e inicializar as propriedades dessa classe, criando uma instância de application.ApplicationAction.
Métodos anotados com @Action devem ter nenhum ou java.awt.event.ActionEvent como parâmetro; devem retornar void ou application.Task. No último caso, Task é executado pelo método actionPerformed de ApplicationAction.
A classe VProduto_Form aplica a teoria mencionada acima. Trata-se de um painel para cadastrar e visualizar os dados de uma entidade - o produto. Os métodos create e update, ao invés de serem definidos separadamente em uma subclasse de javax.swing.Action para cada método (e.g. CreateAction e UpdateAction), são escritos em VProduto_Form.
-
-
private DefaultEntityModel<produto> entityModel;
-
// Demais campos e propriedades
-
-
/** Necessário para construtores de interfaces gráfica, como o NetBeans Matisse. */
-
public VProduto_Form() {
-
super();
-
initComponents();
-
}
-
-
-
public VProduto_Form(DefaultEntityModel<Produto> entityModel) {
-
this();
-
this.entityModel = entityModel;
-
}
-
-
-
if (entityModel == null) {
-
}
-
entityModel.addEntity(getEntity());
-
clear();
-
}
-
-
-
if (entityModel == null) {
-
}
-
entityModel.updateEntity(updateSelectedEntity(produtoSelecionado));
-
clear();<
-
}
-
. . .
-
}
-

Injeção de Recursos e @Actions
javax.swing.Action’s geralmente são utilizados para criar botões em barras de ferramenta, menus e outros componentes gráficos. Portanto, para serem úteis, precisam definir algumas propriedades, como ícones e descrições, além do método actionPerformed.
Recursos especificados num ResourceBundle de mesmo nome da classe action são injetados nas propriedades de ApplicationAction. As propriedades de ApplicationAction cujos valores podem ser injetados a partir de um arquivo de propriedade são:
-
-
Action.iconAction.text
-
Action.shortDescription
-
Action.longDescription
-
Action.smallIcon
-
Action.largeIcon
-
Action.command
-
Action.accelerator
-
Action.mnemonic
-
Action.displayedMnemonicIndex
-
Continuando o exemplo acima, para injetar recursos nas propriedades dos ApplicationAction’s gerados pelo framework a partir dos métodos create e update de VProduto_Form, supondo que essa classe esteja no pacote gui.cadastro, cria-se um arquivo de propriedades gui.cadastro.resources.VProduto_Form.properties. Eis o conteúdo do arquivo:
-
-
create.Action.icon = save22.png
-
create.Action.mnemonic = C
-
create.Action.shortDescription = Cadastra entidade no banco de dados (Alt + C)
-
update.Action.icon = edit22.png
-
update.Action.mnemonic = U
-
update.Action.shortDescription = Atualiza entidade no banco de dados (Alt + U)
-
Os ícones save22.png e edit22.png também estão no pacote gui.cadastro.resources. Repare que o nome do método é utilizado para o binding dos recursos definidos nos arquivos de propriedades com as propriedades dos ApplicationAction’s.
E Finalmente. . .
A classe VProduto contém VProduto_Form e outros componentes gráficos, como a barra de ferramenta cujo dois dos botões serão implementados com o auxílio dos ApplicationAction’s criados pelo framework a partir dos métodos create e update de VProduto_Form.
-
-
public final class VProduto extends JXTitledPanel implements . . . {
-
private iboi.gui.cadastro.VCategoriaCliente_Form form;
-
// Demais campos e propriedades
-
-
private void initComponents() {
-
-
bCreate.setAction(getAction(VProduto_Form.class, form, "create"));
-
toolBar.add(bCreate);
-
bUpdate.setAction(getAction(VProduto_Form.class, form, "update"));
-
toolBar.add(bUpdate);
-
}
-
-
-
/* Método utilitário para obter Actions. */
-
return ApplicationContext.
-
getInstance().
-
getActionMap(actionsClass, actionsObject).
-
get(actionName);
-
}
-
. . .
-
}
-
application.ApplicationActionMap, subclasse de javax.swing.ActionMap, contém chaves e valores correspondentes aos métodos anotados com @Action em uma classe action. A chave é o valor da propriedade name de @Action (por padrão, o nome do método), e o valor é o ApplicationAction que invoca o método anotado com @Action.
O método auxiliar getAction de VProduto é utilizado para obter o Action adequado. Basta fornecer os argumentos necessários: actionsClass é a classe action; actionsObject é uma instância dessa classe; e actionName o valor da propriedade name de @Action.
Os dois primeiros argumentos são necessários para acessar o ApplicationActionMap correto; o terceiro, para obter o Action requerido. Esse exemplo é interessante porque mostra que é possível definir um @Action numa classe e utilizá-lo em outras, algo que não está óbvio em outros tutoriais.
-
-
bCreate.setAction(getAction(VProduto_Form.class, form, "create"));
-

Cenas dos Próximos Capítulos
A terceira parte desse artigo mostrará funcionalidades adicionas ao utilizar @Action’s e tarefas executadas em background.
Veja Também:
Fontes e Referências Utilizadas:
- Swing Application Framework Home Page
- JSR 296: Swing Application Framework
- Javadoc e código fonte do Swing Application Framework
- An Introduction to Swing Application Framework API (JSR-296)


14 de junho de 2007 às 8:19 am
Ae!
Pra quem não prestou atenção, os créditos deste post são do Rafael Fiume! Aliás, muito bom este post. Vale lembrar também que, quem se interessar por esse assunto, poderá ver mais a respeito no blog dele.
Abraços!
4 de setembro de 2007 às 11:25 am
Dai blz?
seguinte, estou tendo problemas com o Swing Application Framework no netbeans, tento extender uma classe da application.Task, mas o netbeans acusa uma exception
“Cannot find symbol
symbol: Task()
location: class application.task”
com outras classes tambem com FrameView, mesmo erro,
será que vc pode me ajudar?
por falta de tutoriais, e documentações fica dificil resolver esse problema
agradeço desde ja
8 de setembro de 2007 às 1:30 am
Walter, esses problemas são referentes às mudanças que a API do Swing Application Framework sofreu a partir da versão 0.50. O artigo se baseou numa versão mais antiga desse framework que, como é um “trabalho em andamento”, pode sofrer alterações de uma hora para outra.
Estou esperando a API estabilizar para fazer ajustes no artigo. Mas não se preocupe porque as mudanças não foram radicais. No seu caso, a classe
Tasknão tem mais o construtor padrão.Sugiro que você baixe o código fonte do Swing Application Framework, que inclusive vem com diversos exemplos, para aprender a lidar com sua API (coisa que esse tutorial sozinho não é capaz de fazer).
Espero ter ajudado.
14 de fevereiro de 2008 às 3:02 pm
Muito legal esse artigo, só tem uma coisa que ainda não vi como exemplo no Application Framework, é como *carregar* JInternalFrames *dentro* da aplicação assim como faço no JDesktopPane.
Como se faz isso?
Tenho uma aplicação que tou migrando para o SAF e preciso saber como se faz isso.
Obrigado
19 de setembro de 2008 às 2:00 pm
Oi Daniel, muito bom o artigo, parabéns.
Gostaria de saber o seguinte:
É possivel adotar um Model View Presentation utilizando Swing Application Framework?
20 de setembro de 2008 às 11:29 am
Na verdade, os créditos vão para o Rafael Fiume… foi ele quem escreveu este post! Infelizmente eu não sei responder sua pergunta.
Dê uma olhada no blog dele e faça a pergunta diretamente para ele:
http://rfiume.blogspot.com/