Javafx Pratico
Javafx Pratico
de conteúdos
Capa 1.1
Prefácio 1.2
Apresentação 1.3
JavaFX Prático 1.4
Um "Olá Mundo" com JavaFX 1.4.1
Mostrando Imagens e Figuras Geométricas 1.4.2
Tocando Áudio 1.4.3
Tocando Vídeo 1.4.4
Controles de interface: Rótulos, campos de texto e outros 1.4.5
Controles de interface: Tratamento de eventos e o botão 1.4.6
Controles de Interface: Radio Button, CheckBox e ToggleButton 1.4.7
Controles de Interface: ComboBox e ChoiceBox 1.4.8
Gerenciando Layout: HBox, VBox e StackPane 1.4.9
Gerenciando Layout: BorderPane, FlowPane e o GridPane 1.4.10
Transições 1.4.11
Desenhando com Canvas 1.4.12
Gráficos 1.4.13
Abrindo páginas Web 1.4.14
Tabelas com JavaFX 1.4.15
Mudando o estilo com CSS 1.4.16
Usando FXML 1.4.17
Projeto: Um simples CRUD 1.4.18
Conclusão 1.5
2
Capa
JavaFX Prático
Leitura prática da API básica do JavaFX
3
Prefácio
Prefácio
Ninguém é uma ilha durante o aprendizado no mundo da programação e, talvez, em
qualquer processo de aprendizado, pois nosso maior diferencial sobre as outras espécies é
aprender e passar pra frente o aprendizado. O mundo conectado é maravilhoso: posso
parar o que estou fazendo agora e ter algumas aulas de neurociência no youtube, ou
biologia e até aprender a fazer as unhas, por que não?
Nesse proceso incrível nos esquecemos do principal, que são os que criam conteúdo.
Tenho isso em meu coração desde o tempo do ensino médio ou quando aprendia eletrônica
com revistinhas _Divirta-se com a Eletrônica, _do mestre Bêda Marques. Claro que o caos
no mundo liberal que vivemos garante que, por motivações diversas, as pessoas poderão
criar conteúdos e serem beneficiadas por isso, como ganhar dinheiro através de _adsense
_do Google ou com _marketing. _Mas há algo mais que move os criadores de conteúdo.
Esse algo mais é uma força incrível, que nos remete a ideia de um mundo melhor através
da disseminação do conhecimento. Sim, ainda existem coisas como essas no mundo
líquido que vivemos. Eu acredito ter isso comigo, pois joguei minha carreira promissora
como ABAP para trabalhar com _open source. _Mas não há nada em especial nisso,
todos temos isso e só precisamos nos manter firmez e exercitar essa ideia em tempos
complicados para o homem romântico com suas ideias destruídas pelo século do ego.
Muitos que criaram conteúdos que permitiram a sua existência tinham isso forte com eles e
hoje podemos contribuir de forma pequena, como esse livro, mas juntos é que crescemos.
Quando se um dia houver o alinhamento desse pensamento, então inicia a história do
homem.
Mas voltando a revistinha Divirta-se com a Eletrônica. Nessa revista não tínhamos horas e
horas de cálculo para então ver algo concreto, nós, os hobbystas, como éramos chamados
pelos escritores da revista, criávemos circuitos divertidos e rápidos e com o tempo íamos
ganhando conhecimento teórico. Essa é a ideia desse livro. Com certeza, eu não acertei o
ponto, mas pensei em escrever com editoras, com regras e tudo mais, mas, pra ser sincero,
assim funcionou pra mim e deve funcionar para um punhado de pessoas, por isso escolhi
essa plataforma gitbooks e organizei tudo aqui.
Ao ler esse livro eu espero que: 1) Você se divirta; 2) Aprenda algo que vai lhe ser útil; 3)
Possa compartilhar as coisas que aprendeu aqui com outras pessoas .
4
Apresentação
JavaFX Prático
Um livro rápido, direto, sem muita enrolação. Objetivo é introduzir as classes mais básicas
da plataforma JavaFX com evolução natural dos conceitos sem que haja buracos no
aprendizado dos componentes básicos da plataforma. É necessário somente o
conhecimento básico de Java e o uso de uma IDE que suporte Maven.
Notem que esse livro é baseado no blog Aprendendo JavaFX, mas revisado, editado e
formatado para ficar no formato de um livro!
Software Necessário
Utilizando JavaFX 8 e Eclipse. O download pode ser realizado nos seguintes links:
Java JDK 8
Eclipse IDE for Java Developers(para esse livro foi usada a versão "Mars")
Espero que o leitor seja curioso e pró-ativo: Abra os links e leia a documentação; Edite o
código; crie coisas legais para você com os exemplos que encontrar.
Código
Há exemplos de código em todos os capítulos e estão estão em um projeto Maven que
poderá ser baixado em http://aprendendo-javafx.blogspot.com.
5
Apresentação
No Eclipse você deve usar o menu File -> Import -> Existing Maven Projects
Então você aponta para o diretório onde está o arquivo pom.xml, que você deszipou;
É só um projeto com todo o código mencionado nesse livro. Você pode rodar as
classes que tiverem um método main _usando Run As -> Java Application_
6
JavaFX Prático
O que é JavaFX?
Calma, em alguns minutos você vai estar se divertindo com JavaFX, passeando por esse
fascinante toolkit gráfico!
7
Um "Olá Mundo" com JavaFX
Ótimo! Já temos tudo o que precisamos. O próximo passo agora é abrir o Eclipse e criar um
projeto do tipo Maven Project. Nesse projeto iremos criar um pacote e nele uma classe
Java. Veja abaixo uma explicação mais detalhada (nomes em negrito e itálico entre
parêntesis foram os que eu usei):
1. Acesse o menu File -> New -> Maven Project, marque a opção "Create a simple
project (skip archetype selection)", preencha os valores para
groupId(org.javafxpratico), artifact-id(javafx-pratico), version(1.0) e clique em
Finish;
2. Clique com o botão direto sobre o seu projeto e acesse o menu New -> Package, dê
um nome (javafxpratico) e em seguida clique em Finish;
3. Clique com o botão direito no pacote main e acesse o menu New -> Class. Dê um
nome para a classe (eu usei OlaMundoJavaFX) e clique em Finish.
Pronto! É nesse mesmo projeto que iremos explorar o JavaFX. O código da classe
OlaMundoJavaFX deve se parecer com o seguinte:
8
Um "Olá Mundo" com JavaFX
package javafxpratico;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
@Override
public void start(Stage palco) throws Exception { // 3
StackPane raiz = new StackPane(); // 4
Label lblMensagem = new Label(); // 5
}
}
Essa é uma das aplicações mais básicas que você pode fazer com JavaFX! Você pode
executa-la clicando em Run ou clicando com o botão direito em cima dela e escolher no
menu o seguinte: Run As -> Java Application. Se fizer tudo certinho a seguinte janela irá
aparecer:
Ótimo! Sua primeira aplicação. Vocë deve ter notado que o código acima está com
comentários numéricos. Isso foi proposital, pois aqui vai a explicaÇão desse código aí!
Preste bastante atenção pois esse mesmo cõdigo é usado em todas as aplicações JavaFX!
9
Um "Olá Mundo" com JavaFX
vai código JavaFX, o código vai no método start (notem que no JavaFX 8 isso é mais
necessário, abaixo mais detalhes);
3. A implementação do método start, herdado da classe Application. O atributo recebido é
do tipo javafx.stage.Stage. Sendo direto, podemos ver o Stage (palco) como o frame,
a janela da nossa aplicação, mas na verdade ele não pode ser representado sim se
pensarmos nos diversos dispositivos que podem rodar(em um futuro próximo) JavaFX:
Celulares, televisores, "tablets", etc;
4. Nesse ponto nós criamos um elemento chamado "pai", pois permite adicionarmos
outras coisas dentro dele. No nosso caso, o javafx.scene.layout.StackPane permite
adicionar vários elementos os quais tem seu leiaute de pilha, ou seja, eles serão
empilhados um sobre o outro. No futuro falaremos mais sobre isso, mas lembre-se que
tudo no JavaFX é um nó, ou seja, herda da classe Node;
5. Não há nada de mais aqui, simplesmente criamos um objeto do tipo
javafx.scene.control.Label, que é um controle de interface para mostrar texto. Ponto;
6. Aqui informamos o texto que o Label irá mostrar. Note que isso poderia ter sido feito
pelo construtor, na criação do Label;
7. Como o StackPane é um elemento pai, ele também tem elementos filhos. Nessa linha
de código, recuperamos os filhos dele(getChildren()) e adicionamos nosso
Label(add(Node)), fazendo que o Label seja um filho dele;
8. É hora de aprender outro conceito do JavaFX. Nessa linha criamos uma
javafx.scene.Scene(cena). Uma cena é o contâiner principal de todos os elementos do
JavaFX e na criação dela aproveitamos para informar a raiz (como o nome diz, a raiz
de todos os componentes), largura e altura da cena;
9. Agora vamos voltar a mexer com nosso palco. Nessa linha informamos o título dele, no
nosso caso atual, o título da janela que será mostrada;
10. O palco precisa de uma cena, simplesmente é isso que é feito nessa linha.
11. Simplesmente mostrando o palco! Se esse método não for chamado, nada irá
acontecer quando executar esse código.
Pronto! Muita coisa nova, né? Mas não desista, no decorrer dos artigos você vai ficando
cada vez mais confortável com JavaFX e seus componentes!
10
Mostrando Imagens e Figuras Geométricas
Forma Geométricas
Todas as formas geométricas do JavaFX, adivinhe, também são Nodes e podem sofrer
efeitos, transformações e animações, além de ter diversas propriedades em comum. Você
pode ver as figuras geométricas oferecidas pelo JavaFX no pacote javafx.scene.shape.
Todas as figuras geométricas herdam de javafx.scene.shape.Shape (que por sua vez
herda de... Node), portanto temos propriedades comuns só para as figuras geométricas,
entre as quais destacamos:
Hora do Código
11
Mostrando Imagens e Figuras Geométricas
Ufa, hora de se divertir. No código atual iremos mostrar a carga de uma imagem e algumas
figuras geométricas, ficando a seu cargo baixar o projeto anexado e fazer algo mais
elaborado e divertido. Se formos explorar todas as propriedades de cada forma geométrica,
estaríamos sendo redundantes, verbosos e chatos e programação se aprende com ação e
não exposição :) Após o código, temos uma explicação linha a linha de tudo que é feito.
package javafxpratico;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
@Override
public void start(Stage palco) throws Exception {
Image imagem = new Image(IMG_URL); // 1
ImageView visualizadorImagem = new ImageView(imagem); // 2
visualizadorImagem.setTranslateX(80); // 3
visualizadorImagem.setTranslateY(5); // 4
12
Mostrando Imagens e Figuras Geométricas
circulo.setTranslateY(110);
circulo.setFill(Color.YELLOW);
1. Nessa linha carregamos nossa imagem usando uma URL da internet. Lembrando que
essa não é a única maneira, podemos também usar um arquivo ou qualquer coisas que
forneça um InputStream;
2. Agora criamos o nó da imagem e informamos que imagem será mostrada no
construtor;
3. Usamos uma propriedade nova nessa linha e ela nem é só do ImageView, é da classe
Node! Com o translateX informamos a posição X(imagine o posicionamento como um
plano cartesiano) de um componente no pai. O método set serve para configurar um
valor, você já viu o uso dele em classes como o Stage;
4. Fazemos o mesmo descrito em 3, mas agora para a posição Y. ATENÇÃO: Posicionar
componentes assim não é legal de ser feito em aplicações grandes, vamos mostrar em
breve os gerenciadores de leiaute do JavaFX;
5. Aqui já estamos criando uma forma geométrica, um Retângulo (Rectangle). De acordo
com a forma criada, teremos parâmetros que devem ser informados. No caso do
retângulo, informamos a largura e a altura;
6. Mudamos a cor padrão da forma geométrica (preta) para verde. Note que aqui usamos
uma constante da classe javafx.scene.paint.Color;
7. É informado a cor da linha que envolve essa forma geométrica, nesse caso: preta;
8. Também aumentamos a largura (ou grossura) da linha;
9. Outra novidade nesse código: a classe javafx.scene.Group. Como o próprio nome
13
Mostrando Imagens e Figuras Geométricas
14
Tocando Áudio
Tocando Áudio
Incrível como as coisas são simples no JavaFX: tocar áudio exige 2 linhas de código, em
outras palavras, simplesmente o áudio deve ser carregado e então tocado. O áudio não
dispõe de uma classe para visualização, já que essa não é necessária e temos somente
uma classe necessária para a carga e execução do áudio, a classe
javafx.scene.media.AudioClip. Claro que você pode criar um player se achar necessário.
Vejam abaixo o código de uma pequena aplicação de exemplo e em seguida a explicação
(se você criar uma classe TocandoAudio no projeto que criamos, você pode testar esse
código):
package javafxpratico;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.media.AudioClip;
import javafx.scene.text.Text;
import javafx.stage.Stage;
@Override
public void start(Stage palco) throws Exception {
AudioClip clip = new AudioClip(AUDIO_URL);// 1
clip.play(); // 2
StackPane raiz = new StackPane();
raiz.getChildren().add(new Text("Tocando Música ")); // 3
Scene cena = new Scene(raiz, 600, 100);
palco.setTitle("Tocando Audio em JavaFX");
palco.setScene(cena);
palco.show();
}
}
15
Tocando Áudio
áudio irá começar a tocar nessa linha. Semelhante ao vídeo, temos vários outros
métodos que poderíamos utilizar
2. Não é relacionado ao áudio, mas essa linha adiciona um simples texto informativo, pois
não temos nada visual quanto tocamos áudio
A aplicação pode demorar um pouquinho para rodar, pois o áudio está na internet. Você
pode incrementar essa aplicação quando aprender sobre botões e outros controles de
interface que falaremos em breve.
16
Tocando Vídeo
Tocando Vídeo
Tocar vídeo em JavaFX é tão simples que chega a assustar quem já tentou tocar um vídeo
usando Java. Nós só temos que seguir três pequenos passos:
Carregar: Você primeiramente deve carregar a mídia que vai tocar. A mídia pode estar
no seu disco rígido como em um um servidor remoto(carregando assim através da sua
URL);
Tocar. A partir da mídia, você deverá controlar a mesma: tocar, parar, pausar...
Mostrar: Nesse ponto iremos colocar o vídeo dentro de sua aplicação JavaFX.
Para realizar esses três passos temos três classes JavaFX que ficam no pacote
javafx.scene.media. Para 1 nós temos a classe Media, 2 podemos fazer com a classe
MediaPlayer e finalmente conseguimos o passo três com o uso da MediaView. O uso
dessas classes é muito simples, abaixo temos o código de um aplicação de exemplo e em
seguida um breve explicação de cada linha nova. Se você quiser testar, crie uma classe
chamada TocandoVideo no mesmo projeto que já criamos e cole o código abaixo - note
que a execução pode levar uns segundos já que ele baixa um arquivo da internet:
17
Tocando Vídeo
package javafxpratico;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
@Override
public void start(Stage palco) throws Exception {
mediaPlayer.play(); // 4
}
}
18
Tocando Vídeo
qualquer Node que herda de Parent (não se preocupe, futuramente teremos posts
específicos sobre essas classes). Nessa linha nós adicionamos o vídeo ao pai;
5. Por fim tocamos o vídeo através do método play(). Há também outros métodos para
controle do vídeo, sendo possível criar um player dinâmico...
Conforme mostrado acima, são quatro linhas para podermos tocar um vídeo em uma
aplicação JavaFX. Veja abaixo o resultado:
No futuro, quando você aprender mais sobre JavaFX, você pode voltar para essa mesma
aplicação e fazer melhorias: adicionar botões de controle, permitir usuário escolher a URL
do vídeo e por aí vai.
19
Controles de interface: Rótulos, campos de texto e outros
Controles de interface
Todos os controles que o JavaFX oferece herdam da classe Control. Como alguns já
devem ter deduzido, Control vai herdar em algum momento de Node, mas nesse caso ele
antes herda de Parent.
java.lang.Object
javafx.scene.Node
javafx.scene.Parent
javafx.scene.control.Control
Logos todos os controles usufruem com atributos como height, maxHeight, width, minWidth,
entre outros.
Os controles são muito fáceis de lidar, no entanto, muitos tem suas características
especifícas, o que leva a uma complicação maior somente para um capítulo, então iremos
separar a abordagem dos controles em vários, nesse iremos abordar "Rótulos, campos de
texto, separadores e controles deslizantes".
package main;
20
Controles de interface: Rótulos, campos de texto e outros
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.Slider;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
@Override
public void start(Stage palco) throws Exception {
VBox raiz = new VBox(10); // 1
raiz.setAlignment(Pos.CENTER); // 2
21
Controles de interface: Rótulos, campos de texto e outros
}
}
22
Controles de interface: Rótulos, campos de texto e outros
controle deslizante.
23
Controles de interface: Tratamento de eventos e o botão
Tratamento de evento
Tratar evento é determinar qual código será executado de acordo com uma ação do
usuário. O usuário interage com sua aplicação através da interface gráfica, e dela ele faz
diversas coisas: passa o cursor do mouse sobre um componente, arrasta coisas, clica,
move o cursor para dentro ou para fora de um componente, entre outros. Qualquer
componente é passível de sobre ações desse tipo por parte do usuário, logo, na classe
Node podemos tratar qualquer um desses eventos. Nesse capítulo, no entanto, não iremos
falar de todos eles, mas só de um que é o evento de ação. Quando o usuário clica em um
botão, ele dispara esse evento. Iremos apresentar o botão, fazer um programa simples com
ele e explicar como tratar o clique em um botão. Quando entrarmos em detalhes na classe
Node iremos mostrar como tratar cada um desses outros eventos
Botões e Ouvintes
Botões estão em todos os lugares, com certeza você deve ter clicado em algum botão hoje!
No JavaFX, um botão pode ser usado através da classe Button. No entanto, simplesmente
adicionar um botão na cena não ajuda em muita coisa, você deve informar para ele o que
deve ser feito assim que um usuário clicar no mesmo. Isso é feito através de ouvintes de
evento, que são classes que implementam uma determinada interface.
No caso de botão, temos o atributo onAction que é do tipo da interface EventHandler. Essa
interface exige que você implemente o método handle, que é será chamado quando você
clicar no botão. Em resumo, você deve criar uma classe que implementa essa interface e
informar ao botão uma instância dessa classe para que o botão chame o método quando o
usuário do seu programa clicar nele! O tipo do evento pode ser parametrizado usando
Genéricos - assim o tipo especificado pelo genérico será o tipo do parämetro recebido no
método handle.
24
Controles de interface: Tratamento de eventos e o botão
Felizmente com o Java 8 a gente não precisa escrever muito código, podemos usar
expressões Lambda! No final desse livro você deverá encontrar um apêndice que fala
sobre Java 8 e as expressões lambdas.
Nossa, muita informação! Mas isso ficará melhor nas próximas linhas, pois mostremos
exemplos de código e tudo ficará mais claro.
Clique em mim!
Vamos começar mostrando um exemplo do clássico clique em mim para assim demonstrar
o tratamento mais simples possível de evento. A nossa classe ouvinte, ou tratadora de
evento se encontra abaixo e em seguida uma breve explicação do código.
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
2. Esse é o método que será chamado quando clicarmos no botão.O parâmetro evento
será enviado pelo gerador do evento, no caso o botão, e deles poderíamos saber tudo
de quem gerou o evento.
Mas de quem esse tratador de evento trata eventos? O próximo passo é informar para um
botão qual será o seu tratador de evento. Veja abaixo que uso duas linhas para isso e
basicamente criamos um botão e informamos quem será o tratador de evento através do
método setOnAction.
Ótimo, já sabemos tratar eventos, mas e se você não quiser criar uma classe para toda vez
que quiser tratar um clique? Você pode utilizar um classe anônima ou as modernas
expressões lambdas.
Para ilustrar tudo isso, criamos uma simples aplicação com dois botões e três formas de se
registar um tratador de evento. O código abaixo mostra essa aplicação e também explica
diretamente no comentário!
25
Controles de interface: Tratamento de eventos e o botão
package javafxpratico;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
//Se quisermos que essa classe trate evento, ela deve herdar de EventHandler
public class TratamentoEventoComBotao extends Application
implements EventHandler<ActionEvent> {
@Override
public void start(Stage palco) throws Exception {
VBox raiz = new VBox(20);
raiz.setAlignment(Pos.CENTER);
raiz.setTranslateY(5);
/*
* Como a própria classe TratamentoEventoComBotao implementa
* a interface EventHandler, ela mesma pode responder a eventos do botão
26
Controles de interface: Tratamento de eventos e o botão
*
*/
public void handle(ActionEvent evento) {
System.out.println("Evento tratado na próxima classe!");
}
/**
* Uma classe para tratar os eventos
* poderia ser uma classe externa
*
*/
public static class TratadorEvento implements EventHandler<ActionEvent> { // 1
A aplicação final bem como o que será impresso no console é mostrado na imagem abaixo:
27
Controles de Interface: Radio Button, CheckBox e ToggleButton
O uso desse tipo de botão é feito em diversos casos onde você tem escolhar bem pré-
definidas, por exemplo: campos para escolha de sexo, faixa de salário, alternativas de
questões multivaloradas com uma resposta válida, entre outros.
Pode parecer estranho, mas um problema que podemos ter é pedir a entrada de um usuário
e o mesmo sequer ligar para esse campo, daí ele larga o campo em branco, logo, como
você vai fazer para saber se ele não respondeu ou não marcou com o objetivo de responder
de forma negativa à pergunta?
28
Controles de Interface: Radio Button, CheckBox e ToggleButton
package javafxpratico;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
@Override
public void start(Stage palco) throws Exception {
VBox raiz = new VBox(10);
raiz.setTranslateX(10);
raiz.setTranslateY(20);
29
Controles de Interface: Radio Button, CheckBox e ToggleButton
Explicação do Código
30
Controles de Interface: Radio Button, CheckBox e ToggleButton
31
Controles de Interface: ComboBox e ChoiceBox
ComboBox e ChoiceBox
Nesse capítulo também sobre controles, vamos falar das caixas de combinação,
ComboBox, e caixas de escolhas, ChoiceBox. Ambas permitem você escolher um valor
entre um conjunto de opções.
Selecione a cor
Para demostrar o ComboBox, criamos uma aplicação bem simples que permite que você
selecione a cor da cena e de um retângulo através do uso desse controle de interface. Ao
selecionar a cor, a mudança já é imediata. Como fazemos isso? Confira o código e em
seguida tenha acesso a uma explicação rápida:
package javafxpratico;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
32
Controles de Interface: ComboBox e ChoiceBox
@Override
public void start(Stage palco) throws Exception {
StackPane raiz = new StackPane();
cbCorCena.getItems().addAll(cores); // 2
cbCorRetangulo.getItems().addAll(cores);
opcoes.getChildren().addAll(cbCorCena, cbCorRetangulo);
1. Começamos instanciando uma ComboBox. Perceba que ela faz uso de genéricos,
onde informamos que tipo de dado serão os itens contidos nela, no nossa caso, String;
33
Controles de Interface: ComboBox e ChoiceBox
2. Nessa linha adicionamos os itens. Isso é feito de forma semelhante com a qual
adicionamos itens a um componente pai como o Group, VBox, HBox, entre outros.
Nesse caso estamos adicionando uma lista de Strings, pois esse é o tipo aceitado por
essa combobox;
3. Para observar quando o usuário escolhe algum valor no Combobox, adicionamos um
ouvinte ao valor observável a propriedade do item selecionado. Isso pode parecer
bastante estranho, mas em breve você vai se acostumar. JavaFX traz uma API com
atributos diferentes, onde nós podemos observar as modificações feitas nesses
atributos e tomar alguma ação. Novamente isso é feito através de Listeners, no nosso
caso usamos um listener de mudança, o ChangeListener. Note que o uso dele é
bastante semelhante ao uso dos listeners de botões. Em resumo, nós estamos
observando o valor selecionado do combox através de um listener, quando ele muda,
nós trocamos a cor de fundo da cena e usamos a sintaxe das expressões lambda para
simplificar;
4. A classe Color do JavaFX é bastante interessante e contém muito mais do que um
aglomerado de constantes para definir cores. É possível também converter o valor de
texto de uma cor para um objeto Color. É isso o que fazermos aqui;
5. Por fim nós usamos o método select do modelo de seleção para escolher uma cor.
Esse método equivale a ação de um usuário ao escolher uma cor na combobox usando
a sua aplicação, ou seja, isso também vai disparar o ouvinte de mudança que falamos
na explicação 3.
34
Gerenciando Layout: HBox, VBox e StackPane
O JavaFX traz alguns gerenciadores pronto para auxiliar você. Nesse capítulo vamos
começar a falar dessa API, no entanto, vocë deve ter percebido o uso de alguns em
capítulos anteriores.
35
Gerenciando Layout: HBox, VBox e StackPane
Arquitetura
Como você já deve ter percebido, essas os gerenciadores aceitam classes que herdam de
Node e os próprios são Nodes também. Eles estendem diretamente de Pane cujo método
mais comum é getChildren.
Conhecendo na prática
Depois de tanto conceito e uma pequena exploração da API, vamos criar aplicações
simples que usam essas classes e dessa forma vamos ver em ação tudo que falamos,
tornando mais prazeroso o aprendizado e a exploração da API. Hoje vamos mostrar só três
classes: VBox, HBox e StackPane.
VBox
Um dos gerenciadores mais simples, a classe VBox simplesmente alinha os componentes
verticalmente e permite determinar o espaçamento entre eles e ainda o alinhamento. Abaixo
um código que simplesmente adiciona umas forma geométricas a uma VBox e em seguida
a explicação do mesmo.
36
Gerenciando Layout: HBox, VBox e StackPane
package javafxpratico;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
@Override
public void start(Stage stage) throws Exception {
VBox caixaVertical = new VBox(); // 1
caixaVertical.setSpacing(5); // 2
caixaVertical.setAlignment(Pos.CENTER); // 3
// 4
caixaVertical.setTranslateX(10);
caixaVertical.setTranslateY(20);
// 5
Rectangle retanguloAzul = new Rectangle(40, 20);
Rectangle retanguloVerde = new Rectangle(40, 20);
Rectangle retanguloVermelho = new Rectangle(40, 20);
retanguloAzul.setFill(Color.BLUE);
retanguloVerde.setFill(Color.GREEN);
retanguloVermelho.setFill(Color.RED);
// 6
caixaVertical.getChildren().addAll(retanguloAzul, retanguloVerde, retanguloVer
melho);
stage.setScene(new Scene(caixaVertical, 230, 250));
stage.show();
stage.setTitle("Testando VBox");
}
1. Criando nossa VBox. Não estamos enviando nada no construtor, mas é possível
informar o espaçamento entre os componentes diretamente no construtor;
2. Informamos o espaçamento. Esse atributo é do tipo Double e ele informa qual distância
os componentes devem entre eles;
3. Aqui determinamos que os componentes fiquem centralizados no nosso VBox.
37
Gerenciando Layout: HBox, VBox e StackPane
Podemos também escolher colocar eles para esquerda, direta, entre outros. Veja o
enum Pos.
4. Nessa linha mudamos a posição X e Y do nosso VBox. O interessante é que os
componentes filhos terão que obedecer a posição do pai, para isso eles também são
deslocados automaticamente;
5. Criamos nossos componentes que estarão no VBox. Criamos retângulos e lembrando
que eles herdam de Node. Isso é um requisito para nosso gerenciador.
6. Agora adicionamos todos de uma vez. A ordem de adicão é a ordem que eles serão
mostrados na aplicação.
O resultado está abaixo. Lembre-se de sempre fuçar bastante as classes, essa é a melhor
forma de aprender e se diverter :)
HBox
Não iremos entrar em detalhes dessa classe por que ela trabalha exatamente igual a VBox,
com exceção que ela alinha os componentes horizontalmente. Abaixo temos uma imagem
de como o código acima se comportaria simplesmente trocar a "instanciação" de VBox para
HBox.
38
Gerenciando Layout: HBox, VBox e StackPane
StackPane
Um comportamento não muito comum, mas que pode ser útil em diversas aplicações, é o
trazido pela classe StackPane. Nela os componentes são empilhados uns nos outros, ou
seja, quem entrou primeiro fica embaixo do segundo e assim por diante. O exemplo de
código abaixo mostra isso muito claramente. Perceba que não iremos explicar o código pois
ele é semelhante ao mostrado anteriormente, a exceção está no resultado visual. Estamos
desenhando uma bandeira do Brasil (ou tentando), para isso criamos um retângulo, um
losango um círculo e, o mais díficil, um arco. Usamos as formas geométricas do JavaFX
para fazer isso e no fim colocamos em um gerenciador do tipo StackPane, veja que ele
empilha as imagens de forma que por final temos algo que é quase uma bandeira do
Brasil... Quase...
package javafxpratico;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.Circle;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
39
Gerenciando Layout: HBox, VBox e StackPane
@Override
public void start(Stage palco) throws Exception {
StackPane painelEmpilhador = new StackPane();
Rectangle retangulo = new Rectangle(220, 120);
retangulo.setFill(Color.GREEN);
arco.getElements().add(moveTo);
arco.getElements().add(arcTo);
arco.setStroke(Color.WHITE);
arco.setRotate(180);
arco.setStrokeWidth(5);
Mais uma vez note que a ordem que adicionamos os componentes é muito importante. Veja
o resultado:
40
Gerenciando Layout: HBox, VBox e StackPane
41
Gerenciando Layout: BorderPane, FlowPane e o GridPane
BorderPane
Uma das heranças do bom e velho Swing é o BorderPane. A idéia é bem simples: você
coloca os componentes em regiões do painel. Essas regiões são referenciadas como: norte,
sul, leste, oeste e centro.
Não há nenhum segredo no uso dele, mas há um pequena diferença que é termos que
informar na hora de adicionar os componentes a qual região o mesmo pertence. Vamos ao
exemplo de código e em seguida a explicação.
42
Gerenciando Layout: BorderPane, FlowPane e o GridPane
GridPane
O GridPane, ou painel de grade, permite adicionar componentes em posições específicas
semelhantes á uma grade de nós. Para entender melhor imagine a área do GridPane como
um tabuleiro de batalha naval. Nesse tipo de jogo, temos os campos definidos por divisões,
como por exemplo A1, B5, etc. O GridPane atua de forma semelhante, posicionando
componentes nessa grade. No entanto, especificamos a posição com dois números invés
de uma letra e um número, exemplo: 1-1, 5-2, etc. Esse gerenciador de leiaute também não
utiliza os métodos add, set e remove. Na verdade, no momento de adicionar o componente
já especificamos qual a "gradezinha" ele vai ocupar. Vamos a um exemplo de código para
esclarecer.
43
Gerenciando Layout: BorderPane, FlowPane e o GridPane
FlowPane
"Painel de Fluxo" é um significado ao pé da letra para FlowPane. Como o nome diz, é um
painel que segue o fluxo da coisa, ou seja, você vai adicionando componentes e ele vai
colocando de acordo com o fluxo. O fluxo pode ser na vertical ou horizontal e os
componentes podem ser posicionados de forma centralizada, centralizada na vertical, tudo
ao topo, etc. Parece difícil, mas é um dos paineis mais simples. Por exemplo, digamos que
você utilize um desses do tipo horizontal e adicione 4 componentes. O 4 não caberia na
mesma linha, então o FlowPane coloca ele na "linha abaixo", mesmo sobrando espaço na
terceira linha. O mesmo acontece para o FlowPane na vertical, mas aí ele colocaria os
componentes na próximo coluna, seguindo o fluxo. Lembrando que isso é dinâmico, se
vocề redimensiona o pai, ele realoca os componentes sempre seguindo o fluxo. Mas chega
de papo e vamos ao código.
// 1
FlowPane flowPane = new FlowPane();
// 2
flowPane.setAlignment(Pos.CENTER_RIGHT);
for (int i = 0; i < 10; i++) {
// 3
flowPane.getChildren().add(new Label("Label " + i));
}
1. Criamos o nosso FlowPane. Falei que podemos a direção do fluxo. Isso pode ser feito
direto no construtor usando a classe Orientation;
2. Aqui setamos o alinhamento: centro, centro para a direita, centro // para esquerda, topo
para esquerda, etc. Brinque com outros valores; :)
3. Adicionando um componente ao nosso Painel. Isso é feito da forma simples já
mostrada em seções anteriores anterior.
44
Gerenciando Layout: BorderPane, FlowPane e o GridPane
O código geral pode ser encontrado nesse mesmo repositório, lá vocês poderão ver os
valores de import para as classes usadas.
45
Transições
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:
46
Transições
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 Pathpassado;
A API do JavaFX também disponibiliza transições que permitem que várias transições
sejam "tocadas" ao mesmo tempo, são elas:
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;
47
Transições
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;
setNode(Node): Aqui é onde falamos qual será nosso alvo ou o nó que será manipulado
por essa transição;
Exemplo de uso
Vamos agora explorar uma pequena aplicação que irá mostrar as funcionalidades das
principais transições. Você pode encontrar o código da classe no arquivo
AprendendoTransicoes.java. Veja nossa aplicação de exemplo:
48
Transições
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:
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();
49
Transições
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 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(setAutoReverse e setCycleCount), logo não precisamos repetir a chamada
50
Transições
do mesmo para cada transição criada.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:
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:
51
Transições
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:
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:
52
Transições
// criando o slider
sldTempo = new Slider(1, 10, 5);
//... criando a transição
transicaoAtual = FabricaTransicao.fazerTransicao(t, sldTempo.getValue(), alvo);
Terminamos aqui nossa seção sobre transições. Lembrando que a aplicação discutida
acima foi demonstrada em um vídeo no youtube.
53
Desenhando com Canvas
Canvas
O canvas é simplesmente um nó que representa uma área para desenhar. Isso mesmo,
nada mais do que isso. A mágica acontece com a class GraphicContext, que pode ser
adquirida assim que criamos um Canvas. Com o GraphicContext você pode desenhar
formas geométricas, textos, imagens, mudar cor, aplicar efeito, etc. Veja um exemplo:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.effect.BoxBlur;
import javafx.scene.effect.Reflection;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
54
Desenhando com Canvas
@Override
public void start(Stage palco) throws Exception {
// O construtor do Canvas recebe a largura e a altura
Canvas canvas = new Canvas(300, 300);
// O objeto principal do Canvas é o GraphicsContext, que usamos para desenhar
GraphicsContext ctx = canvas.getGraphicsContext2D();
// estamos prontos para desenhar coisas! Vamos começar mudando a cor
ctx.setFill(Color.RED);
// podemos configurar uma fonte para os textos
ctx.setFont(Font.font("Serif", FontWeight.BOLD, 25));
// desenhando um texto, o primeiro param é o texto, os seguintes são a pos X e
Y
ctx.fillText("Olá Mundo Canvas", 15, 30);
// podemos configurar efeitos e novamente trocar a cor
ctx.setFill(Color.BLUE);
ctx.setEffect(new BoxBlur());
ctx.fillText("Olá Mundo Canvas", 15, 60);
// agora vamos trocar o efeito, cor e desenhar um retângulo(x,y, largura, altu
ra)
ctx.setEffect(new Reflection());
ctx.setFill(Color.AQUA);
ctx.fillRect(15, 90, 240, 20);
// ou um retângulo sem preenchimento
ctx.setStroke(Color.GREEN);
ctx.strokeRect(15, 135, 240, 30);
// ou circulos (forma oval)
ctx.setEffect(null);
ctx.setFill(Color.BROWN);
ctx.fillOval(15, 175, 90, 25);
ctx.setStroke(Color.YELLOWGREEN);
// ou formas ovais sem preenchimento
ctx.strokeOval(160, 175, 90, 25);
// ou até desenhar uns poligonos locos, usando diversos pontos X e Y
double xs[] = {15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165,
180, 195, 210, 225, 240, 255, 270};
double ys[] = {205, 235, 250, 265, 205, 235, 205, 205, 235, 250,
265, 205, 235, 205, 205, 235, 250, 205};
ctx.setFill(Color.MAGENTA);
ctx.setEffect(new Reflection());
ctx.fillPolygon(xs, ys, 18);
Scene cena = new Scene(new StackPane(canvas), 800, 600);
palco.setTitle("Canvas");
palco.setScene(cena);
palco.show();
}
55
Desenhando com Canvas
Nesse momento, você deve estar se perguntando qual é a diferença do Canvas para uma
aplicação JavaFX comum, já que podemos fazer tudo isso no JavaFX. Bem, o Canvas é
uma tela de desenho, é ótimo para animações, jogos ou visualizações fantásticas. Já uma
aplicação JavaFX, temos como maior objetivo objetos que se aninham hierarquicamente e
são, no geral, estáticos, como essa página WEB. Desenhar essa página com o Canvas
seria um buta dor de cabeça, já usar controles e outras características do JavaFX torna o
serviço muito mais fácil.
56
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ó.
57
Gráficos
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:
58
Gráficos
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.
59
Gráficos
60
Gráficos
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 diferente: através de barras. Veja como o exemplo
anterior, de linhas, usando o mesmo conjunto de dados, mas em um gráfico de barras:
Claro que a API é muito avançada. Nesse pequeno livro vamos abordar o básico e cabê ao
leitor explorar as APIs mencionadas.
61
Abrindo páginas Web
A relação entre essas classes é simples: O WebView usa uma instância de WebEngine e
cria a representação visual de um conteúdo HTML na sua aplicação JavaFX. Mas como
usar os mesmo?
Usando WebView
O uso de WEBView consiste em três passos:
62
Abrindo páginas Web
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.web.WebView;
import javafx.scene.Scene;
@Override
public void start(Stage s) {
// O nó em sí, que será mostrado
WebView webView = new WebView();
// A engine é do tipo WebEngine
webView.getEngine().load("http://aprendendo-javafx.blogspot.com");
// criamos a cena e adicionamos no nosso stage
s.setScene(new Scene(webView));
// mostramos
s.show();
}
}
63
Abrindo páginas Web
Exatamente, meus caros amigos. Foram 3 linhas de código e uma página WEB na sua app
JavaFX.
Nessa aplicação temos uma lista de URLs no lado esquerdo e quando o usuário seleciona
uma, temos a mesma carregada no lado direito no nosso WEB View , vejam:
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.web.WebView;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.layout.HBox;
import java.util.stream.Stream;
/**
*
* @author william
*/
public class NavegaSites extends Application {
64
Abrindo páginas Web
@Override
public void start(Stage s) {
// criando uma lista visual de Strings, um webView e uma caixinha pra colocar
as coisas
ListView<String> listaSites = new ListView<>();
WebView webView = new WebView();
HBox raiz = new HBox(20);
// a lista não permite seleção de página quando uma página está sendo carregada
listaSites.disableProperty().bind(webView.getEngine().getLoadWorker().runningPrope
rty());
// formalidades...
raiz.getChildren().addAll(listaSites, webView);
s.setScene(new Scene(raiz));
s.show();
}
}
65
Tabelas com JavaFX
Nesse capítulo iremos mostrar o básico sobre criação de tabelas usando JavaFX.
Uma tabela tem colunas e linhas. Quando configuramos as colunas de uma TableView,
temos que também dizer como cada coluna vai representar os dados da tabela.
Itens
Os dados devem ser do tipo da declaração da tabela. Por exemplo, se declaramos uma
tabela usando:
66
Tabelas com JavaFX
tabela.setItems(FXCollections.observableArrayList(pessoas));
Caso você tente inserir dados de outro tipo, simplesmente você terá um erro de
compilação.
Colunas
As colunas são definidades pela classe TableColumn e devem saber lidar com cada linha
da tabela. Isso é feito através de fábricas de células, que são classes que recebem cada
item da tabela e retornam uma célula da tabela
. A fábrica você deve fornecer ou usar algumas colunas que já sabem fabricar as células de
um tipo já conhecido. Veja um exemplo onde criamos colunas para as propriedades nome,
idade e email de uma pessoa:
colunaNome.setCellValueFactory(new PropertyValueFactory<>("nome"));
colunaIdade.setCellValueFactory(new PropertyValueFactory<>("idade"));
colunaEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
package javafxpratico;
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
@Override
public void start(Stage primaryStage) {
67
Tabelas com JavaFX
colunaNome.setCellValueFactory(new PropertyValueFactory<>("nome"));
colunaIdade.setCellValueFactory(new PropertyValueFactory<>("idade"));
colunaEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
tabela.setItems(FXCollections.observableArrayList(pessoas));
tabela.getColumns().addAll(colunaNome, colunaIdade, colunaEmail);
primaryStage.setScene(new Scene(tabela));
primaryStage.setWidth(250);
primaryStage.setHeight(300);
primaryStage.setTitle("Tabelas no JavaFX");
primaryStage.show();
}
68
Tabelas com JavaFX
this.idade = idade;
}
}
}
69
Mudando o estilo com CSS
Exemplo
Criamos a seguinte aplicação de exemplo para que você possa ver o que abordamos
anteriormente na prática.
70
Mudando o estilo com CSS
Note que a aplicação está diferente. Isso é por que eu carreguei o arquivoapp.css na cena:
cena.getStylesheets().add("app.css");
.root{
-fx-base: darkblue;
-fx-background: lightblue;
}
.button {
-fx-font-weight: bold;
-fx-font-size: 15px;
}
.label {
-fx-font-style: italic;
-fx-font-size: 9px;
-fx-text-fill: darkgreen;
}
.titulo {
-fx-font-style: normal;
-fx-font-weight: bolder;
-fx-font-size: 30px;
-fx-alignment: center;
}
Também temos contéudos para o label lblTitulo que têm a classe titulo, que referenciamos
para modificar o estilo:
No código Java:
lblTitulo.getStyleClass().add("titulo");
Notem que alguns componentes já tem uma classe usado pelo próprio JavaFX, mas que
você pode modificar como quiser. No lado esquerdo podemos adicionar o CSS que
queremos e ao apertar o botão, esse CSS é aplicação no Text do lado direito.
71
Mudando o estilo com CSS
package javafxpratico;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
String txt = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
+ "Nunc porta erat id lectus interdum, a pharetra est luctus. "
+ "Nulla interdum convallis molestie. In hac habitasse platea "
+ "dictumst. Ut ullamcorper ultricies viverra. Quisque blandit "
+ "libero in ante sagittis sagittis. Ut gravida nibh quis justo "
+ "sodales rutrum. Fusce euismod diam diam, vitae vulputate urna"
+ " placerat vel. ";
raiz.setCenter(pnlCentro);
raiz.setTop(lblTitulo);
BorderPane.setAlignment(lblTitulo, Pos.CENTER);
72
Mudando o estilo com CSS
txtCSS.setMinWidth(350);
txtAlvo.setWrappingWidth(220);
btnAplicar.setMinWidth(120);
btnAplicar.setOnAction( event -> {
txtAlvo.setStyle(txtCSS.getText());
});
// configuramos classes para os nossos labels especiais
lblTitulo.getStyleClass().add("titulo");
// informamos o arquivo principal de CSS
cena.getStylesheets().add("app.css");
s.setScene(cena);
s.setTitle("Teste de CSS do JavaFX");
s.show();
}
73
Usando FXML
O uso de XML é possível no JavaFX para que possamos criar a GUI de uma aplicação e
então referenciar o mesmo no código Java. Os XMLs que contém componentes JavaFX são
chamados de FXML.
74
Usando FXML
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.effect.Effect;
import javafx.scene.effect.Reflection;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
@Override
public void start(Stage palco) throws Exception {
final Effect r = new Reflection();
final VBox raiz = new VBox(30);
final HBox hbTopo = new HBox(5);
final TextField txtNome = new TextField();
final Button btnAcao = new Button("Enviar");
final Label lblMensagem = new Label();
raiz.setTranslateX(10);
raiz.setTranslateY(10);
lblMensagem.setText("Digite seu nome e clique no botão");
hbTopo.getChildren().addAll(txtNome, btnAcao);
raiz.getChildren().addAll(hbTopo, lblMensagem);
lblMensagem.setEffect(r);
Scene cena = new Scene(raiz, 250, 100);
palco.setTitle("Aplicação usando código Java");
palco.setScene(cena);
palco.show();
Essa é uma aplicação simples, temos poucos componentes e um leiaute muito fácil de se
montar. Mas e quando temos aplicações cheia de controles e leiaute complexo?
75
Usando FXML
Usando FXML
Utilizar XML em interface gráfica não é uma novidade. O Pivot, um framework Java para
criação de aplicações desktop, e o Adobe Flex também utilizam esse conceito. A grande
vantagem do uso dessa linguagem declarativa está na possibilidade de usar uma
ferramenta para a geração da interface e a possibilidade de modificar o XML sem ter que
recompilar a aplicação inteira.
O JavaFX traz suporte ao FXML, uma forma de declarar todos os elementos de interface
sem escrever uma linha de código de Java. Veja como o programa que demonstramos
anteriormente ficaria com FXML:
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
Claro que o FXML também pode ser complexo e gigante, já falamos mais sobre isso. No
código Java acima é fácil adicionar ações ao botão e manipular os elementos da interface.
Mas como fazer com FXML?
O controller de um FXML
A lógica e o tratamento de eventos em uma aplicação JavaFX que usa FXML fica em uma
classe que referênciamos no próprio FXML, essa classe é chamada de controller. Nessa
classe podemos referenciar os elementos declarados no FXML para manipulação deles, lá
76
Usando FXML
também declaramos o método que irá tratar os eventos. Veja como fica o FXML completo e
pronto para uso com o nosso controller.
O código do controller ControleAplicacao está mais abaixo e ele tem declarado campos
correspondentes ao nosso TextField e Label. Notem que usamos a anotação @FXML no
campo, é ela que informa o nome do mesmo e o JavaFX injeta o campo declarado lá no
XML para nosso uso aqui! Veja o método atualizaMensagem também, é ele que é invocado
quando clicamos no botão.
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
@FXML
Label lblMensagem;
@FXML
TextField txtNome;
77
Usando FXML
@Override
public void start(Stage palco) throws Exception {
URL arquivoFXML = getClass().getResource(
"./ola-mundo.fxml");
Parent fxmlParent = (Parent) FXMLLoader.load(arquivoFXML);
palco.setScene(new Scene(fxmlParent, 300, 100));
palco.setTitle("Olá mundo com FXML");
palco.show();
}
}
Essa ótima ferramenta é mantida pela empresa Gluon e pode ser baixada no seguinte
endereço: http://gluonhq.com/labs/scene-builder
78
Usando FXML
79
Projeto: Um simples CRUD
Definição de CRUD
CRUD é uma sigla que vem das operações básicas que podemos fazer um algo
armazenado em uma fonte de dados:
Delete: Apagar.
O motivo de não usarmos um banco de dados tradicional é que o foco do artigo é mostrar
JavaFX. Um banco de dados comum implica em termos que falar de SQL, conexão com o
banco, select, etc, isso vai fugir do foco.
Nosso CRUD
Nossa aplicação simples vai ser um CRUD de Contas. Sim, bills, contas! Pagamos todo
mês contas de luz, água, gás, faturas, etc, etc, argh. Para representar a conta, criamos um
objeto Java chamado Conta com três atributos: id (gerado automaticamente para controle
interno), concessionária, descrição e data de vencimento. É isso, simples, não? Em breve
mostramos o código dessa classe, mas agoras que conhecemos os campos, veja a telinha
que modelamos usando o SceneBuilder que gerou um FXML (se não sabe o que é isso,
veja esse artigo sobre FXML, ou veja o capítulo Usando FXML).
80
Projeto: Um simples CRUD
Começamos com uma tabela com três colunas representando os campos, após a tabela
temos os campos de texto para entrada do nome, descrição e um campo para entrada de
data do tipo DatePicker, que não foi abordado nesse livro, e por fim os botões de ações.
A tabela tem ID tblContas e três colunas: clConc, clDesc e clVenc. Elas são
populadas com os dados de um objeto do tipo Conta;
Os campos de texto e o campo de data tem um (txtConc, txtDesc, dpVenc) serão
injetados no controller para que possamos saber o valor que o usuário entrou;
Cada um dos botões ação:
salvar: salva o objeto de acordo com a informação entrada pelo usuário. Não está
habilitado quando um campo está selecionado na tabela;
atualizar: Só está habilitado quando selecionamos uma linha da coluna e permite
atualizar os dados dessa linha (os campos de entrada de dados vão ser
atualizados com o valor selecionado para serem modificados pelo usuário);
apagar: apaga a linha selecionada;
limpar: limpa o campo selecionado atualmente.
As operações e os elementos da tela ficam na classe ContasController. Código que
veremos já já.
81
Projeto: Um simples CRUD
que retorna todas as contas selecionadas. É nessa classe que fazemos as operações.
Todo o código poderia ficar dentro do controller, MAS ISSO É COISA FEIA, temos que
definir os métodos em uma interface e, vejam que interessante, usando a capacidade do
Java 8 de definir métodos padrões, criamos um método getInstance para retornar a
implementação que queremos dessa interface. Assim, criamos a clase ContasCSVService,
que é uma implementação da interface, e retornamos uma nova instância nesse método!
Podemos, obviamente, criar uma interface, por exemplo ContasBDService que faria a
mesma coisa, mas que invés de usar um arquivo CSV, se comunica com um banco de
dados, a mesma ideia poderia ser aplicada para um arquivo XLS, como
ContasXLSService, e por aí vai. O código do controller, que os métodos da interface, não
iria sofrer nenhuma modificação, pois só precisaríamos trocar a intância de ContasService
retornada no método getNewInstance! (claro que com CDI e outras tecnologias, sequer
criar manualmente precisaríamos). Veja a nossa interface:
VAMOS AO CÓDIGO!
82
Projeto: Um simples CRUD
Agora, depois desse mooonnnntteee de papo, vamos ao código. Claro que se você leu
acima com atenção, vai ser muito simples de entender tudo, mas mesmo assim o código
está comentado na medida do possível.
Não vou colocar o todo código nesse capítulo, pois já está muito extenso, mas veja o código
da classe Conta, da interface ContasService e da classe ContasController. Note que você
pode encontrar o código no anexo javafx-pratico.zip _no pacote javafxpratico.crud_.
import java.util.Date;
/**
*
* Nossa classe de modelo do objeto que "sofrerá" as operações de CRUD
* @author wsiqueir
*
*/
public class Conta {
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.ResourceBundle;
import javafx.beans.binding.BooleanBinding;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
/**
*
* O controller da aplicação, onde a mágica acontece
* @author wsiqueir
*
*/
83
Projeto: Um simples CRUD
@FXML
private TableView<Conta> tblContas;
@FXML
private TableColumn<Conta, String> clConsc;
@FXML
private TableColumn<Conta, String> clDesc;
@FXML
private TableColumn<Conta, Date> clVenc;
@FXML
private TextField txtConsc;
@FXML
private TextField txtDesc;
@FXML
private DatePicker dpVencimento;
@FXML
private Button btnSalvar;
@FXML
private Button btnAtualizar;
@FXML
private Button btnApagar;
@FXML
private Button btnLimpart;
84
Projeto: Um simples CRUD
// método utilitário para pega a data que foi selecionada (que usa o tipo novo do
java 8 LocalDateTime)
private Date dataSelecionada() {
LocalDateTime time = dpVencimento.getValue().atStartOfDay();
return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
}
85
Projeto: Um simples CRUD
btnAtualizar.disableProperty().bind(algoSelecionado);
btnLimpart.disableProperty().bind(algoSelecionado);
// o botão salvar só é habilitado se as informações foram preenchidas e não te
m nada na tela
btnSalvar.disableProperty().bind(algoSelecionado.not().or(camposPreenchidos));
// quando algo é selecionado na tabela, preenchemos os campos de entrada com o
s valores para o
// usuário editar
tblContas.getSelectionModel().selectedItemProperty().addListener((b, o, n) ->
{
if (n != null) {
LocalDate data = null;
data = n.getDataVencimento().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
txtConsc.setText(n.getConcessionaria());
txtDesc.setText(n.getDescricao());
dpVencimento.setValue(data);
}
});
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
*
* Uma implementação do ContasService para lidar com arquivo CSV
* @author wsiqueir
*
*/
public class ContasCSVService implements ContasService {
// os dados do arquivo
private List<Conta> contas;
86
Projeto: Um simples CRUD
public ContasCSVService() {
carregaDados();
}
@Override
public void salvar(Conta conta) {
conta.setId(ultimoId() + 1);
contas.add(conta);
salvaDados();
}
@Override
public void atualizar(Conta conta) {
Conta contaAntiga = buscaPorId(conta.getId());
contaAntiga.setConcessionaria(conta.getConcessionaria());
contaAntiga.setDataVencimento(conta.getDataVencimento());
contaAntiga.setDescricao(conta.getDescricao());
salvaDados();
}
@Override
public List<Conta> buscarTodas() {
return contas;
}
@Override
public void apagar(int id) {
Conta conta = buscaPorId(id);
contas.remove(conta);
salvaDados();
}
87
Projeto: Um simples CRUD
e.printStackTrace();
System.exit(0);
}
}
88
Projeto: Um simples CRUD
Esse foi nosso projeto de exemplo. Não há nada demais nele, não com o código.
89
Conclusão
Conclusão
Chegamos ao fim do livro! Se você, nesse ponto, consegue criar aplicações simples com
JavaFX, se divertiu e está apto a repassar conhecimento desse livro para frente, então meu
objetivo foi concluído!
Há a ideia de novos livros com tópicos mais avançados. Mas só o tempo dirá se teremos ou
não!
90