javafx_
Conhecendo o funcionamento desta plataforma que
promete estilizar aplicações Desktop, mesmo sem grandes
conhecimentos de CSS.
N
o dia a dia dos desenvolvedores de software,nos deparamos com incógnitas defi nidas pelo cliente fi nal, as quais demandam tempo e recursos para constatar a melhor forma de satisfazêlo. Afi -nal, nem sempre aquilo que imaginamos ser o me-lhor para o sistema, é aquilo que o cliente espera do produto. Apesar de muitas vezes pormos em prática aquele velho conceito de que “devemos nos preocu-par em entregar o sistema rodando, com layout nos preocupamos mais tarde, se for viável”, começamos a repensar sobre este pensamento, que limita o sis-tema e esquece de torná-lo agradável aos olhos dos usuários. Para a entrega fi nal, vemos cada dia mais a importância de um sistema visualmente interes-sante, semelhante a um jogo de videogame no qual os jogadores muitas vezes se animam com o jogo só pelo trailer, antes mesmo de seu lançamento ofi cial. Porém, também sabemos o quão difícil é dar uma aparência agradável a aplicações Desktop com as APis gráfi cas disponíveis. Por este motivo os desen-volvedores preferem desenvolver aplicações Web, pela variedade de frameworks disponíveis, como o Primefaces e RichFaces, por exemplo.
O JavaFX oferece uma solução efi caz para este problema. Com a plataforma JavaFX, pode-se dar di-versos “toques de requinte” para aplicações Desktop, como o uso de CSS para dar estilo aos componentes gerais, e efeitos gráfi cos interessantes, como o Re-fl ection, que dá o efeito de espelho d’água em um componente, dando um visual inimaginável para este fi m, além de Transitions e Timelines, que são efeitos de tempo, como a translação de um painel para um determinado local na tela. Estes diversos
efeitos podem se unir, formando um gráfi co agradá-vel aos olhos dos usuários. Os componentes desta plataforma se diferem dos componentes de aplica-ções Swing, melhorando certos itens, como o JTable, que se mostra complexo para muitos desenvolvedo-res Java, dando lugar para os TableViews e TableCo-lumns, que possuem conceitos semelhantes aos Ob-servers (Observer Pattern), que facilitam na edição dos dados exibidos. Além de outros componentes adicionados, como o Accordion, um painel sanfona-do interessante para quem utilizava diversos JPanels para dar um efeito dinâmico, e também possui uma variedade de componentes Charts (gráfi cos) que so-luciona o problema de muitas aplicações nas quais há necessidade de conjunto de informações numéri-cas. Ao fi nal do artigo, encontram-se referências para exemplos práticos que ensinam o funcionamento de vários códigos que serão mostrados a seguir.
Desenvolvendo uma tela de cadastro
Para começarmos a desenvolver com JavaFX, criaremos uma tela simples, para cadastro de um cliente com alguns campos: nome, idade e sexo. ini-cialmente, não serão constatadas grandes mudanças em relação ao antigo Swing, mas já veremos uma es-trutura diferente.
Criação da tela
Começaremos entendendo que precisamos de uma cena para “acontecer” nossa tela, e a tela pro-priamente dita é o nosso estágio, que seria equiva-lente ao JFrame, no Swing. Faremos uso, também, de
Toques de requinte
para aplicações
Este artigo apresenta a plataforma JavaFX, com foco no
desenvolvi-mento de aplicações Desktop com uso de CSS e efeitos gráfi cos
visu-ais de forma simples. Ao fi nal deste artigo, o leitor aprenderá como
construir formulários e utilizar recursos como Effects, Transitions e
Timelines para tornar a aplicação cada vez mais interessante aos
olhos do cliente fi nal.
Bruno Henrique de Oliveira | bruno.vky@live.com cursando Análise e Desenvolvimento de Sistemas na FATEC São José dos Campos, programa com Java desde 2010, focado em desenvolvimento Android e JavaFX, possui conhecimento em desenvolvimento de jogos em Android com a framework AndEngine.
um AnchorPane, que seria equivalente ao JPanel do Swing, para adicionar os componentes. Os compo-nentes são adicionados ao painel, que é adicionado à cena, que por sua vez é adicionada ao estágio.
Listagem 1.
Criação de uma tela simples.package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
publicclass CadastroApp extends Application {
// Método principal para execução da Application publicstaticvoidmain(String[] args) {
launch(args); }
// Método implementado da Application, para iniciar a tela
@Override
publicvoidstart(Stage stage) throws Exception { AnchorPane pane = newAnchorPane(); pane.setPrefSize(150, 200);
Scene scene = newScene(pane); stage.setScene(scene);
stage.setTitle(“Cadastro de Clientes”); stage.show();
} }
O método main é necessário para executar o nosso formulário. O método launch é estático, da classe Ap-plication, e passa como parâmetro o args que vem do método main, caso haja alguma variável que venha junto da execução da classe. O método start é imple-mentado também da classe Application, e é nele que colocamos a lógica para inicialização do formulário. inicialmente criamos um painel que conterá os com-ponentes da tela, o AnchorPane, e damos sua largu-ra e altulargu-ra com o método setPrefSize(double width, double height), no exemplo, damos 150x200. Então, criamos uma nova Scene, correspondente à tela, passando o componente de visualização principal da tela, no caso o nosso pane. indicaremos o valor da variável stage, que é do tipo Stage, que seria nossa tela propriamente dita, passando para ela qual cena acontecerá com o método setScene(Scene scene). Demos também um título para a tela com o método setTitle(String value), e por fi m abrimos a tela com o método show(), da Stage.
Criando os componentes
Nossa tela terá poucos e básicos itens, como campos de texto e botões. Criaremos um método para inicializar os componentes e adicioná-los à cena.
Listagem 2.
Método para inicialização de compo-nentes.privatevoidinitComponents(AnchorPane pane) { TextField txNome = newTextField();
txNome.setPromptText(“Digite seu nome”); TextField txIdade = newTextField();
txIdade.setPromptText(“Digite sua idade”); txIdade.setLayoutY(30);
RadioButton rbMasc = newRadioButton(“Masculino”); rbMasc.setLayoutY(60);
RadioButton rbFem = newRadioButton(“Feminino”); rbFem.setLayoutY(90);
ToggleGroup groupSexo = newToggleGroup(); groupSexo.getToggles().addAll(rbMasc, rbFem); Button btCadastrar = newButton(“Cadastrar”); btCadastrar.setLayoutY(120);
Button btSair = newButton(“Sair”); btSair.setLayoutY(150);
pane.getChildren().addAll(txNome, txIdade, rbMasc, rbFem, btCadastrar, btSair);
}
Neste método, instanciamos os componentes da tela, que são os seguintes:
» TextField: campos de texto, indicamos para nome e idade;
» RadioButton: botões de opção, indicamos para o sexo (masculino ou feminino);
» ToggleGroup: grupo de opções, indicamos os RadioButtons, para que se possa escolher ape-nas uma opção, para isto usa-se o método get-Toggles().addAll(Toggle... toggles) passando os RadioButtons como parâmetros;
» Button: botões, indicamos para os itens “Ca-dastrar” e “Sair”.
Indicamos a coordenada de cada componente na tela, através do método setLayoutY(double value), que indica a coordenada Y do eixo cartesiano. Pode--se usar setLayoutX(double value) para indicar a co-ordenada X. Adicionamos todos os componentes ao painel principal, usando o método getChildren(), que retorna a lista de componentes deste painel, e adicio-namos itens a esta lista, com o método addAll(Node... nodes), passando todos os itens de uma só vez, pois todos são Node. indicamos também um texto padrão de visualização nos campos de texto, com o método setPromptText(String value), este texto será visuali-zado enquanto seu foco estiver fora do componente, facilitando, por exemplo, para evitar o uso de Labels excessivas. Um código simples que pode ser melho-rado, criando atributos privados para torná-los visí-veis a outros métodos, como um método para iniciar as ações dos botões, por exemplo. Para criarmos sua ação, usamos um código semelhante ao listener do JButton.
btSair.setOnAction(new EventHandler<ActionEvent>() { @Override
publicvoidhandle(ActionEvent arg0) { stage.close();
} });
O método setOnAction(EventHandler han-dler) é o que indica a ação do botão, criamos um novo EventHandler para indicar o evento de ação, este método deve ser implementado, com o método handle(ActionEvent arg0).
Para a função de cadastrar, apenas exibiremos uma caixa de mensagem dizendo que o cliente foi ca-dastrado com sucesso.
btCadastrar.setOnAction(new EventHandler<ActionEvent>() {
@Override
publicvoidhandle(ActionEvent event) { JOptionPane.showMessageDialog(null, “Cliente cadastrado com sucesso!”); }
});
Primeiro toque de requinte - CSS
No JavaFX, podemos fazer uso de CSS para esti-lizar a aplicação. Porém, seus códigos são um pouco diferentes do padrão CSS. Podemos utilizar de dois modos: criando um novo arquivo CSS e indicando seus ids conforme seus componentes, ou também diretamente em código de cada componente, utili-zando o método setStyle(String value), passando em uma String o mesmo estilo CSS que seria utilizado no arquivo.
Modificaremos o fundo do painel principal da nossa tela de cadastro dos dois modos. Primeiro, uti-lizaremos o arquivo CSS, para isto, criaremos ele com o nome cadastro.css.
Listagem 3.
Arquivo CSS para personalização da tela..pane {
-fx-background-color: blue; }
E identificamos este CSS em duas partes em có-digo. Primeiro, indicamos o arquivo utilizado dentro da cena.
scene.getStylesheets().add(CadastroApp.class. getResource(“cadastro.css”).toExternalForm());
E depois identificamos os componentes conforme o iD indicado.
pane.getStyleClass().add(“pane”);
A figura 1 apresenta nossa tela inicial com o uso do estilo CSS indicado.
Mas que tal mudarmos esta cor de fundo para um tom gradiente, com duas cores distintas, por exemplo, um cinza e um azul? isto é completamen-te possível com o JavaFX, utilizando a propriedade linear-gradient. Vamos utilizar no próprio arquivo CSS. Aproveitaremos, também, para modificar a cor
do texto dos RadioButtons para branco, para melhor visualização.
Listagem 4.
Modificação no arquivo CSS..pane { -fx-background-color: linear-gradient(from 0% 0% to 100% 100%, blue 0%, gray 100%); } .rb { -fx-text-fill: white; }
E apenas precisamos indicar nos RadioButtons, o nosso iD deste arquivo.
rbMasc.getStyleClass().add(“rb”); rbFem.getStyleClass().add(“rb”);
Veja o toque de requinte dado à aplicação, depois dessas modificações. O efeito gradiente para painéis faz uma diferença gráfica perceptível para qualquer leigo. A figura 2 mostrará o resultado da modificação de estilo CSS na tela.
A partir daqui, veremos diversos estilos de CSS para produzirmos efeitos visuais para a aplicação.
Podemos também indicar o CSS direto no código. Veremos o exemplo do efeito gradiente:
pane.setStyle(“-fx-background-color: linear-gradient( from 0% 0% to 100% 100%, blue 0%, gray 100%);”);
E dará o mesmo efeito do exemplo com o arquivo CSS.
Segundo toque de requinte – Effects
Com o JavaFX, podemos usufruir de efeitos grá-ficos visuais surpreendentes, como, por exemplo, um espelho d’água em um componente, ou uma sombra no mesmo. São diversas opções de Effects, a própria Oracle disponibiliza exemplos práticos de uso.
Neste artigo, mostraremos dois exemplos, com Reflection e Drop Shadow. Primeiro, usaremos o Re-flection para dar um efeito de reflexão aos dois bo-tões da tela. Seu uso em código é muito simples.
btCadastrar.setEffect(newReflection()); btSair.setEffect(newReflection());
O método setEffect(Effect effect) indica o tipo de efeito utilizado no componente. instanciando um novo Reflection, já vemos seu efeito prático. A figura 3 apresenta este efeito.
Podemos alterar certas propriedades do Reflec-tion, como a opacidade da reflexão. Para isto, bas-ta insbas-tanciar uma variável do tipo Reflection e usar seus métodos para configurá-lo da sua maneira. Este mesmo efeito poderia ser facilmente utilizado nos RadioButtons ou nos TextFields, com o mesmo mé-todo, presente em qualquer componente, pois todos derivam da classe Node, envolvendo o conceito do Composite Pattern.
Agora vamos colocar um efeito de sombra nos dois TextFields. Com o mesmo método setEffect(Effect effect), podemos indicar o Drop Shadow.
DropShadow dropShadow = newDropShadow(); dropShadow.setSpread(0.5);
Usamos o método setSpread(double value) ape-nas para aumentar o espaço de sombreamento do componente. Agora, basta passar o efeito para cada componente.
txNome.setEffect(dropShadow); txIdade.setEffect(dropShadow);
No nosso exemplo, este efeito não será muito perceptível, porém, mudando a cor da tela para o branco, o sombreamento será mais visível. A figura 4 apresenta o efeito DropShadow nos TextFields.
Terceiro toque de requinte – Transitions
e Timelines
O uso de Transitions e Timelines pode ser inte-ressante em aplicações que exigem recursos visuais avançados. Com eles podemos, por exemplo, mudar um componente de lugar, como em um efeito de translação, e também utilizar um efeito alpha, que tira a visibilidade aos poucos de um componente e o torna visível, em seguida.
Primeiro, mostraremos o uso de Transitions, en-tre os vários tipos, usaremos a classe FadeTransition, manipulando um efeito Fade in/Fade Out.
Listagem 5.
FadeTransition no botão btCadastrar.// Ação no botão, ao passar ao mouse sobre o componente btCadastrar.setOnMouseEntered(new
EventHandler<MouseEvent>() { @Override
publicvoidhandle(MouseEvent event) {
FadeTransition transition = newFadeTransition( Duration.millis(2000), btCadastrar);
transition.setFromValue(0.0); transition.setToValue(1.0); transition.play();
} });
Com o método setOnMouseEntered (EventHand-ler hand(EventHand-ler), indicamos uma ação ao passar o mouse sobre o componente. Em sua implementação, criamos um novo FadeTransition(Duration duration, Node node), passando a duração da transição, utilizando a classe Duration do JavaFX, no nosso exemplo, passa-mos 2000 milissegundos, ou seja, 2 segundos de tran-sição, e também passamos qual o Node que acontece-rá o efeito. Os métodos setFromValue(double value) e setToValue(double value) indicam a variação do Fade, começando em 0.0 e terminando em 1.0, res-pectivamente, em seus métodos. E, por fim, executa-mos a transição com o método play().
Há diversos tipos de Transitions, como já comen-tado, inclusive pode-se utilizar vários Transitions em sequência ou paralelamente.
Mostraremos agora o uso de Timelines para
ver um componente de um ponto ao outro, daremos este efeito para o botão “sair”.
Listagem 6.
Timeline no botão btSair.//Listagem 6. Timeline no botão btSair. btSair.setOnMouseEntered(new
EventHandler<MouseEvent>() { @Override
publicvoidhandle(MouseEvent arg0) { Timeline timeline = newTimeline(); KeyValue kv = newKeyvalue(btSair.
layoutxProperty(), btSair.getLayoutx() + 20); KeyFrame kf = newKeyFrame(
Duration.millis(2000), kv); timeline.getKeyFrames().add(kf); timeline.play();
} });
Criamos uma nova Timeline, que será responsável pelo efeito. A criação da KeyValue indica qual a tran-sição de valores ocorrerá, no nosso caso, a coordenada X do btSair será incrementada em 20. A KeyFrame in-dica o tempo de execução do efeito, necessita passar em sua construção qual a duração (Duration) e qual a KeyValue, pode-se passar diversas KeyValues ao mes-mo tempo. Adicionames-mos a KeyFrame para a Timeline, com o método getKeyFrames().add(KeyFrame kf), e, por fim, executamos, com o método play().
Ao passar o mouse sobre o botão, veremos o mes-mo mes-movendo-se para o lado direito. Este efeito já se mostra bastante avançado. Podemos também au-mentar a largura e altura de um componente, voltan-do ao normal quanvoltan-do tira o mouse dele.
Listagem 7.
Efeito Scale no botão btSair.btSair.setOnMouseEntered(new
EventHandler<MouseEvent>() { @Override
publicvoidhandle(MouseEvent arg0) { Timeline timeline = newTimeline();
KeyValue kv = newKeyvalue(btSair.scalexProperty(), 1.2);
KeyValue kv2 = newKeyvalue( btSair.scaleYProperty(), 1.2);
KeyFrame kf = newKeyFrame(Duration.millis(1000), kv, kv2);
timeline.getKeyFrames().add(kf); timeline.play();
} });
btSair.setOnMouseExited(new EventHandler <MouseEvent>() {
@Override
publicvoidhandle(MouseEvent arg0) { Timeline timeline = newTimeline();
KeyValue kv = newKeyvalue(btSair.scalexProperty(), 1.0);
KeyValue kv2 = newKeyvalue( btSair.scaleYProperty(), 1.0);
KeyFrame kf = newKeyFrame(Duration.millis(1000), kv, kv2);
timeline.getKeyFrames().add(kf); timeline.play();
} });
A novidade aqui é a indicação de duas KeyValues ao mesmo tempo, para aumentar a escala do botão em coordenada X e Y. Na construção da KeyFra-me, indicamos todas as KeyValues necessárias, logo após a duração. Utilizamos também o método setOnMouseExited(EventHandler handler) para indi-car uma ação ao tirar o mouse do componente, ele irá fazer o botão voltar ao normal, conforme outra Time-line criada.
Considerações finais
Vimos um pouco do que o JavaFX oferece para os desenvolvedores Java. Seus efeitos gráficos visu-ais mostram-se incríveis para aplicações Desktop, dando-nos poder para pensar em um layout adequa-do e belo, mesmo sem conhecer efeitos avançaadequa-dos de CSS e JavaScript, por exemplo. Com esta plataforma, torna-se simples programar extensos formulários e dimensioná-los na tela de forma limpa. Pode-se tor-nar ainda mais organizado utilizando o programa da Oracle, o JavaFX Scene Builder, que é um ambiente para desenvolver layouts do JavaFX com um sistema drag-and-drop. Ele gera um arquivo FXML, que é fa-cilmente identificado em código.
> JavaFX 2.0: Introduction by Example, de Carl Dea, ed. Apress. – Livro para introduzir JavaFX, com códigos práticos e ensino fácil, porém em inglês.
> http://docs.oracle.com/javafx/2/visual_effects/jfxpub-visual_effects.htm – Documentação sobre Effects > http://docs.oracle.com/javafx/2/animations/jfxpub-animations.htm – Documentação sobre Transitions e Timelines
> http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/ cssref.html – Documentação sobre CSS JavaFX