Mostrando postagens com marcador api. Mostrar todas as postagens
Mostrando postagens com marcador api. Mostrar todas as postagens

14 de ago. de 2014

Introdução a gráficos com JavaFX

Os desenvolvedores de aplicações desktop e applets que vieram antes do JavaFX tinham muito trabalho criando gráficos.
JavaFX felizmente tem uma API pronta para criação de gráficos de diversos tipos. Nesse breve artigo vamos, através de exemplos, mostrar os gráficos mais simples do JavaFX.

A API de gráficos


As classes da API de gráficos do JavaFX ficam no pacote javafx.scene.chart. Para cada tipo de gráfico há uma classe (por exemplo, PieChart) e um tipo de objeto a ser populado com dados para serem exibidos nesse gráfico (como PieChart.Data).  Lembrando que, assim como todo componente em uma aplicação JavaFX, gráfico herda de nó.
Os principais gráficos são mostrados na imagem abaixo retirada do tutorial da Oracle.

O gráfico de Pizza

Esse é com certeza o gráfico mais fácil de usar :) Como dito, cada gráfico tem o seu tipo de dados. Os tipos de dados do gráfico de pizza é o PieChart.Data  e esse tipo de dado contém uma String, que é o nome do dado, e um valor double, que é o valor desse dados.
Os valores são somados e dividos pela quantidade de dados, assim descobrimos qual a fatia de cado um.
Veja como é fácil criar um gráfico com dados fictícios de uma empresa com os ganhos de cada trimestre do anos:

PieChart graficoPizza = new PieChart();
graficoPizza.getData().addAll(new PieChart.Data("Trimestre 1", 11),
  new PieChart.Data("Trimestre 2", 1),
  new PieChart.Data("Trimestre 3", 34),
  new PieChart.Data("Trimestre 5", 12));
graficoPizza.setTitle("Lucros por Trimestre");
graficoPizza.setPrefSize(GRAFICO_LARGURA, GRAFICO_ALTURA);

Viu! O que temos acima é:

  • PieChart: Um nó que representa o gráfico a ser desenhado;
  • PieChart.Data: os dados do gráfico;
Por fim podemos adicionar o gráfico a uma cena e teremos o seguinte resultado:


O gráfico de linha


O gráfico de linha é representado pela classe LineChart e não é dificil de ser usado também, no entanto, os dados já não são tão simples de criar. Ele é um subtipo de gráfico com plano cartesiano X e Y, ou seja, XYChart e o tipo de dados para esse gráfico são o XYChart.Series. Mas o que vem a ser esse tipo de dados?
Esse tipo de dado consiste principalmente de valores para X, valores para Y de um dado grupo de dados. Um exemplo seria comparar o lucro de cada produto de uma empresa ao longo do ano.
O gráfico de linha, no entanto, também exige a definição dos eixos X e Y através da classe Axis.
Bem, vejamos um exemplo de comparação de lucros por trimestre da empresa separado por produtos:

LineChart graficoLinha = new LineChart<>(
  new CategoryAxis(), new NumberAxis());
final String T1 = "T1";
final String T2 = "T2";
final String T3 = "T3";
final String T4 = "T4";

XYChart.Series prod1 = new XYChart.Series();
prod1.setName("Produto 1");

prod1.getData().add(new XYChart.Data(T1, 5));
prod1.getData().add(new XYChart.Data(T2, -2));
prod1.getData().add(new XYChart.Data(T3, 3));
prod1.getData().add(new XYChart.Data(T4, 15));

XYChart.Series prod2 = new XYChart.Series();
prod2.setName("Produto 2");

prod2.getData().add(new XYChart.Data(T1, -5));
prod2.getData().add(new XYChart.Data(T2, -1));
prod2.getData().add(new XYChart.Data(T3, 12));
prod2.getData().add(new XYChart.Data(T4, 8));

XYChart.Series prod3 = new XYChart.Series();
prod3.setName("Produto 3");

