15 de ago de 2012

Controles Básicos de Interface III


Na terceira parte de nossa série sobre os controles do JavaFX, 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. Além do que mostrar como usar o controle, vamos ainda explorar os eventos que ele oferece,criando uma aplicação um pouco mais interessante do que algo inútil

Muitas opções, uma possível escolha

Os dois controles que vamos apresentar hoje funcionam de maneira muito semelhante, a maior diferença está na forma visual que elas são apresentadas dentro da sua aplicação. Ambas permitem que você faça a escolha de uma só opção entre diversas outras. no entanto, há uma pequena diferença visual entre elas e o ComboBox permite que você fabrique as células que serão mostradas. Criar fábrica de células é um assunto que facilmente ocuparia uma postagem inteira, você pode ver mais sobre isso aqui.
Para tratar dos dados individualmente da parte visual, usamos em ambas classes o conceito de SelectionModel, onde abstraimos a parte de seleção de dados. Temos duas abstrações: MultipleSelectionModel(permite selecionar vários itens ao mesmo tempo) e SingleSelectionModel(permite selecionar um único item ao mesmo tempo.
Hoje também vamos falar de um conceito novo e específico do JavaFX, então vamos nos limitar a mostrar o ComboBox e uma aplicação super simples, no entanto, o leitor deve pode acessar a documentação do ChoiceBox e criar a mesma aplicação usando ele. Enfim, vamos ao código!

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

package main;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
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;

public class Main extends Application {

 String cores[] = { "Blue", "Black", "Red", "White", "Green", "Yellow",
   "Gray", "Pink", "Salmon" };

 public static void main(String[] args) {

  launch();
 }

 @Override
 public void start(Stage palco) throws Exception {
  StackPane raiz = new StackPane();

  HBox opcoes = new HBox(10);
  opcoes.setAlignment(Pos.CENTER);

  final Rectangle retangulo = new Rectangle(300, 100);

  ComboBox cbCorCena = new ComboBox<>(); // 1
  ComboBox cbCorRetangulo = new ComboBox<>();

  cbCorCena.getItems().addAll(cores); // 2
  cbCorRetangulo.getItems().addAll(cores);

  opcoes.getChildren().addAll(cbCorCena, cbCorRetangulo);

  raiz.getChildren().addAll(retangulo, opcoes);

  final Scene cena = new Scene(raiz, 450, 250);
  palco.setTitle("Uso de ComboBox");
  palco.setScene(cena);
  palco.show();
  // 3
  cbCorCena.getSelectionModel().selectedItemProperty()
    .addListener(new ChangeListener() {
     @Override
     public void changed(
       ObservableValue valorObservado,
       String valorAntigo, String valorNovo) {
      cena.setFill(Color.valueOf(valorNovo));
     }

    });
  cbCorRetangulo.getSelectionModel().selectedItemProperty()
    .addListener(new ChangeListener() {
     @Override
     public void changed(
       ObservableValue valorObservado,
       String valorAntigo, String valorNovo) {
      // 4
      retangulo.setFill(Color.valueOf(valorNovo));
     }

    });
  cbCorCena.getSelectionModel().select(0); // 5
  cbCorRetangulo.getSelectionModel().select(1);
 }
}


  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;
  2. Nessa linha adicionamos os itens. Isso é feito de forma semelhante com a qual adicionamos itens a um componente pai como o Grupo, 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 Combox, 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;
  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.
Por fim, essa é a aplicação resultante:


Conclusão

Hoje nós mostramos o combobox e também apresentamos um conceito muito importante do JavaFX que são as "Properties". Você já deve ter percebido que há muito coisa a ser esclarecida e faremos isso aos poucos. 
Já está chegando o dia da nossa primeira aplicação do "mundo real", vamos apresentar mais alguns conceitos e em breve poderemos começar a criar coisas mais interessantes com JavaFX.

1 de ago de 2012

Controles Básicos de Interface II

Vamos para mais um post e nesse vamos falar sobre mais alguns controles de interface, especificamente sobre botões agrupados, mas que permitem a seleção individual, e também sobre a caixa de checagem, que representam um valor booleano (sim ou não, verdadeiro ou falso).

Várias possibilidades, uma escolha

Os botões de rádio, RadioButton, ou os botões alternados, ToggleButton, permitem apresentar um grupo de botão no qual é permitido selecionar somente um. Esse controle de não deixar dois botões serem selecionados é feito atráves de um grupo de botões, ToggleGroup, que recebe os mesmos e então controla o comportamento deles. 
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, alternativas de questões multivaloradas com uma resposta válida, entre outros.

Três estados, um controle

O segundo controle de interface que vamos mostrar hoje é simples e bastante utilizado em formulários para pedido de informações de usuários quando temos uma questão direta (exemplo: "Você Fuma?"). Estamos falando da caixa de checagem, CheckBox, que na verdade tem três estados: selecionado, não selecionado e indeterminado(você pode escolher se quer habilitar esse estado ou não). 
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 responde ou não marcou de propósito? 

A hora mais feliz

Vamos agora colocar esses botões em uma tela JavaFX e  mostrar algumas classes novas para posicionar os componentes. Vamos avançar um pouco o level, já são 5 tutoriais só com aplicações simples, temos que colocar um pouco mais de emoção e daqui a pouco já estaremos trabalhando com aplicações grandes com JavaFX. Enfim, como já está se tornando algo clássico do presente blog, vamos ao código e em seguida explicações dos pontos mais interessantes ou novos.
O programa abaixo representa um programa de uma pesquisa simples sobre programação. Com ele vamos mostrar o que discutimos nesse post e algumas coisas novas.


import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
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;

public class Principal extends Application {

 public static void main(String[] args) {
  launch();
 }

 @Override
 public void start(Stage palco) throws Exception {
  VBox raiz = new VBox(10);
  raiz.setTranslateX(10);
  raiz.setTranslateY(20);

  Label lblTitulo = new Label("Pesquisa sobre Programação");
  lblTitulo.setUnderline(true); // 1

  final TextField txtNome = new TextField();
  HBox hbNome = new HBox(10); // 2
  hbNome.getChildren().addAll(new Label("Nome"), txtNome);

  HBox hbSo = new HBox(20);
  ToggleButton tbLinux = new ToggleButton("Linux"); // 3
  tbLinux.setSelected(true);
  ToggleButton tbWindows = new ToggleButton("Windows");
  ToggleButton tbMac = new ToggleButton("Mac");
  final ToggleGroup tgSo = new ToggleGroup(); // 4
  tgSo.getToggles().addAll(tbLinux, tbWindows, tbMac); // 5
  hbSo.getChildren().addAll(new Label("Sistema Operacional utilizado"),
    tbLinux, tbWindows, tbMac);

  final ToggleGroup tgLinguagem = new ToggleGroup();
  HBox hbLinguagens = new HBox(20);
  RadioButton rbJava = new RadioButton("Java"); // 6
  rbJava.setSelected(true);
  RadioButton rbC = new RadioButton("C");
  RadioButton rbPython = new RadioButton("Python");
  tgLinguagem.getToggles().addAll(rbJava, rbC, rbPython);
  hbLinguagens.getChildren().addAll(
    new Label("Linguagem de programação Predileta:"), rbJava, rbC,
    rbPython);

  final CheckBox chkFrequencia = new CheckBox("Programa todo dia?"); // 7
  final CheckBox chkGosto = new CheckBox("Gosta de programação?");
  chkGosto.setAllowIndeterminate(true); // 8
  chkGosto.setIndeterminate(true);

  Button btnSubmeter = new Button("Submeter pequisa");
  btnSubmeter.setOnAction(new EventHandler() {

   @Override
   public void handle(ActionEvent evt) {

    System.out.println("\t\tResultado da pesquisa para \""
      + txtNome.getText() + "\"\n");
    // Podemos não ter um SO selecionado
    ToggleButton tbSo = (ToggleButton) tgSo.getSelectedToggle(); // 9
    System.out.print("Sistema Operacional predileto: ");
    System.out.println(tbSo == null ? "Não selecionado." : tbSo
      .getText());

    // Deve ter uma linguagem selecionada
    RadioButton rbLinguagem = (RadioButton) tgLinguagem
      .getSelectedToggle();
    System.out.println("Linguagem de programação: "
      + rbLinguagem.getText());
    // 10
    System.out.println((chkFrequencia.isSelected() == true ? "P"
      : "Não p") + "rograma todo dia.");

    System.out.print("Gosta de programação: ");
    if (chkGosto.isSelected()) {
     System.out.println("Sim.");
     // 11
    } else if (chkGosto.isIndeterminate()) {
     System.out.println("Não respondido.");
    } else {
     System.out.println("Não.");
    }
    System.out.println("\n\n");
   }
  });

  raiz.getChildren().addAll(lblTitulo, hbNome, hbSo, hbLinguagens,
    chkFrequencia, chkGosto, btnSubmeter);

  Scene cena = new Scene(raiz, 450, 250);
  palco.setTitle("Tratando eventos");
  palco.setScene(cena);
  palco.show();
 }
}


  1. Já começamos mostrando uma propriedade do Label. Se você chamar esse método e enviar true, ele será sublinhado;
  2. Esse componente é novo, mas o primo dele, VBox, funciona de forma muito semelhante. As propriedades são exatamente as mesmas, a diferença é que a HBox os componentes são organizados horizontalmente;
  3. Nessa linha estamos criando o tão falado botão alternado. Vamos usar três. Daqui a pouco teremos que adicionar ele a um grupo junto com outros botões alternados, assim somente um poderá ser escolhido nesse grupo, mas há a possibilidade de não escolher nenhum. Perceba que estamos informando no construtor o texto que ele irá mostrar;
  4. O grupo que falamos no passo anterior é representado pela classe ToggleGroup. Ele agrupo objetos do tipo Toggle, que é a classe pai do ToggleButton e do RadioButton;
  5. Nessa linha simplesmente adicionamos os botões já declarados para o grupo, dizendo que eles não podem ser selecionados simultaneamente;
  6. Semelhante ao ToggleBox, temos o RadioButton. A maior diferença está na aparência e que um grupo de RadioButton não permite um botão não selecionado;
  7. Aqui usamos uma caixa de checagem. A String enviada no construtor também é o texto associado a ela;
  8. Dizemos que essas caixas de checagem têm três estados. Nessa linha habilitamos o terceiro estado, o estado indeterminado (quântico?);
  9. Dentro do listener anônimo do botão, estamos lendo as propriedades dos controles de interface apresentados. Essa linha especificamente retorna o Toggle selecionado. Como sabemos que esse grupo contém toggles do tipo ToggleButton, já fazemos um "cast" para esse tipo. Se nada estiver selecionado, null é retornado;
  10. O isSelected retorna um valor booleano para informar se essa caixa está selecionada;
  11. Por fim(ufa), usamos o método isIndeterminate para sabermos se o estado dessa CheckBox é indeterminado.
Como sempre, você deve pode baixar o projeto anexado ao final do post para aprender mais e explorar esses novos componentes.

Conclusão

Mostramos mais alguns controles simples de interface, dessa vez os botões que dão ao usuário certa chance de escolha. Veja que após aprender campos de texto, botões e os organizadores de layouts que mostramos até agora, você já está apto a criar pequenas aplicações. Então, não perca tempo e nos mostre tudo o que vocês tem para oferecer.