Olá Pessoal essa é uma postagem especial sobre como portar sua aplicação JavaFX para dispositivos Android!
Há um projeto do Johan Vos para trazer o suporte do JavaFX para o Android e iOs chamado JavaFX Ports e foi o destaque do JavaOne de 2014. O site contém todas as informações para transformar sua aplicação JavaFX 2.2 em uma app para Android, no entanto, o mesmo está em inglês.
Felizmente, nosso amigo Bruno de Oliveira, que tem um livro sobre JavaFX publicado na casa do código, fez um vídeo ensinando passo-a-passo como colocar sua aplicação JavaFX no Android, confiram:
30 de dez. de 2014
28 de ago. de 2014
Threads e JavaFX
Uma das coisas mais comuns que fazemos em nossa aplicação é executar algo "pesado". Por exemplo, usualmente lemos arquivos gigantes, acessamos páginas com muita informação, aguardamos a resposta do servidor, etc. Imagine que você queria fazer isso em paralelo na sua aplicação JavaFX, mas se deparada com erros. Como devemos proceder? Nesse artigo vamos falar como executar ações em paralelo na nossa aplicação sem causar transtorno aos nossos usuários.
Bem, esse código funciona, mas como ele trava a execução, a aplicação fica travada quando isso acontece:
Na imagem não fica nítido, mas a aplicação fica com o botão como se estivesse apertado. Como resolver isso?
Massa, agora não temos erro! No entanto, notem que essa thread que criamos está sob o controle do JavaFX, mas mesmo assim ela trava o botão... Como resolver isso de vez?
Task
As tasks são a solução! Com elas podemos executar algo em paralelo e pegar o resultado depois para sim atualizar a nossa aplicação. O funcionamento é simples, vamos focar em três principais métodos:
O nosso código está no github!
Um caso de uso
Imagine que temos uma aplicação que mostra o código de uma página HTML dentro de um campo de texto. Para pegar o código de uma página, temos que abrir uma conexão com uma URL, ler o InputStream e em seguida atualizar o campo de texto com o resultado. Vamos as nossas soluções.Caso 1: Abrir URL ao clique do botão
Nesse primeiro exemplo, iremos abrir a URL quando o usuário clicar no botão, veja o código:EventHandlercenario1 = e -> { try { txtResultado.setText(carregaPagina(txtUrl.getText())); } catch (Exception e1) { e1.printStackTrace(); } };
Bem, esse código funciona, mas como ele trava a execução, a aplicação fica travada quando isso acontece:
Na imagem não fica nítido, mas a aplicação fica com o botão como se estivesse apertado. Como resolver isso?
Caso 2: Abrir URL em uma thread separada
Essa solução é a mais óbvia para quem já tem um pouco de intimidade com Java. O que podemos fazer é simplesmente abrir a URL em uma thread separada e pronto! A operação de abrir a URL seria em paralelo e atualização do campo de texto só feita quando terminassemos de ler a URL, veja o código:
EventHandlercenario2 = e -> { Thread t = new Thread(() -> { try { txtResultado.setText(carregaPagina(txtUrl.getText())); } catch (Exception e1) { e1.printStackTrace(); } }); t.start(); };
Legal, mas ao clicar algumas vezes no botão teremos o seguinte erro:
java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
E agora?
Threads e JavaFX
O ponto é que como JavaFX é quem coordena a modificação da parte visual da aplicação, ele não deixa que coisas feitas em outra thread tente atuar diretamente na view, assim ele tem controle da atualização da tela. Claro que os desenvolvedores da API já sabiam que fazer coisas em paralelo eram normais, assim eles arrumaram uma forma de ajudar você a criar aplicações que tenham execução de tarefas pesadas e não travar a thread do JavaFX!Platform.runLater
Com esse método estático da classe Platform, podemos infomar ao JavaFX uma thread que será executada sob o controle dele, assim não teríamos o erro que tivemos no caso 2. Veja o nosso caso do clique:Massa, agora não temos erro! No entanto, notem que essa thread que criamos está sob o controle do JavaFX, mas mesmo assim ela trava o botão... Como resolver isso de vez?
Task
As tasks são a solução! Com elas podemos executar algo em paralelo e pegar o resultado depois para sim atualizar a nossa aplicação. O funcionamento é simples, vamos focar em três principais métodos:
- call: É onde fazemos nossa tarefa pesada. Esse médoto o JavaFX não está cuidando, logo não devemos alterar nada da view aqui;
- succeded: Quando há o sucesso na execução do método call, esse método é chamado e dele podemos pegar o resultado do call usando o método getValue;
- failed: Esse método já é chamado quando temos uma exceção na execução do método call. Nele também podemos pegar a exceção lançada com o método getExeception.
Pronto! Isso é o suficiente para começar a usar a Task, mas notem que um ponto importante é que a Task contém um tipo genérico, dessa forma temos segurança nos tipos dos dados e evitamos espalhar "casting" pelo código. Enfim, vamos ao nosso exemplo do botão com uma Task do tipo String:
EventHandlercenario4 = e -> { carregando.setVisible(true); Task tarefaCargaPg = new Task () { @Override protected String call() throws Exception { return carregaPagina(txtUrl.getText()); } @Override protected void succeeded() { String codigo = getValue(); carregando.setVisible(false); txtResultado.setText(codigo); } }; Thread t = new Thread(tarefaCargaPg); t.setDaemon(true); t.start(); };
Ótimo! Veja nossa aplicação final abaixo. Para deixar tudo mais legal, colocamos um ProgressIndicator, assim quando a página está sendo carregada, a opção de carregar nova página fica também desabilitada.
Conclusão
Mostramos como fazer atividades em paralelo no JavaFX não é um bicho de 7 cabeças.O nosso código está no github!
18 de ago. de 2014
[Especial] Eleições 2014: Uma aplicação em JavaFX e apresentando uma API Java
Novamente esse teremos teremos eleições no nosso Brasil. Essas eleições serão especiais não só pelo fato do Brasil ser mais consciente, mas por que nunca estivemos tão conectados.
Nesse clima eu criei essa aplicação média com JavaFX que faz uso de umaAPI de transparência para mostrar dados das eleições.
Embora eu tenha achado a aplicação muito interessante, devo deixar claro que essa aplicação não tem como objetivo substituir o ótimo DivulgaCand, do TSE, mas sim divulgar o projeto do pessoal do transparencia.org e também demonstrar um pouco do que aprendemos aqui nesse blog através de uma "aplicação do mundo real".
Veja um exemplo de uso do wrapper para listar todos candidatos ao governo de SP:
TransparenciaClient cli = new TransparenciaClient("{Sua chave}");
cli.getCandidatos("SP", "3", null, null).forEach(c -> {
System.out.printf("%s do partido %s para o cargo %s.\n",
c.getApelido(), c.getPartido(), c.getCargo());
Simples, não? Notem que no meu código eu deixei a minha chave, mas, por gentileza, não abusem ;) Conto com vocês! Deixei para facilitar para quem quer só executar a aplicação para testar.
Ao abrir a aplicação no netbeans e esperar ele importar as coisas certinhas, e executar a mesma com F6, você deverá ver:
Agora, vamos explicar algumas partes da aplicação e colocar links para aprofundamento do tópico envolvido:
--
Enfim, a paginação e a parte de rodar uma "task" no fundo não foram tratadas nesse blog, mas serão em breve. Veja o código completo para entender melhor:
Apresentamos uma aplicação com a qual você pode aprender JavaFX e ainda exercer sua cidadania! Mais uma vez eu peço por gentileza para não abusarem da minha chave da API :/
O código inteiro está no github e gostaria de salientar que a aplicação inteira foi feita em algumas horas, digamos 5 horas corridas, mas isso por que a mesma teve uma mudança de planos e foi reescrita... Um agradecimento especial a minha namorada Luana que ficou programando e desenvolvendo a aplicação comigo em pleno fim de semana! :*
Nesse clima eu criei essa aplicação média com JavaFX que faz uso de umaAPI de transparência para mostrar dados das eleições.
Embora eu tenha achado a aplicação muito interessante, devo deixar claro que essa aplicação não tem como objetivo substituir o ótimo DivulgaCand, do TSE, mas sim divulgar o projeto do pessoal do transparencia.org e também demonstrar um pouco do que aprendemos aqui nesse blog através de uma "aplicação do mundo real".
Uma API para busca de dados das eleições
Conforme relatei em meu blog pessoal, eu já tive a honra de criar uma API REST para expor os dados das eleições. Esse ano o pessoal do transparencia.org fez uma API muito e mais abrangente do a que eu tinha feito. O mais legal é que haverá um hackthon esse fim de semana com a API e há muitos exemplos de código e "wrappers" para facilitar o uso da mesma! Nessa postagem iremos usar um só método do Wrapper Java criado pelo Josué Eduardo.
Instalando e usando o "wrapper"
A nossa aplicação utiliza Maven e Java 8. Clone o wrapper usando git e então entre no diretório da aplicação e use o comando mvn install para que ela fique disponível para outras apĺicações maven. Assim, podems adicionar o seguinte à nossa aplicação com o objetivo de acessar as classes da API java do transparência:
Agora você tem tudo para começar a codificar Java e usar os dados da eleição, mas precisa de uma chave da API. A chave pode ser adquirida seguindo as instruções no site do dev.transparencia.org.br.Veja um exemplo de uso do wrapper para listar todos candidatos ao governo de SP:
TransparenciaClient cli = new TransparenciaClient("{Sua chave}");
cli.getCandidatos("SP", "3", null, null).forEach(c -> {
System.out.printf("%s do partido %s para o cargo %s.\n",
c.getApelido(), c.getPartido(), c.getCargo());
Simples, não? Notem que no meu código eu deixei a minha chave, mas, por gentileza, não abusem ;) Conto com vocês! Deixei para facilitar para quem quer só executar a aplicação para testar.
A aplicação JavaFX
A nossa aplicação JavaFX é um projeto maven também. Você pode clonar o código e importar no netbeans. Cuidado com o repositório maven configurado no Netbeans!Ao abrir a aplicação no netbeans e esperar ele importar as coisas certinhas, e executar a mesma com F6, você deverá ver:
Agora, vamos explicar algumas partes da aplicação e colocar links para aprofundamento do tópico envolvido:
Estrutura da aplicação
A App usa FXML e os campos do FXML são injetados no controller. É lá no controller que pegamos os dadosOs estados
Os estados sob a imagem do Brasil são Label que estão em um grupo. Na inicialização da aplicação temos um for nesses labels para registrar um listener que irá modificar o estado selecionado. Ao clicar no estado também carregamos uma imagem e o nome dele.Os cargos
Os cargos são botões do tipo ToggleButton. Quando um novo botão do grupo é selecionado, mudamos o cargo selecionado. Cada cargo tem um código e o código é "armazenado" no botão usando o UserData.Binding no cargo e estado selecionado
O cargo e o estado atualmente selecionados são armanezados em suas respectivas propriedades e quando há a mudança dos valores dos mesmos, iremos atualizar os dados da tabela.A tabela e a busca de dados
Quando há a mudança do estado ou do cargo, disparamos a busca com os novos valores. Quando está acontecendo a busca, temos uma propriedade que indica que os dados estão carregando, assim disabilitamos a tabela, a seleção de cargos e mostramos um ProgressIndicator usando binding.Paginação de dados
A API de transparência não nos deixa saber quantos candidatos temos, assim a paginação dos dados fica dificil, mas de qualquer forma, fizemos uma paginação com infinitas páginas, se não houver dados naquela página, não há erro, mas é uma requisição perdida ao servidor... Ao mudar a paginação também pedimos dados para o servidor.Estilo
Embora a aplicação não tenha sido muito modificada, temos um pequeno CSS para o estilo de algumas coisas. Aceitamos PR se você manjar da parte visual :D--
Enfim, a paginação e a parte de rodar uma "task" no fundo não foram tratadas nesse blog, mas serão em breve. Veja o código completo para entender melhor:
Próxima parte
Vamos voltar nesse blog com a segunda parte que é abrir uma telinha com detalhes de um candidato selecionado na tabela. Aceitaremos pull request!Conclusão
Apresentamos uma aplicação com a qual você pode aprender JavaFX e ainda exercer sua cidadania! Mais uma vez eu peço por gentileza para não abusarem da minha chave da API :/
O código inteiro está no github e gostaria de salientar que a aplicação inteira foi feita em algumas horas, digamos 5 horas corridas, mas isso por que a mesma teve uma mudança de planos e foi reescrita... Um agradecimento especial a minha namorada Luana que ficou programando e desenvolvendo a aplicação comigo em pleno fim de semana! :*
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.
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.
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:
Viu! O que temos acima é:
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:
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.
Código no Github.
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:
LineChartgraficoLinha = 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:
BarChartgraficoBarra = 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.
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:
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.
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.
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.
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:
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:
Bem, paramos por aqui, mas a javadoc é sua amiga. Leia por lá e navegue na API que em breve você está mestre nisso!
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:
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 ComboBoxcmbValores = 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:10 de ago. de 2014
Algumas boas práticas para criação de aplicações sérias com JavaFX
Olá Pessoal! Essa semana aconteceu o TDC 2014, edição de São Paulo. Eu tive a honra de mais uma vez palestrar e dessa vez eu coloquei um conteúdo mais avançado nos slides, que seriam boas práticas para criação de aplicações sérias JavaFX.
A apresentação em si não se limitou aos slides, pois falamos do JavaFX em geral e tivemos vários demos (como uma aplicação JavaFX que lê RFID), no entanto, nos slides abaixo vocês podem ter um gostinho sobre como foi a palestra.
A apresentação em si não se limitou aos slides, pois falamos do JavaFX em geral e tivemos vários demos (como uma aplicação JavaFX que lê RFID), no entanto, nos slides abaixo vocês podem ter um gostinho sobre como foi a palestra.
4 de ago. de 2014
Desenhando livremente com Canvas e o ColorPicker
Mostramos como desenhar formas geométricas com as classes que herdam de Shape. Essas formas, no entanto, ficam como nós separados no JavaFX. Como faremos se quisermos somente desenhar formas geométricas, textos e outras coisas livremente? Para isso temos o Canvas, uma classe muito interessante para desenharmos livremente!
E para gerar isso usamos o seguinte código:
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.
* Código no Github
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:E para gerar isso usamos o seguinte código:
// 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, altura) 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);
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.
Um mini paint com canvas
Nesse momento, já temos nossa missão cumprida! Pois apresentamos o componente que queríamos... No entanto, criamos uma aplicação um pouco mais complexa para demonstrar o poder desse componente: um micro paint. Vejam abaixo como é o nosso "paint":Trocando de cor
Um controle até agora não abordado, mas que foi adicionado no Java 8, é o ColorPicker. Ele é um controle que herda de nó e pode ser adicionada à cena da aplicação e o objetivo é permitir o usuário escolher uma cor em uma paleta de cores! Assim, quando o usuário escolhe a cor, temos a chamada de um método onAction com e o valor do componente muda, podemos assim saber a cor escolhida. Veja o código completo no github.
Conclusão
Não julgue o Canvas só por essa postagem, ele é um dos componentes mais poderosos do JavaFX!* Código no Github
3 de ago. de 2014
Organizando conteúdos com o Accordion
Mostramos anteriormente como organizar conteúdos em paineis de aba com o TabPane e como organizar o layout da aplicação. Hoje iremos mostrar mais um controle para organização de conteúdo, o Accordion.
Accordion
Semelhante ao TabPane, o Accordion é feito de paineis, mais especificamente de TitledPane. Para cada TitledPane adicionado ao controle, teremos um painel que pode ser expandido e, quando expandido, temos os outros retraídos. O conteúdo do TitledPane pode ser qualquer coisa, já que o conteúdo deve ser um nó. Veja:
Criando o Accordion
Quando criamos o Accordion, temos que levar em conta que usamos paineis do tipo TitledPane como os paineis do accordion. Assim, essa classe tem uma propriedade para os paineis e é ela que usamos para adicionar todos os paineis do accordion. Também podemos deixar um painel aberto por padrão usando o método setExpanded. Veja o código:
// criamos o Accordion Accordion accordion = new Accordion(); // criando os paineis do Accordion. Notem que o construtor recebe o // texto que vai aparecer e o nó TitledPane painel1 = new TitledPane("Painel 1", new Label( "O Primeiro Painel")); TitledPane painel2 = new TitledPane("Painel 2", new Button( "Sou um botão do painel 2")); TitledPane painel3 = new TitledPane("Painel 3", new Rectangle(150, 50)); // Adicionando um ícone ao Painel painel1.setGraphic(new ImageView(new Image(getClass() .getResourceAsStream("coracao.png")))); painel2.setGraphic(new ImageView(new Image(getClass() .getResourceAsStream("fogo.png")))); painel3.setGraphic(new ImageView(new Image(getClass() .getResourceAsStream("agua.png")))); // agora adicionamos todas as abas de vez accordion.getPanes().addAll(painel1, painel2, painel3); // aqui deixamos o painel que vai expandido por padrao accordion.setExpandedPane(painel1); // definimos um padrão mínimo para o painel ou ele vai se dimensionar de // acordo com o tamanho dos nós accordion.setMinSize(300, 300);
Conclusão
Apresentamos mais um controle, o Accordion. Veja o código no nosso github.1 de ago. de 2014
Organizando conteúdo em paineis com o TabPane
Anteriormente no nosso blog, apresentamos diversas formas de gerenciamento de layout:
Uma forma básica de se dispor conteúdo, no entanto, está em disponibilizar eles em paineis. Hoje vamos apresentar como apresentar conteúdos usando o TabPane.
Uma forma básica de se dispor conteúdo, no entanto, está em disponibilizar eles em paineis. Hoje vamos apresentar como apresentar conteúdos usando o TabPane.
TabPane
Para organizarmos os componentes em paineis acessados através de abas, podemos utilizar a classe TabPane, onde podemos adicionar paineis e o JavaFX automaticamente irá organizar eles em abas, veja:
Criando e customizando o TabPane
Criar um painel de Abas não é nada difícil. Você deve saber que a classe TabPane herda de nó e tem um atributo getTabs que retorna uma lista de abas, onde você pode adicionar instâncias de Tab, que representam uma Aba. Cada Aba tem como principais atributos o texto, um gráfico que representa um ícone e se a aba é "fechável" ou não. Veja abaixo como fica o código para criar o painel que mostramos acima:
// criamos o painel TabPane painelAbas = new TabPane(); // criando paineis de abas, o construtor recebe o nome da aba Tab aba1 = new Tab("Aba 1"); Tab aba2 = new Tab("Aba 2"); Tab aba3 = new Tab("Aba 3"); //configuramos o conteúdo de cada aba, que aceita qualquer tipo de Nó aba1.setContent(new Label("Configurando como conteúdo um label...")); aba2.setContent(new Button("Um botão de conteúdo")); aba3.setContent(new Rectangle(150, 50)); // abas podem ser fechadas, ou não. Por padrão elas são. aba1.setClosable(false); aba2.setClosable(false); aba3.setClosable(true); // podemos adicionar ícones as abas aba1.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("coracao.png")))); aba2.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("fogo.png")))); aba3.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("agua.png")))); // agora adicionamos todas as abas de vez painelAbas.getTabs().addAll(aba1, aba2, aba3);
Para o a instância do TabPane, temos um atributo que permite escolher o lado que a Aba pode ficar: em baixo, à esquerda, à direita ou acima (padrão). Isso é possível através do método setSide, que aceita um dos valores do Enum javafx.geometry.Side. Por exemplo, a chamada do método setSide(Side.BOTTOM) gera o seguinte:
Conclusão
Apresentamos o painel de Abas do JavaFX! O nosso próximo objetivo é o Accordion e aí fecharemos os principais controles. Acesse o código completo no github
Estamos próximos de cobrir todos os aspectos básicos do JavaFX! Os tópicos desse blog serão organizados em um mini ebook para principiantes na tecnologia e será disponibilizado gratuitamente!
31 de jul. de 2014
Estruturas de Árvore com TreeView
Um dos maiores usos de aplicações gráficas é para criação de aplicações onde o usuário interage através de controles. Já abordamos muitos controles aqui no blog:
Hoje iremos apresentar os controle TreeView!
- Rótulos, campos de texto, separadores e controles deslizantes
- Radio Button, CheckBox e ToggleButton
- ComboBox e ChoiceBox
- Tabelas
Hoje iremos apresentar os controle TreeView!
TreeView
TreeView é classe que usamos para visualizar dados em formatos de árvore ou com uma estrutura hierárquica(como uma estrutura de diretórios). Formado por células, podemos usar uma estrutura hierarquica onde uma célula pode ter outras células filhas. Veja:
Usando o TreeView
A classe TreeView, como muitos espertinhos já devem ter adivinhado, herda de Node, ou seja, podemos aplicar efeitos, rotacionar, etc... Veja uma a mesma árvore mostrada acima rotacionada e com um efeito de "Blur"
O elemento principal que se relaciona com o TreeView é o TreeItem, que representa os itens da árvore. Agora note algo interessante: um Item pode ter como filhinho vários outros items, assim criamos a estrutura de árvore. Ou seja, temos um item raiz e ele pode ter filhinhos, e os filhinhos, mais filhinhos, e assim vai... Na TreeView, só informamos o nó raiz. Enfim, veja o código que gerou a árvore acima:
O elemento principal que se relaciona com o TreeView é o TreeItem, que representa os itens da árvore. Agora note algo interessante: um Item pode ter como filhinho vários outros items, assim criamos a estrutura de árvore. Ou seja, temos um item raiz e ele pode ter filhinhos, e os filhinhos, mais filhinhos, e assim vai... Na TreeView, só informamos o nó raiz. Enfim, veja o código que gerou a árvore acima:
// a nossa árvore TreeViewarvore = new TreeView<>(); // Esse é o item raiz da nossa árvore. Embaixo dele temos que colocar // mais itens TreeItem raiz = new TreeItem ("Raiz"); // Os itens podem ser aninhados, abaixo criamos dois items filhos no // nível 1 e para cada um desses, três filhotes no nível 2 for (int i = 0; i < 2; i++) { TreeItem lvl1 = new TreeItem ("LVL1 " + i); for (int j = 0; j < 3; j++) { lvl1.getChildren().add(new TreeItem ("LVL2 " + j)); } raiz.getChildren().add(lvl1); } // você pode expandir para por padrão mostrar os filhos de um item. // Vamos fazer isso com a nossa raiz raiz.setExpanded(true); // agora setamos a raiz da nossa árvore arvore.setRoot(raiz);
Conclusão
Apresentamos mais um controle do JavaFX. O código pode ser visto no nosso github e usamos Java 8!
18 de jul. de 2014
Adicionando estilo à sua aplicação com CSS
Até o momento nesse blog fizemos aplicações e deixamos a "cara" delas a padrão que vem com o JavaFX, ou seja, não nos preocupamos em mudar a aparência das da nossa aplicação. Para fazer isso no JavaFX, não precisamos escrever código Java, mas sim conhecer CSS (Cascade Style Sheet), onde podemos declarativamente configurar a aparência de nossa aplicação.
CSS é uma linguagem declarativa onde identificamos os elementos da nossa aplicação e em seguida definimos valores para as propriedades suportadas para aquele componente.
Essa tecnologia já é utilizada em páginas WEB e para o JavaFX todas as possibilidades de uso do CSS estão descritas em um completo guia de referência.
No código Java:
btnAplicar.setOnAction( event -> {
txtAlvo.setStyle(txtCSS.getText());
});
Veja o código inteiro da nossa aplicação abaixo:
Como fica se quisermos aplicar CSS:
O que é e o que pode ser feito com CSS?
Com o CSS do javaFX é possível adicionar efeitos, mudar cores, dimensionar e completamente trocar a aparência da aplicação. É possível também definir a aparência quando o mouse fica sobre o elemento.CSS é uma linguagem declarativa onde identificamos os elementos da nossa aplicação e em seguida definimos valores para as propriedades suportadas para aquele componente.
Essa tecnologia já é utilizada em páginas WEB e para o JavaFX todas as possibilidades de uso do CSS estão descritas em um completo guia de referência.
Como referênciar os componentes do JavaFX no CSS?
Os componentes javafx podem ter várias classes CSS que referenciamos para usarmos na declaração do CSS. Assim, no código Java falamos qual a classe daquele componente e no CSS referenciamos a classe com ponto("."). Também podemos dar um id para nosso componente e referenciar a classe dele usando cerquilha ("#"). Note que o ID deve ser único, já a classe pode ser aplicada a diversos nós.Como carregar CSS no JavaFX?
O CSS pode ficar em um arquivo separado e ser carregado na Scene da aplicação ou podemos adicionar estilo a qualquer classe que estenda de nó (todas as classes de uma cena no JavaFX) usando o método setStyle.Exemplo
Criamos a seguinte aplicação de exemplo para que você possa ver o que abordamos anteriormente na prática.
Note que a aplicação está diferente. Isso é por que eu carreguei o arquivo app.css na cena:
cena.getStylesheets().add("app.css");
Esse arquivo configura o estilo raiz de toda a aplicação, veja o conteúdo:
.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;
}
-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");
No CSS:
.titulo {
-fx-font-style: normal;
-fx-font-weight: bolder;
-fx-font-size: 30px;
-fx-alignment: center;
}
No CSS:
.titulo {
-fx-font-style: normal;
-fx-font-weight: bolder;
-fx-font-size: 30px;
-fx-alignment: center;
}
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.
txtAlvo.setStyle(txtCSS.getText());
});
// imports omitidos public class TesteCSS extends Application { 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. "; public void start(Stage s) { // declarações BorderPane raiz = new BorderPane(); HBox pnlCentro = new HBox(50); VBox vbEsquerda = new VBox(10); VBox vbDireita = new VBox(10); Button btnAplicar = new Button("Aplicar CSS"); TextArea txtCSS = new TextArea(); Text txtAlvo = new Text(txt); Label lblTitulo = new Label("Testando CSS"); Scene cena = new Scene(raiz, 800, 250); // configurando Layout e adicionando componentes vbEsquerda.getChildren().addAll(new Label("Entre o CSS aqui"), txtCSS); vbDireita.getChildren().addAll(new Label("O texto Alvo"), txtAlvo); pnlCentro.getChildren().addAll(vbEsquerda, btnAplicar, vbDireita); pnlCentro.setAlignment(Pos.CENTER); raiz.setCenter(pnlCentro); raiz.setTop(lblTitulo); BorderPane.setAlignment(lblTitulo, Pos.CENTER); 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(); } }
Como fica se quisermos aplicar CSS:
Conclusão
Nesse artigo mostramos como é fácil mudar a aparência de nossas aplicaçõe usando JavaFX.
25 de jun. de 2014
[Especial] Outra app da Copa do Mundo... Usando JavaFX, FXML, Javascript e CSS
Olá pessoal, essa é uma postagem especial da copa do mundo onde faço uma tradução da minha postagem no blog fxapps.blogspot.com
Outra app da Copa do Mundo... Usando JavaFX, FXML, Javascript e CSS
A Copa do mundo Brasil está acontecendo! É empolgante ver pessoas de todas as partes do mundo visitando nosso pais. Hoje eu decidi criar outra app para a Copa do Mundo, usando JavaFX, mas dessa vez eu não irei escrever nenhum código Java.
É uma aplicação muito simples para visualizar todas as partidas da copa do mundo e quando você clica em um jogo, você tem detalhes do mesmo. Eu gastei menos de 3 horas trabalhando no "core" da aplicação e algumas horas mais trabalhando nos detalhes.
Adquirindo os recursos para criar a aplicação
Recursos quer dizer imagens and para adquiri elas eu baixei todas as imagens de bandeiras do site da Fifa. Fiz um pequeno e fácil scrapping. Note que todas as imagens seguem o seguinte padrão de URL: http://img.fifa.com/images/flags/4/{CODE}.png. Então, para baixar todas as bandeiras, fiz o seguinte script python:
import urllib2
codes = open('countries_codes.txt', 'r')
for line in codes:
code = line.replace('\n', '').lower() + '.png'
img_url = 'http://img.fifa.com/images/flags/4/' + code
print img_url
req = urllib2.Request(img_url)
response = urllib2.urlopen(req)
img = response.read()
f = open(code, 'w')
f.write(img)
codes = open('countries_codes.txt', 'r')
for line in codes:
code = line.replace('\n', '').lower() + '.png'
img_url = 'http://img.fifa.com/images/flags/4/' + code
print img_url
req = urllib2.Request(img_url)
response = urllib2.urlopen(req)
img = response.read()
f = open(code, 'w')
f.write(img)
Também utilizei a seguinte imagem como uma inspiração para nossa aplicação:
A view da aplicação
A view foi inteiramente criada no Scene Builder e foi dado estilos e id para os componentes da view, então, do Javascript nós podemos destacar algumas partes de acordo com as informações da copa.
Temos todos os jogos mostrados na aplicação e quando o usuários clica em um jogo, os detalhes do mesmo são mostrados em um painel:
O estilo da aplicação
Para mudarmos a aplicação para termos as cores do Brasil, usamos um simples arquivo CSS que também troca a aparência da partida quando passamos sobre ela:
.root{
-fx-base: CornflowerBlue;
-fx-background: rgb(227,231,239);
}
.TitledPane{
-fx-text-fill: FIREBRICK;
}
#match_details{
-fx-background-color: rgb(177,174,218);
}
.match:hover{
-fx-font: bold 12pt "Calibri";
-fx-effect: dropshadow(three-pass-box , blue, 20, 0.4 , 0 , 0 );
-fx-cursor: hand;
}
-fx-base: CornflowerBlue;
-fx-background: rgb(227,231,239);
}
.TitledPane{
-fx-text-fill: FIREBRICK;
}
#match_details{
-fx-background-color: rgb(177,174,218);
}
.match:hover{
-fx-font: bold 12pt "Calibri";
-fx-effect: dropshadow(three-pass-box , blue, 20, 0.4 , 0 , 0 );
-fx-cursor: hand;
}
A lógica
Como essa é uma aplicação temporal, não precisamos criar classes de modelo para representar os dados do jogo, então usamos somente Javascript para escrever a lógica da aplicação!
Uma boa alma raspou os dados da FIFA e disponibiliza eles em JSON. Nós lemos esse JSON e basicamente preenchemos a view com os dados que nele vem. Notem que para cada partida eu dei um ID(isso foi chato bagario) e do JSON que peguei, eu preencho os dados. Veja:
var matches = downloadMatchesInfo() ... function downloadMatchesInfo(){ print("Trying to download the matches information.........") var out, scanner try{ var urlStream = new java.net.URL(MATCHES_DATA_URL).openStream() scanner = new java.util.Scanner(urlStream, "UTF-8") // TODO: save the latest downloaded JSON }catch(e){ print("Couldn't download the updated information, using a cached one.....") scanner = new java.util.Scanner(new java.io.File(CACHED_DATA_URL), "UTF-8") } scanner.useDelimiter("\\A") out = scanner.next(); scanner.close(); return eval(out); }
Usando a função eval, transformamos a nossa String de resposta em um object Javascript para que possamos acessar os dados JSON diretamente. Para entender melhor, veja como as partidas são preenchidas:
function fillMatch(match){ var viewMatch = $STAGE.scene.lookup("#match_" + match.match_number) if(viewMatch && match.home_team.country){ viewMatch.children[0].image = getImg(match.away_team.code) viewMatch.children[1].text = match.status == "future"? "_": match.home_team.goals; viewMatch.children[3].text = match.status == "future"? "_": match.away_team.goals; viewMatch.children[4].image = getImg(match.home_team.code) } viewMatch.onMouseClicked = function(e){ fillMatchDetails(match) } } function getImg(code){ var imgUrl = code?"./images/teams/" + code.toLowerCase() + ".png":"./images/no_team.png" if(!imgCache[imgUrl]) imgCache[imgUrl] = new javafx.scene.image.Image(new java.io.FileInputStream(imgUrl)) return imgCache[imgUrl] }
Você pode ver no código acima como é fácil usar estruturas do Javascript em um código que lida com bibliotecas Java(veja a variável de cache de imagens chamada imgCache). Notem que quando o usuário clica em uma partida, registramos um listener para preencher os dados da partida em um painel central:
function fillMatchDetails(match){ var s = $STAGE.scene; detailsTransition.playFromStart() var notPlayedScore = match.status == "completed"?"0":"_" s.lookup("#match_home_team").image = getImg(match.home_team.code) s.lookup("#match_away_team").image = getImg(match.away_team.code) s.lookup("#match_home_score").text = match.home_team.goals?match.home_team.goals:notPlayedScore s.lookup("#match_away_score").text = match.away_team.goals?match.away_team.goals:notPlayedScore s.lookup("#match_status").text = "Match " + match.status s.lookup("#match_time").text = match.datetime.substring(0, 16) s.lookup("#match_location").text = match.location }
Por fim, vejam que invés de injetar os componentes em uma classe controller, decidimos pegar os elementos por ID usando o método lookup da Scene.
Rodando a aplicação
A aplicação não é compilada, é interpretada! Para rodar ela, você simplesmente precisa ter Java 8 instalado e no seu PATH assim você pode rodar a aplicação jjs para rodar a aplicação. Como o código está no github, você pode clonar it e já executar:
$ git clone https://github.com/jesuino/another-world-cup-app.git
$ cd another-world-cup-app
$ jjs -fx app.js
Você também pode editar o arquivo run.sh para configurar a variável JAVA_HOME e fazer o arquivo executável para rodar nossa app:
$ chmod +x run.sh
$ ./run.sh
Se você estiver no windows, minha namorada Luana testou a aplicação nesse "sistema operacional" e ela simplesmente criou um arquivo chamado run.bat com o seguinte conteúdo:
"C:\Program Files\Java\jre8\bin\jjs" -fx app.js
Note que você deve mudar o conteúdo desse arquivo de acordo com sua instalação.
Conclusão
Como você pode ver, é muito fácil criar aplicações JavaFX e não precisamos sequer escrever código Java! Usamos Javascript para ler o JSON e interagir com a view, o que se mostrou uma ótima abordagem, já que não precisamos usar nenhuma biblioteca de terceiros para lidar com o "parsing" de JSON.
Também ensinei minha namorada como rodar e mudar a aparência da aplicação e ela não é uma programadora Java. Isso mostra como aplicações JavaFX são acessíveis a todos os programadores.
Também ensinei minha namorada como rodar e mudar a aparência da aplicação e ela não é uma programadora Java. Isso mostra como aplicações JavaFX são acessíveis a todos os programadores.
20 de jun. de 2014
[Apresentação] JavaFX: Desktop para desenvolvedores WEB
26 de mai. de 2014
Adicionando efeitos à sua aplicação
Muitos efeitos vêm no JavaFX prontos para uso na sua aplicação! Nessa postagem vamos falar e demonstar os efeitos mais famosos da biblioteca gráfica do Java.
A API de efeitos
Conforme já falamos aqui, a classe nó tem um método chamado setEffect que aceita um parâmetro de tipo que herda da classe abstrata javafx.scene.effect.Effect. Essa classe é base de todos os efeitos que temos na API do JavaFX. Lembrando que por ser um nó, qualquer coisa em uma cena JavaFX pode receber efeitos: QUALQUER COISA. Algumas classes que herdam de Effect são listadas abaixo.- Reflection;
- Shadow;
- GaussianBlur;
- BoxBlur;
- Bloom;
- DisplacementMap;
- SepiaTone;
- MotionBlur;
- Outros Efeitos.
Uma aplicação de exemplo
Criamos uma aplicação de exemplo para testar os efeitos mais famosos do JavaFX em uma imagem. O código dessa aplicação está no github. A ideia da aplicação é que você possa ler a documentação e explorar os efeitos por sí próprio.
24 de abr. de 2014
Usando Tabelas com JavaFX: TableView
Um dos controles mais utilizados em aplicações cotidianas é a Tabela. Com controles que permitam visualizar dados em forma de tabelas podemos mostrar: lista de funcionários, de produtos, dados já ordenados em planilhas, informações diversas que vêm de algum servidor.
Nesse aspecto, estamos bem "servidos" com o TableView do JavaFX. A TableView, juntamente com a classe TableColumn, facilita visualizações de dados em uma aplicação JavaFX.
Nesse artigo, 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.
TableView<Pessoa> tabela = new TableView<>();
A tabela só irá aceitar dados do tipo Pessoa:
List<Pessoa> pessoas = ....
tabela.setItems(FXCollections.observableArrayList(pessoas));
Caso você tente inserir dados de outro tipo, simplesmente você terá um erro de compilação.
TableColumn<Pessoa, String> colunaNome = new TableColumn<>("Nome");
TableColumn<Pessoa, String> colunaIdade = new TableColumn<>("Idade");
TableColumn<Pessoa, String> colunaEmail = new TableColumn<>("E-mail");
tabela.getColumns().addAll(colunaNome, colunaIdade, colunaEmail);
Por exemplo, para acessar as propriedades do objeto Pessoa, podemos usar uma fábrica pronta, a PropertyValueFactory. Abaixo criamos as fábricas para as propriedades (atributos) da classe pessoa, note a String que ele recebe no construtor que é o nome da propriedade que declaramos na classe:
colunaNome.setCellValueFactory(new PropertyValueFactory<>("nome"));
colunaIdade.setCellValueFactory(new PropertyValueFactory<>("idade"));
colunaEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
Nesse aspecto, estamos bem "servidos" com o TableView do JavaFX. A TableView, juntamente com a classe TableColumn, facilita visualizações de dados em uma aplicação JavaFX.
Nesse artigo, iremos mostrar o básico sobre criação de tabelas usando JavaFX.
Visão geral da classe TableView
TableView é mais um controle de interface. Para começarmos falando dela, veja a seguinte imagem: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:TableView<Pessoa> tabela = new TableView<>();
A tabela só irá aceitar dados do tipo Pessoa:
List<Pessoa> pessoas = ....
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:TableColumn<Pessoa, String> colunaNome = new TableColumn<>("Nome");
TableColumn<Pessoa, String> colunaIdade = new TableColumn<>("Idade");
TableColumn<Pessoa, String> colunaEmail = new TableColumn<>("E-mail");
tabela.getColumns().addAll(colunaNome, colunaIdade, colunaEmail);
Por exemplo, para acessar as propriedades do objeto Pessoa, podemos usar uma fábrica pronta, a PropertyValueFactory. Abaixo criamos as fábricas para as propriedades (atributos) da classe pessoa, note a String que ele recebe no construtor que é o nome da propriedade que declaramos na classe:
colunaNome.setCellValueFactory(new PropertyValueFactory<>("nome"));
colunaIdade.setCellValueFactory(new PropertyValueFactory<>("idade"));
colunaEmail.setCellValueFactory(new PropertyValueFactory<>("email"));
Um exemplo completo de uso da TableView
Abaixo temos um código simples que mostra como mostrar uma lista de pessoas em uma TableView. Veja que não é nada sofisticado, mas com esse código, você já estará apto a construir suas próprias aplicações que usam tabelas.
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; /** * * @author william */ public class Post13Tabelas extends Application { @Override public void start(Stage primaryStage) { Listpessoas = Arrays.asList( new Pessoa("William", 32, "william@email.com"), new Pessoa("Luana", 17, "luana@email.com"), new Pessoa("Maria", 12, "maria@email.com"), new Pessoa("João", 15, "joao@email.com"), new Pessoa("Antônio", 28, "antonio@email.com"), new Pessoa("Teles", 17, "teles@email.com"), new Pessoa("Eduan", 30, "eduan@email.com"), new Pessoa("Gabu", 22, "gabu@email.com") ); TableView tabela = new TableView<>(); TableColumn colunaNome = new TableColumn<>("Nome"); TableColumn colunaIdade = new TableColumn<>("Idade"); TableColumn colunaEmail = new TableColumn<>("E-mail"); 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(); } public static class Pessoa { private String nome; private int idade; private String email; public Pessoa(String nome, int idade, String email) { this.nome = nome; this.idade = idade; this.email = email; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public int getIdade() { return idade; } public void setIdade(int idade) { this.idade = idade; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } }
Conclusão
Nesse breve artigo nós mostramos como criar tabelas em JavaFX. Claro que o tópico é extenso e podemos voltar ao tópico no futuro.
15 de abr. de 2014
Escrevendo aplicações JavaFX 8 usando Javascript
Uma das novidades mais legais do Java 8 é a nova engine javascript chamada "Nashorn". Com ela podemos escrever aplicações inteiras que usam JavaFX com a linguagem Javascript.
Hoje vamos mostrar aplicações simples para introduzir e apresentar esse conceito. Lembre que estamos usando a mais nova versão do Java, o Java 8.
* É requerido ter feito pelo menos o "Olá mundo" do JavaFX para seguir nessa postagem
Veja o uso da classe ScriptEngineManager para carregar a engine do Nashorn. Logo, carregamos o conteúdo do arquivo em um FileReader e interpretamos o script usando o método eval, mas antes disso colocamos o objeto stage no escopo do Javascript. Veja como ficou nosso script:
Note que se você quiser alterar a view, você simplesmente pode modificar o script sem ter que recompilar o seu código Java! Resultado:
Para executar ele, tenha o JDK 8 instalado e no seu "path", ou navegue até o diretório $JAVA_HOME/bin/ e encontre o executável do jjs e execute o seguinte comando:
$ jjs -fx helloJavaFX.js
Esse script produz o mesmo resultado do código anterior.
Caso você não queira escrever Java, nem Javascript, lembre-se que você poderá usar FXML e a ferramenta Scene Builder.
O código Javascript do Olá mundo está no github
Hoje vamos mostrar aplicações simples para introduzir e apresentar esse conceito. Lembre que estamos usando a mais nova versão do Java, o Java 8.
* É requerido ter feito pelo menos o "Olá mundo" do JavaFX para seguir nessa postagem
Carregando javascript a partir do Java
Através de sua aplicação, você pode colocar variáveis visíveis para o Javascript e do seu código Java chamar Javascript. O código abaixo é uma aplicação JavaFX que usa a engine para colocar o Stage principal no escopo do script Javascript e então chamamos um script do nosso sistema de arquivos com o resto do código da view:import javafx.application.Application; import javafx.stage.Stage; import javax.script.*; import java.io.FileReader; public class CarregaJS extends Application{ @Override public void start(Stage stage){ try{ ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.put("stage", stage); engine.eval(new FileReader("/opt/helloJavaFX.js")); }catch(Exception e){ e.printStackTrace(); } } }
Veja o uso da classe ScriptEngineManager para carregar a engine do Nashorn. Logo, carregamos o conteúdo do arquivo em um FileReader e interpretamos o script usando o método eval, mas antes disso colocamos o objeto stage no escopo do Javascript. Veja como ficou nosso script:
var txtOla = new javafx.scene.control.Label(">> Olá Mundo! <<") txtOla.font = new javafx.scene.text.Font(50) stage.scene = new javafx.scene.Scene(txtOla) stage.width = 500 stage.title = "Olá JavaFX + Javascript" stage.show()
Note que se você quiser alterar a view, você simplesmente pode modificar o script sem ter que recompilar o seu código Java! Resultado:
Carregando scripts usando a linha de comando
É possível usar a ferramenta jjs e escrever somente javascript. Para JavaFX especificamente, há um parâmetro que, quando usado, o Nashorn irá colocar uma variável chamada $STAGE para ser usada no seu script. Ela representa o stage principal da sua aplicação. Veja um "Olá Mundo" só com Javascript:var txtOla = new javafx.scene.control.Label(">> Olá Mundo! <<") txtOla.font = new javafx.scene.text.Font(50) $STAGE.scene = new javafx.scene.Scene(txtOla) $STAGE.width = 500 $STAGE.title = "Olá JavaFX + Javascript" $STAGE.show()
Para executar ele, tenha o JDK 8 instalado e no seu "path", ou navegue até o diretório $JAVA_HOME/bin/ e encontre o executável do jjs e execute o seguinte comando:
$ jjs -fx helloJavaFX.js
Esse script produz o mesmo resultado do código anterior.
Conclusão
Com Java 8 temos uma nova alternativa para escrever aplicações. Claro que o "Olá Mundo" é só o começo, mas teríamos que explorar a nova engine e sua compatibilidade com as APIs Java para construirmos grandes aplicações.Caso você não queira escrever Java, nem Javascript, lembre-se que você poderá usar FXML e a ferramenta Scene Builder.
O código Javascript do Olá mundo está no github
4 de mar. de 2014
Introdução ao FXML: Criando interfaces em JavaFX usando XML e o Scene Builder
Veja aqui um CRUD com JavaFX
Até agora nossas postagem utilizaram código Java na criação das interfaces gráficas(GUI). O uso de Java pode parecer atrativo a primeira vista, no entanto, o código pode se tornar complexo e de díficil manutenção, mas não é só em Java que podemos criar as telas.
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 JavaFX. Os XMLs que contém componentes JavaFX são chamados de FXML.
O modo Java de se fazer interfaces
Digamos que temos uma aplicação que contém um campo de texto, um botão e um campo de texto de leitura com uma saudação ao nome entrado. O código de interface para esse simples programa ficaria como segue:
public class DigaOlaComJava extends Application { public static void main(String[] args) { launch(); } @Override public void start(Stage palco) throws Exception { final Reflection 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(); btnAcao.setOnAction(new EventHandler() { @Override public void handle(ActionEvent arg0) { lblMensagem.setText("Olá, " + txtNome.getText() + ", bem vindo!"); } }); } }
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?
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(código no github):
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á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; public class ControleAplicacao { @FXML Label lblMensagem; @FXML TextField txtNome; public void atualizaMensagem() { lblMensagem.setText("Olá, " + txtNome.getText() + ", bem vindo!"); } }
Executando sua aplicação com FXML
Nesse momento, nossa aplicação está funcionando. Só precisamos carregar o FXML e isso é feito através da classe FXMLLoader, que lê o nosso arquivo .fxml e retorna um objeto do tipo Parent. Com ele é possível configurar a raiz da cena da aplicação, veja:
public class DigaOlaComFXML extends Application { public static void main(String[] args) { launch(); } @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(); } }
Criando interfaces visualmente com o Scene Builder
Falamos que com Java o projeto poderia ficar muito complexo, mas você pode perceber que o XML não é lá aquelas facilidades... Felizmente temos uma ferramenta onde podemos arrastar e soltar componentes para desenhar nossa tela. Em seguida, exportamos um arquivo .fxml para uso em nossa aplicação JavaFX! Veja uma imagem da ferramenta. (mais imagens e informações nesse blog)
Em uma postagem futura iremos trazer mais detalhes com relação ao uso do Scene Builder. O download pode ser feito no site da Oracle.O Scenebuilder deve ser baixado no site da empresa Gluon.
Vídeo
Abaixo um vídeo demonstrando o que falamos nesse breve artigo.
Conclusão
Criar interfaces com FXML traz agilidade e facilidade na criação de aplicações em JavaFX, além de forçar o usuário a separar bem sua lógica da construção da GUI.
O código da aplicação está no Github!
O código da aplicação está no Github!
Assinar:
Postagens (Atom)