prod3.getData().add(new XYChart.Data(T1, 12));
prod3.getData().add(new XYChart.Data(T2, 15));
prod3.getData().add(new XYChart.Data(T3, 12));
prod3.getData().add(new XYChart.Data(T4, 20));
graficoLinha.getData().addAll(prod1, prod2, prod3);
graficoLinha.setPrefSize(GRAFICO_LARGURA, GRAFICO_ALTURA);

Isso geraria:



Notem que o código consiste de agrupamento de dados em tipo de categoria. No nosso caso agrupamos os dados do Produto 1 e a categoria foi determinada pelo trimestre.

O gráfico de Barras

Muito similar ao gráfico de linha, temos o gráfico de barras. Esse gráfico usa o mesmo tipo de dados, mas representa de forma: através de barras. Veja como o exemplo anterior, de linhas, usando o mesmo conjunto de dados, mas em um gráfico de barras:

BarChart graficoBarra = new BarChart<>(
  new CategoryAxis(), new NumberAxis());
// igualzinho ao feito para o gráfico de linha...
graficoBarra.getData().addAll(prod1, prod2, prod3);
graficoBarra.setPrefSize(GRAFICO_LARGURA, GRAFICO_ALTURA);



Conclusão

Introduzimos os gráficos do JavaFX! Bem, a API é extensa, voltaremos ao assunto em breve falando de outros gráficos. Até lá! Por enquanto, veja os gráficos na documentação oficial do JavaFX.

Código no Github.

11 de ago. de 2014

API do JavaFX: Properties, Listeners e Bindings

Uma das características mais interessantes do JavaFX também está na API não gráfica, onde podemos facilitar com que elementos de interface respondam a variações em classes Java, usualmente classes que representam um negócio. Hoje vamos falar das classes de Properties do JavaFX e dar pequenos exemplos para entendimento das mesmas.

Como fazer com que a mudança de dados reflita na aplicação?

Imagine que sua aplicação você tem um campo de entrada texto, um TextField, e em seguida um texto, um Label, para mostrar o que tem nesse campo, em tempo real, como você faria?
  
Bem, a forma mais usual é adicionar um key handler ao campo de texto e quando esse for acionado, configurar o texto do Label. Veja o código:

TextField txtNome = new TextField();
Label lblNome = new Label();
txtNome.setOnKeyReleased(e -> {
 lblNome.setText(txtNome.getText());
});
lblNome.setFont(Font.font("Verdana", FontWeight.BOLD, 30));


Esse cenário, no entanto, pode ser muito mais complexo e levar você a ter que espalhar listeners na aplicação para fazer com que duas propriedades reflitam uma a outra e, o pior de tudo, o código pode não ficar tão legível e de difícil manutenção.

Properties


Felizmente o JavaFX tem uma API de properties, onde foram criadas diversas classes que adicionam "superpoderes" aos tipos mais comuns do java e que podem ser extensíveis para usarmos com nosso objetos da aplicação.
O melhor ainda é que toda a API do JavaFX está preparada para isso. Todos os campos de um elemento do JavaFX, como o Node, têm um equivalente com property. Por exemplo, um campo de texto tem um textProperty para o valor de texto do mesmo.

Binding

Um super poder muito notável das properties é o binding. Realizar binding significa fazer com que uma propriedade tenha seu valor modificado em função da outra. Exemplificando, se temos o texto A e queremos que o texto B seja o mesmo que o A, mas mais ainda, que B atualize quando B atualizar, dizemos que B está amarrado à A (bound). Quando isso acontece, B não pode ser modificado diretamente ou teremos um erro. Se quiser mudar B, teremos que mudar A. Isso em código fica como mostrado a seguir (reescrevendo nosso exemplo anterior):

TextField txtNome = new TextField();
Label lblNome = new Label();
lblNome.textProperty().bind(txtNome.textProperty());  
lblNome.setFont(Font.font("Verdana", FontWeight.BOLD, 30)); 

