
Tópicos na Parte 2
- Criar a Classe Model
- Usando a classe model em uma ObservableList
- Mostrar dados na TableView usando Controllers
Criar a Classe Model
Nós precisamos de uma classe model para guardar informação sobre as pessoas na nossa agenda. Adicione uma nova classe ao pacote model (ch.makery.address.model) chamado Person (pessoa). A classe Person (pessoa) terá um pouco de variáveis de instância para o nome, endereço e aniversário. Adicione o código seguinte à classe. Eu explicarei algumas coisas específicas do JAvaFX depois do código.
Person.java
package ch.makery.address.model;
import java.time.LocalDate;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
* Classe Model para uma Person (pessoa).
*
* @author Marco Jakob
*/
public class Person {
private final StringProperty firstName;
private final StringProperty lastName;
private final StringProperty street;
private final IntegerProperty postalCode;
private final StringProperty city;
private final ObjectProperty<LocalDate> birthday;
/**
* Construtor padrão.
*/
public Person() {
this(null, null);
}
/**
* Construtor com alguns dados iniciais.
*
* @param firstName Primeiro nome da Pessoa.
* @param lastName Sobrenome da Pessoa.
*/
public Person(String firstName, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
// Alguns dados de exemplo, apenas para testes.
this.street = new SimpleStringProperty("some street");
this.postalCode = new SimpleIntegerProperty(1234);
this.city = new SimpleStringProperty("some city");
this.birthday = new SimpleObjectProperty<LocalDate>(LocalDate.of(1999, 2, 21));
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public String getStreet() {
return street.get();
}
public void setStreet(String street) {
this.street.set(street);
}
public StringProperty streetProperty() {
return street;
}
public int getPostalCode() {
return postalCode.get();
}
public void setPostalCode(int postalCode) {
this.postalCode.set(postalCode);
}
public IntegerProperty postalCodeProperty() {
return postalCode;
}
public String getCity() {
return city.get();
}
public void setCity(String city) {
this.city.set(city);
}
public StringProperty cityProperty() {
return city;
}
public LocalDate getBirthday() {
return birthday.get();
}
public void setBirthday(LocalDate birthday) {
this.birthday.set(birthday);
}
public ObjectProperty<LocalDate> birthdayProperty() {
return birthday;
}
}
Explicações
- Com JavaFX é comum o uso de
Properties(propriedades) para todos os campos de uma classe model. UmaProperty(propriedade) nos permite, por exemplo ser notificado automaticamente quando olastName(sobrenome) ou qualquer outra variável seja mudada. Isso nos ajuda a manter a view sincronizada com os dados. Para aprender mais sobrePropertiesleia Usando Propriedades e Ligações de Propriedades no JavaFX. LocalDate, o tipo que nós estamos usando parabirthday(aniversário), é parte da nova API Data e Hora (Date and Time API) para JDK 8.
Uma Lista de Pessoas
Os principais dados que nossa aplicação gerencia é um monte de pessoas. Vamos criar uma lista para objetos Person dentro da classe MainApp. Todos as outras classes controller classes obterão acesso posteriormente à lista central dentro de MainApp.
ObservableList
Nós estamos trabalhando com classes view JavaFX que precisam de ser informadas sobre quaisquer mudanças feitas à lista de pessoas. Isto é importante, caso contrário a view não seria sincronizada com os dados. Para este propósito, JavaFX introduz algumas novas classes de Coleção.
Para aquelas coleções, nós precisamos da ObservableList. Para criar uma nova ObservableList, adicione o código seguinte ao começo da classe MainApp. Nós adicionaremos também um construtor que cria alguns dados de exemplo e um método getter público:
MainApp.java
// ... APÓS AS OUTRAS VARIÁVEIS ...
/**
* Os dados como uma observable list de Persons.
*/
private ObservableList<Person> personData = FXCollections.observableArrayList();
/**
* Construtor
*/
public MainApp() {
// Add some sample data
personData.add(new Person("Hans", "Muster"));
personData.add(new Person("Ruth", "Mueller"));
personData.add(new Person("Heinz", "Kurz"));
personData.add(new Person("Cornelia", "Meier"));
personData.add(new Person("Werner", "Meyer"));
personData.add(new Person("Lydia", "Kunz"));
personData.add(new Person("Anna", "Best"));
personData.add(new Person("Stefan", "Meier"));
personData.add(new Person("Martin", "Mueller"));
}
/**
* Retorna os dados como uma observable list de Persons.
* @return
*/
public ObservableList<Person> getPersonData() {
return personData;
}
// ... O RESTANTE DA CLASSE ...
O PersonOverviewController
Agora vamos finalmente colocar alguns dados em nossa tabela. Nós precisaremos de um controller para nosso PersonOverview.fxml.
- Criar uma classe normal dentro do pacote view chamada
PersonOverviewController.java. (Nós devemos colocá-la no mesmo pacote do que aPersonOverview.fxml, entretanto o SceneBuilder não o encontrará pelo menos não na versão atual). - Nós adicionaremos algumas variáveis de instância que nos dá acesso à tabela e às labels dentro da view. Os campos e alguns métodos tem uma anotação especial
@FXML. Isso é enecessário para o arquivo FXML ter acesso aos campos e métodos privados. Após nós termos tudo ajustado no arquivo FXML, a aplicação vai preencher automaticamente as variáveis quando o arquivo FXML é carregado. Então vamos adicionar o código abaixo:
PersonOverviewController.java
package ch.makery.address.view;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import ch.makery.address.MainApp;
import ch.makery.address.model.Person;
public class PersonOverviewController {
@FXML
private TableView<Person> personTable;
@FXML
private TableColumn<Person, String> firstNameColumn;
@FXML
private TableColumn<Person, String> lastNameColumn;
@FXML
private Label firstNameLabel;
@FXML
private Label lastNameLabel;
@FXML
private Label streetLabel;
@FXML
private Label postalCodeLabel;
@FXML
private Label cityLabel;
@FXML
private Label birthdayLabel;
// Reference to the main application.
private MainApp mainApp;
/**
* O construtor.
* O construtor é chamado antes do método inicialize().
*/
public PersonOverviewController() {
}
/**
* Inicializa a classe controller. Este método é chamado automaticamente
* após o arquivo fxml ter sido carregado.
*/
@FXML
private void initialize() {
// Inicializa a tablea de pessoa com duas colunas.
firstNameColumn.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
lastNameColumn.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
}
/**
* É chamado pela aplicação principal para dar uma referência de volta a si mesmo.
*
* @param mainApp
*/
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
// Adiciona os dados da observable list na tabela
personTable.setItems(mainApp.getPersonData());
}
}
Agora este código provavelmente vai precisar de explicação.:
- Todos os campos e métodos onde o arquivo fxml precisa de acesso devem ser anotados com
@FXML. Na verdade, omente se eles forem private, mas é melhor tê-los private e marcá-los com a anotação! - O método
initialize()é chamado automaticamente após o arquivo fxml ter sido carregado. Nessa hora, todos os campos FXML já devem ter sido inicializados. - O método
setCellValueFactory(...)que nós definimos nas colunas da tabela são usados para determinar qual campo dentro dos objetos dePersondevem ser usados para determinda coluna. A seta->indica que nós estamos usando um recurso do Java 8 chamado Lambdas. (Outra opção seria usar uma PropertyValueFactory, mas esta não é type-safe (segura por tipo)).
Conectando a MainApp com o PersonOverviewController
O método setMainApp(...) deve ser chamado pela classe MainApp. Isso nos dá uma maneira de acessar o objeto MainApp e obter a lista de Persons e outras coisas. Substitua o método showPersonOverview() pelo abaixo. Ele contém duas linhas adicionais:
MainApp.java - novo método showPersonOverview()
/**
* Mostra a person overview dentro do root layout.
*/
public void showPersonOverview() {
try {
// Carrega a person overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml"));
AnchorPane personOverview = (AnchorPane) loader.load();
// Define a person overview no centro do root layout.
rootLayout.setCenter(personOverview);
// Dá ao controlador acesso à the main app.
PersonOverviewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
Ligar a View ao Controller
Nós estamos quase lá. Mas uma pequena coisa está faltando: Nós não contamos ao nosso arquivo PersonOverview.fxml ainda, qual controller usar e qual elemento deve combinar com qual campo dentro do controller.
-
Abra
PersonOverview.fxmlcom o SceneBuilder. -
Abra o grupo Controller no lado direito e selecione
PersonOverviewControllercomo controller class.

-
Selecione a
TableViewno grupo Hierarchy e escolha no grupo Code o campopersonTablecomo fx:id.

-
Faça o mesmo para as colunas, selecione
firstNameColumnelastNameColumncomo fx:id respectivamente. -
Para cada label nas segunda coluna, escolha o fx:id correspondente.

-
Importante: Volta ao Eclipse e atualize (refresh) o projeto AddressApp inteiro project (F5). Isso é necessário porque o Eclipse às vezes não sabe sobre mudanças que foram feitas dentro do Scene Builder.
Inicie a Aplicação
Quando você iniciar a sua aplicação agora, você deve ver algo como o screenshot no começo deste post do blog.
Parabéns!
O Que Vem Depois?
No Tutorial Parte 3 nós adicionaremos mais funcionalidades como adicionar, deletar e editar Persons.