Simples, não? Aqui pode não parecer tão intessante, mas imagine que estamos em uma aplicação que traz objetos do banco de dados e queremos refletir os dados desses objetos na view em tempo real. Não seria essa uma boa alternativa? Adicionalmente podemos realizar um binding bidirecional, onde se au altero A, B também será alterado, e se eu altero B, A também terá o conteúdo de B!

Note que por enquanto falamos somente de texto, mas isso é possível com valores boleanos, inteiros e do tipo double:

StringProperty: Para textos (textProperty no TextField ou no Label)
BooleanProperty: Valores booleanos( visibleProperty, disableProperty no Node)
DoubleProperty: Valores double (value no Slider)
IntegerProperty: Valores inteiros (int)
ObjectProperty: Objetos no geral.


Cada uma das properties acima tem um equivalente para ser instanciado caso você queria usar as properties em sua aplicação, por exemplo: SimpleStringProperty, SimpleBooleanProperty, etc..
Agora, para introduzir a API, vamos mostrar brevemente tudo isso. Futuramente voltamos a aprofundar nesse tópico.

Binding com expressões

Imagine agora que você queira não só amarrar um texto, mas amarrar um texto com outro e ainda um texto fixo no meio, como fazer? Ou, se estiver usando números, quer que um valor seja sempre o resultado da soma desses dois números. Isso é muitp fácil e é possível através das expressões das properties.
Por exemplo, para  String, temos a expressão concat,  onde passamos passar outra String literal ou outra String property e cancat irá retornar uma StringProperty que é atualizada com o resultado daquela concatenação, veja um simples exemplo:





TextField txtNome = new TextField();
TextField txtSaudacao = new TextField();
Label lblNome = new Label();
lblNome.textProperty().bind(
  txtNome.textProperty().concat(", ")
  .concat(txtSaudacao.textProperty()
));



Claro que nem sempre queremos que o resultado dessa expressão seja outro texto, logo, temos também expressões da String que retornam uma propriedade de outro tipo. Por exemplo, a expressão greaterThanOrEqualTo irá retornar uma BooleanProperty de comparação de duas StringProperty. Um outro exemplo é gerar um resultando de soma de duas DoubleProperty e uma String que contenha a representação em texto, veja:







Slider sld1 = new Slider(0, 100, 50);
Slider sld2 = new Slider(0, 100, 50);
Label lblResultado = new Label();
lblResultado.textProperty().bind(
  sld1.valueProperty()
  .add(sld2.valueProperty())
  .asString()
);



Bem, paramos por aqui, mas a javadoc é sua amiga. Leia por lá e navegue na API que em breve você está mestre nisso!

Observando mudanças


Lembra do padrão observer? Um super poder das properties é também deixar que você observe ela. Assim, quando ela muda temos um pedaço de código notificado. Esse código notificado irá receber três parâmetros: o valor observável que sofreu a mudança, o valor que era antes, o novo valor. Simples, não? Com Java 8 é ainda mais simples pois podemos usar Lambdas para definir os ChangeListeners. Veja o seguinte exemplo que observamos as mudanças de um combo box:



String valores[] = { "Garrafa", "Copo", "Monitor", "Notebook",
  "Celular" };
// na próxima falamos de FXCollections
ComboBox cmbValores = new ComboBox(
  FXCollections.observableArrayList(valores));
Label lblAntigo = new Label();
Label lblNovo = new Label();
cmbValores.valueProperty().addListener((obs, velho, novo) -> {
 lblAntigo.setText("Valor Antigo: " + velho);
 lblNovo.setText("Valor Novo: " + novo);
});


Conclusão

Ah, chegamos ao fim... Essa API é muito abrangente e divertida, por isso iremos voltar ao tópico no futuro. Veja o código da nossa aplicação de teste no github e a carinha dela final:


13 de out. de 2013

A classe Node e seus principais atributos

Desde o começo desse blog nós falamos sobre a classe Node (nó). Ela é a classe pai(mãe?) de tudo que está em uma aplicação JavaFX: textos, formas geométricas, botões, tabelas, gerenciadores de leiautes que contém outros nós, etc... Nesse artigo, vamos dar um "rolê" na documentação do nó e tentar deixar claro por que a API do JavaFX, a tal do scene graph, é muito poderosa e facilita qualquer um começar a criar aplicações atrativas visualmente sem gastar muito tempo com aprendizagem.

A classe Node e seus principais atributos

Essa classe é grandinha: A documentação dela jé de assustar, mas imagine só que o código dela tem 8760 linhas! Portanto, não vamos cobrir todos os seus aspectos, mas vamos dividir essa parte em subseções: Transformações, atributos, eventos.
Nó, conforme repetido inúmeras vezes, é a classe pai de todos os componentes que estão em uma aplicação JavaFX. Com o nó você consegue navegar entre os objetos e tratar os mesmos sem se importar qual é a implementação(você consegue modificar algumas propriedades sem se preocupar se o nó em sí é um botão, forma geométrica, etc). O nó é também responsável pela arquitetura do JavaFX, o tal do Scene Graph:

Veja o que selecionamos para discutirmos sobre essa classe:

Transformações

É possível transformar um nó: Rotacionar, escalar(mudar o tamanho) e mudar sua posição. No post anterior acabamos por mostrar como é possível criar animações usando esses atributos e as classes de transições. Vejam os principais atributos de transformação de um nó:
  • Rotação: Permite rotacionar o nó usando o método setRotate(double). Lembre-se que a rotação é sempre de 0 a 360;
  • Escalar: Escalar um nó significa aumentar proporcionalmente o tamanho do mesmo. Podemos escalar a altura e largura. Exemplo: se escalamos o nó em 2 na largura X, quer dizer que a largura do mesmo será X*2. Os métodos para alterar a escala de largura e altura são, respectivamente, setScaleX(double) e setScaleY(double);
  • Trocar posição: Há dois atributos que determinam a posição do componente na tela: X e Y, onde X é a posição horizontal e Y é a posição vertical. Para mudar a posição vertical e horizontal de um componente, usamos, respectivamente, os métodos setTranslateY(double) e setTranslateX(double).

Atributos 

Alguns atributos são muito úteis e já estão presentes no nó. Eu escolhi alguns para abordar aqui. É óbvio que temos muitos outros, mas vamos deixar pra mais tarde. Se você estiver ansioso, fique a vontade para explorar a documentação da classe.
  • Effect: Um efeito a ser aplicado a esse nó. Ah, não vamos falar muitos de efeitos nessa postagem! Vamos deixar um biscoito, os efeitos estão todos no pacote javafx.scene.effect e vamos abordar com mais detalhes no futuro;
  • id: É um identificado único que podemos dar a esse nó. Podemos configurar o valor usando o método setId(String);
  • Disabled: Indica se um nó está desabilitado. Caso um nó esteja desabilitado, ele será visível, mas não receberá eventos (ver a seção Eventos nesse mesmo artigo) e sua aparência será de desabilitado, ou seja, você não poderia interagir com o nó. Para desabilitar um nó use: setDisabled(boolean).
  • Visible:  Indica se um nó será visível. Caso false, o nó não será visível e não receberá eventos. Configuramos o valor de visible com o método setVisible(boolean).
  • Focused: Informa se o nó tem o foco. Caso tenha o foco, ele poderá receber eventos de teclado. Você pode saber se um nó está focado através do método isFocused(). E para trazer o foco para um nó, você deverá usar o método requestFocus(). Note que o foco poderá vir naturalmente quando navegando na aplicação;
Eventos
Nós suportam todos os eventos possíveis, sejam eles vindo de teclados, toque, ou mouse. Se você quer entender sobre tratamento de eventos, por favor, veja esse artigo. Hoje iremos tratar de diversos outros eventos, mas seremos breves, pois a teoria básica está no artigo mencionado.
  • Eventos do Mouse: O nó contém diversos métodos setOnMouse*, onde * é uma ação relacionada ao mouse, que pode ser: Clicked, Moved, Exited, Released, entre outras. Em outras palavras, quando configuramos um EventHandler usando o método setOnMouseClicked, estamos informando uma ação que queremos que seja executada quando o usuário clica sobre o nó. Note que o tipo de evento depende do evento que foi feito, no caso do Mouse temos os dois principais eventos: MouseEvent e MouseDragEvent;
  • Eventos do Teclado: Similar aos eventos gerados por mouse, temos os eventos gerados pelo teclado. O evento gerado é o KeyEvent e configuração nosso listener usando os métodos setOnKey*;
  • Eventos gerados por gestos: Algo que recentemente tem se tornado imprescindível nos frameworks gráficos é o uso de eventos gerados pelo toque. Muitos dispositivos hoje contém uma touch screen que permitem que, com os dedos, geramos diversos eventos novos. Vejam a imagem abaixo com os principais eventos:
O JavaFX possuí suporte a esses eventos de touch, zoom, scroll, rotate e swipe. Há os métodos setOn* para cada um dos eventos que podemos gerar com os dedos, mas como precisaríamos de um dispositvo que tenha suporte a esses eventos, não vamos abordar eles nessa postagem.

Notem que todas essas propriedades são do tipo Property, ou seja, podemos realizar binding e adicionar listeners para elas. Mas, esse é um assunto para uma postagem futura :)

O nó na prática

No próximo artigo vamos discutir uma pequena aplicação que mostra como acessar os atributos do nó aqui mostrados. Para evitar estender demais a postagem, iremos fazer isso em um artigo dedicado.

Conclusão

A classe node do JavaFX é muito poderosa e facilita a manipulação de qualquer elemento da aplicação de forma fácil e unificada. Aprender essa classe é um passo importante no aprendizado eficaz da nova API gráfica da plataforma Java.

18 de set. de 2013

Criando animações usando as transições do JavaFX 2 - Prática

Seguindo o artigo anterior, hoje vamos mostrar as transições na prática, mostrar um pouco de código!
Para demonstrar a ideia básica dessa API, criei uma aplicação e fiz um vídeo, vejam abaixo:



Código

Para criar as transições, usamos uma classe chamada FabricaTransicao  Nessa classe há um método chamado fazerTransicao que, dado um enum, duração e um nó, sempre cria uma nova transição:

public static class FabricaTransicao {

 public static enum Transicoes {
  FADE, TRANSLATE, SCALE, FILL, ROTATE
 }

 public static Transition fazerTransicao(Transicoes transicao,
   double duracaoSegundos, Node alvo) {
  Duration duracao = new Duration(duracaoSegundos * 1000);
  Transition t = null;

  switch (transicao) {
  case FADE:
   FadeTransition fadeTransition = new FadeTransition();
   fadeTransition.setFromValue(1);
   fadeTransition.setToValue(0);
   fadeTransition.setDuration(duracao);
   fadeTransition.setNode(alvo);
   t = fadeTransition;
   break;
  case FILL:
   FillTransition fillTransition = new FillTransition();
   fillTransition.setFromValue(Color.RED);
   fillTransition.setToValue(Color.DARKGREEN);
   fillTransition.setDuration(duracao);
   fillTransition.setShape((Shape) alvo);
   t = fillTransition;
   break;
  case ROTATE:
   RotateTransition rotateTransition = new RotateTransition();
   rotateTransition.setByAngle(360);
   rotateTransition.setDuration(duracao);
   rotateTransition.setNode(alvo);
   t = rotateTransition;
   break;
  case SCALE:
   ScaleTransition scaleTransition = new ScaleTransition();
   scaleTransition.setFromX(1);
   scaleTransition.setFromY(1);
   scaleTransition.setToX(4);
   scaleTransition.setToY(4);
   scaleTransition.setDuration(duracao);
   scaleTransition.setNode(alvo);
   t = scaleTransition;
   break;
  case TRANSLATE:
   TranslateTransition translateTransition = new TranslateTransition();
   translateTransition.setToX(600);
   translateTransition.setToY(250);
   translateTransition.setDuration(duracao);
   translateTransition.setNode(alvo);
   t = translateTransition;
   break;
  }
  t.setAutoReverse(true);
  t.setCycleCount(2);
  return t;
 }
}


Isso obviamente não é "bonito", mas esse código não utiliza as melhores práticas de codificação, ele é somente para demonstrar as transições. As 5 transições aí criadas mostram como usamos os métodos mais básicos da transição. Primeiramente criamos temos um atributo que é do tipo Transition, ou seja, uma classe abstrata, então de acordo com o valor do enum criamos uma transição concreta e atribuimos à transição abstrata.
Note a repetição de uso dos métodos setNode e setDuration. Esses métodos estão em quase todas as transições, mas não em todos, por isso eles não puderam ser definidos na classe abstrata. já nas seguintes duas linhas em destaque, temos dois métodos que são da classe abstrata, logo não precisamos repetir a chamada do mesmo para cada transição criada.

  public static Transition fazerTransicao(Transicoes transicao,
  

   switch (transicao) {
   case FADE:
    // ...
    fadeTransition.setDuration(duracao);
    fadeTransition.setNode(alvo);
    t = fadeTransition;
    break;
   case FILL:
    //...
    fillTransition.setDuration(duracao);
    fillTransition.setShape(alvo);
    t = fillTransition;
    break;
   case ROTATE:
    //...
    rotateTransition.setDuration(duracao);
    rotateTransition.setNode(alvo);
    t = rotateTransition;
    break;
   case SCALE:
    //...
    scaleTransition.setDuration(duracao);
    scaleTransition.setNode(alvo);
    t = scaleTransition;
    break;
   case TRANSLATE:
    //...
    translateTransition.setDuration(duracao);
    translateTransition.setNode(alvo);
    t = translateTransition;
    break;
   }
   
   t.setAutoReverse(true);
   t.setCycleCount(2);
   return t;
  }

Esses dois métodos simplesmente irão fazer com que a transição mude o atributo do nó e volte para o valor original. Para isso precisamos ter dois ciclos (ciclos são quantas vezes a transição será tocada).

Os botões na parte acima da aplicação são do tipo "ToggleButton" e são parte de um grupo. Esse grupo é gerado baseado no seguinte Enum que você pode ver declarado na classe FabricaTransicao mostrado acima. O Enum contém as transições que a Fábrica suporta e de acordo com os valores dele, a gente gera os botões. Veja o código abaixo:

private HBox criaPainelSuperior() {
 HBox hbTopo = new HBox(10);
 hbTopo.setSpacing(10);
 hbTopo.setAlignment(Pos.CENTER);
 Transicoes[] transicoes = Transicoes.values();
 // grupo para todas as transições
 botoesTransicao = new ToggleGroup();
 for (int i = 0; i < transicoes.length; i++) {
  Transicoes t = transicoes[i];
  ToggleButton tb = new ToggleButton(t.name());
  tb.setUserData(t);
  if (i == 0) {
   tb.setSelected(true);
  }
  tb.setToggleGroup(botoesTransicao);
  hbTopo.getChildren().add(tb);
 }
 return hbTopo;
}

Perceba que através do método setUserData nós adicionamos a cada botão o valor do enum que esse botão representa e usamos esse valor para fabricar nossa transição.  
Quando você clica no botão "Tocar", a "action" do mesmo será usar a fábrica para produzir uma transição de acordo com o botão selecionado, configurar o comportamento dos botões para que os mesmos não fiquem ativos quando a transição estiver tocando(ou que fiquem ativos só quando a transição estiver tocando). Veja a ação do botão Tocar:

btnTocar.setOnAction(new EventHandler() {
 @Override
 public void handle(ActionEvent e) {
  // antes de tocar, pegamos a mais nova transição selecionada
  Transicoes t = (Transicoes) botoesTransicao.getSelectedToggle()
    .getUserData();
  transicaoAtual = FabricaTransicao.fazerTransicao(t,
    sldTempo.getValue());
  // lógicas de habilitação dos botões, temos que setar todas as
  // vezes pq trocamos as transições
  btnParar.disableProperty().bind(
    transicaoAtual.statusProperty().isNotEqualTo(
      Status.RUNNING));
  btnTocar.disableProperty().bind(
    transicaoAtual.statusProperty().isEqualTo(
      Status.RUNNING));
  btnPausar.disableProperty().bind(
    transicaoAtual.statusProperty().isNotEqualTo(
      Status.RUNNING));
  btnAjusta.disableProperty().bind(
    transicaoAtual.statusProperty().isEqualTo(
      Status.RUNNING));
  sldTempo.disableProperty().bind(
    transicaoAtual.statusProperty().isEqualTo(
      Status.RUNNING));
  System.out.println("Tocando transição " + t);
  transicaoAtual.play();
 }
});

Os outros botões irão controlar a transição (parar e pausar) e um serve para "ajustar" o texto quando a transição é parada no meio. Veja o método que é chamado quando clicamos nesse botão.

private void criaNoAlvo() {
 // configurar coisas do texto alvo...
 alvo = new Text("** Transições **");
 alvo.setFont(new Font(60));
 // efeitinsss
 Reflection efeito = new Reflection();
 efeito.setFraction(0.7);
 alvo.setEffect(efeito);
 alvo.setFill(Color.RED);
 raiz.setCenter(alvo);
}

O "slider" no canto direito será usado para que possamos selecionar o tempo total da transição.  Ao criar a transição, pegamos o valor dele e enviamos para o método de criação. Veja a criação e o uso do slider:

// criando o slider
sldTempo = new Slider(1, 10, 5);
//... criando a transição
transicaoAtual = FabricaTransicao.fazerTransicao(t, sldTempo.getValue(), alvo);

Conclusão

Nesse breve artigo nós apresentamos o código de uma aplicação que as transições do JavaFX. Talvez algumas coisas nesse artigo podem parecer um pouco obscuras, mas provavelmente é por que você não acompanha o blog há muito tempo! Sinta-se a vontade para explorar os artigos antigos que muitas coisas serão esclarecidas.
O código completo pode ser conferido no github. Comente esse artigo se tiver dúvidas ou use nosso grupo sobre JavaFX.




15 de set. de 2013

Criando animações usando as transições do JavaFX 2 - Teoria

Hoje vamos falar de algo mais interessante do que simples botões ou figuras geométricas: as transições! Com elas nós podemos criar animações simples com poquissímo código!

O que são transições?

Transições são um conjunto de classes da API do JavaFX 2 que  permitem que crie animações. Com ela nós podemos modificar o valor de uma propriedade em um dado tempo. Por exemplo, você poderia fazer um objeto mover da posição X 0 até a posição X 150 em 2 segundos e isso iria criar uma animação.
Após configurar os parâmetros corretamente, você pode decidir quando a transição começa e até parar antes da mesma terminar. Ou seja, você pode, por exemplo, utilizar um botão para disparar o início da transição e outro para parar. Para você ter ideia, abaixo seguem umas telas de aplicações que demonstram o uso de transições:



Transições disponíveis na API do JavaFX 2

As classes de transição oferecidades no JavaFX 2 ficam no pacote javafx.animation e as seguintes transições estão disponíveis para uso:

  • FadeTransition: Muda a opacidade(tranparência) de um nó. O FadeTransition permite variar essa opacidade em um dado tempo. Por exemplo, você pode configurar uma transição para em 1 segundo variar a opacidade de um nó(um botão, uma imagem, uma figura geométrica, etc) de 0 até 1 e isso fará com que o mesmo passe de invisível até ser completamente visível no tempo de 1 segundo;
  • FillTransition: Com a FillTransition nós podemos mudar a cor de preenchimento de um objetvo. Se um objeto tem o preenchimento com a cor azul e você usa a transição para mudar a cor de azul para rosa em um segundo, isso significa que a cor de preenchimento do mesmo irá iniciar totalmente azul e no espaço de tempo de 1 segundo irá se tornar completamente rosa, dando um efeito bastante interessante;
  • RotateTransition: Uma das propriedades mais comuns em um nó é a rotate (rotação). A RotateTransition mudará a rotação de um objeto de acordo com o tempo configurado. Por exemplo, você pode rotacionar um objeto de 0º até 90º em 2 segundos e após iniciar essa tranisção, ele irá ter a rotação modificada gradualmente até que o tempo termine;
  • ScaleTransition: A ScaleTransition server para você modificar a escala de um objeto, seja a altura ou a largura. Em outras palavras, você pode fazer a escala de um objeto ser modificada de X para X^2  em um dado intervalo de tempo;
  • TranslateTransition: Similarmente ao que foi falado na introdução desse artigo, a TranslateTransition irá modificar a posição X ou Y de um objeto em um dado intervalo de tempo;
  • StrokeTransition: A StrokeTransition é muito similar à FillTransition, no entanto, nessa transição a modificação não é do preenchimento, mas sim da linha que contorna o mesmo;
  • PathTransition: Embora complexa, a PathTransition é muito útil, pois permite que muitas ações sejam tomadas de acordo com o objeto Path passado;

A API do JavaFX também disponibiliza transições que permitem que várias transições sejam "tocadas" ao mesmo tempo, são elas:

SequentialTransition: A SequentialTransition server para adicionar diversas transições para serem "tocadas" de forma sequencial, ou seja, uma após a outra. Por exemplo, se adicionamos a transição t1, t2, t3 em uma SequentialTransition e tocar ela, t1 será ativada, em sequência será ativada t2 e por fim iremos fechar com t3; Se quisermos adicionar um tempo de espera entre as transições, podemos usar a PauseTransition, que é um tipo especial de transição cuja função é simplesmente "dar um tempo" antes da próxima transição da sequência;
ParallelTransition: A ParallelTransition atua de forma semelhante à SequentialTransition, mas toca todas as transições em paralelo, sendo que o tempo de duração será a da transição mais longa.



Lembre-se que todo componentes em uma aplicação JavaFX herda de (é um) nó e todos os nós tem propriedades em comum como rotação, posição X e Y, opacidade, etc;

Transições na prática

Como muitos já devem ter imaginado, temos uma classe comum para todas as transições, a classe Transition  Abaixo temos uma explicação de seus principais métodos:

play(): Começa a "tocar" a transição. Se a transição estava pausada antes, chamar esse método fará com que a transição volte a tocar do ponto onde tinha parada. Similar ao play, temos a playFromStart, que começa uma transição desde o começo e playFrom(Duration), onde podemos informar um ponto para a transição começar a tocar;
pause(): Para a transição em um dado momento, sendo que ao chamar play, a transição irá começar no momento parado por pause;
stop(): Para a transição por completo. A próxima vez que chamarmos play a transição irá iniciar do ponto inicial;
setOnFinished(EventHandler<ActionEvent>): Esse método é interessante! Com ele podemos informar uma ação que você deseja que seja feita assim que a transição termina de "tocar";
setAutoReverse(boolean value): Se chamarmos esse método e informar o valor true para value, iremos fazer com que a transição "volte", ou seja, se a transição for fazer um nó ir da posição X 0 para a posição 10, ao chamar setAutoReverse(true), o mesmo irá até a posição 10 e irá voltar para a posição 0 invés de parar na posição X 10;
setNode(Node): Aqui é onde falamos qual será nosso alvo
Outros métodos: Há outros métodos e atributos interessantes(acessados através de métodos) que você queria dar uma olhada. Para isso veja a documentação da classe que Transition veio, a Animation.

E o código?

Na próxima parte desse artigo vamos mostrar o código de uma aplicação que usa todas as transições do JavaFX. Eu sei que é "brochante" ler um textão desse e no fim não ter código, mas garanto um próximo artigo com bastante código pra gente discutir!

Conclusão

Transições é uma parte divertida da API do JavaFX. Com elas podemos criar animações com pouquíssimas linhas de código. Não perca o próximo artigo!