I am trying to re-create the table view sample using scene builder 2, but my TableView couldn’t be populated.
I defined my table in JavaFx SceneBuilder like so:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="380.0" prefWidth="462.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="tableviewsample.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="325.0" layoutY="324.0" onAction="#handleButtonAction" text="Click Me!" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<TableView fx:id="table" layoutX="26.0" layoutY="29.0" prefHeight="221.0" prefWidth="411.0">
<columns>
<TableColumn fx:id="firstNameCol" prefWidth="75.0" text="First Name" />
<TableColumn fx:id="lastNameCol" prefWidth="75.0" text="Last Name" />
<TableColumn fx:id="emailCol" prefWidth="75.0" text="Email" />
</columns>
</TableView>
<TextField fx:id="addFirstName" layoutX="26.0" layoutY="284.0" prefHeight="25.0" prefWidth="81.0" promptText="First Name" />
<TextField fx:id="addLastName" layoutX="121.0" layoutY="284.0" prefHeight="25.0" prefWidth="89.0" promptText="Last Name" />
<TextField fx:id="addEmail" layoutX="222.0" layoutY="284.0" promptText="Email" />
</children>
</AnchorPane>
My controller code:
package tableviewsample;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
#FXML
private TableView<Person> table;// = new TableView<Person>();
#FXML private TableColumn firstNameCol ;
#FXML private TableColumn lastNameCol ;
#FXML private TableColumn emailCol ;
#FXML TextField addFirstName;
#FXML TextField addLastName;
#FXML TextField addEmail;
private final ObservableList<Person> data
= FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
data.add(new Person(
addFirstName.getText(),
addLastName.getText(),
addEmail.getText()));
addFirstName.clear();
addLastName.clear();
addEmail.clear();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
firstNameCol.setMinWidth(100);
lastNameCol.setMinWidth(100);
emailCol.setMinWidth(200);
table.getItems().setAll(this.data);
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
The main code:
package tableviewsample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TableViewSample extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Screenshot:
When I run it, there are empty rows in the table. If I type some values in the 3 TextFields and click the button, still the values are not inserted in the table.
Can you please find what's wrong with the code? Also, on an unrelated note, how can I make the table scrollable?
You haven't set any cellValueFactorys on your TableColumns (Example 12-5 in the tutorial you linked).
You can do this in FXML with
<TableColumn fx:id="firstNameCol" prefWidth="75.0" text="First Name" >
<cellValueFactory><PropertyValueFactory property="firstName"/></cellValueFactory>
</TableColumn>
or in the controller with
firstNameCol.setCellValueFactory(new PropertyValueFactory("firstName"));
(and similarly for the other columns)
You've actually made two mistakes.
First of all, you're trying to assign the datamodel to the TableView using getItems().setAll(). Take a look at the documentation of setAll(). It copies all the values of the given list into the ObservableList. This is not what you want, you want the TableView to start observing data and responding to changes. The way to do this is to assign a reference directly, through setItems(data).
Take a look at the code examples in the documentation of TableView. You forgot to connect the various StringProperties in Person up to the columns. This is the way they do it:
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
Lastly, I've got a little sidenote. Note that this is NOT the cause of your specific issue.
I see you're using raw types. This is generally considered a bad thing, and you're probably getting some warnings from the compiler about it. You can solve the issue by stating the generic types your objects use. Notice in the above code sample, I state for the PropertyValueFactories that the type of class contained within the TableView.items is Person and that the type of object displayed in the rows is String.
As for scrolling, which you also asked for, it does that automatically once there are enough lines in the TableView.
IN handle Mouse Button you can write:
/setItems();
follow the code of green tick above
Related
I am learning JavaFX FXML. In order to add data to TableView I add controller to FXMLLoader in a POJO class.
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/views/my_view.fxml"));
fxmlLoader.setController(controller);
try {
VBox myView = fxmlLoader.load();
controller.getInboxTable().setItems(getMyDisplayedItems());
//...
Root of FXML file has this definition:
<VBox fx:id="rootVBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
Thus, I can't specify controller in FXML file.
When I define Buttons in the same class I can't specify onMouseClicked because "No controller specified for top level element".
So, I can either populate TableView with data or attach action handler, but not both. What is the correct way to attach SortedList to TableView AND specify onAction in FXML?
If you want to use FXML, try to manage all the View layer's code there. You can add the controller in the FXML file via the fx:controller tag. Have a look at the Creating an Address Book with FXML at Oracle Docs. Most of the code below is from that tutorial.
Another thing is that using such a way of assigning the controller should fix the "No controller specified for top level element" issue. I added a button which causes the Table View's data is shuffled.
So, assuming you have all the files in the folder called sample in your project folder:
Main.java:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
#Override
public void start(final Stage stage) {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(Main.class.getResource("/sample/sample.fxml"));
try {
Parent root;
root = fxmlLoader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Application.launch(args);
}
}
sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<VBox fx:id="rootVBox"
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sample.Controller">
<Button text="Shuffle Data" onAction="#shuffleDataButtonClicked"/>
<TableView fx:id="tableView">
<columns>
<TableColumn text="First Name">
<cellValueFactory><PropertyValueFactory property="firstName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="Last Name">
<cellValueFactory><PropertyValueFactory property="lastName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="Email Address">
<cellValueFactory><PropertyValueFactory property="email" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</VBox>
Controller.java:
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
import java.util.Collections;
import java.util.Vector;
public class Controller {
#FXML
private TableView<Person> tableView;
#FXML
private void initialize() {
tableView.getItems().addAll(getSomePersonData());
}
private Vector<Person> getSomePersonData() {
Person jacobSmith = new Person("Jacob", "Smith", "jacob.smith#example.com");
Person isabellaJohnson = new Person("Isabella", "Johnson", "isabella.johnson#example.com");
Person ethanWilliams = new Person("Ethan", "Williams", "ethan.williams#example.com");
Person emmaJones = new Person("Emma", "Jones", "emma.jones#example.com");
Person michaelBrown = new Person("Michael", "Brown", "michael.brown#example.com");
Vector<Person> people = new Vector<>();
people.add(jacobSmith);
people.add(isabellaJohnson);
people.add(ethanWilliams);
people.add(emmaJones);
people.add(michaelBrown);
return people;
}
#FXML
private void shuffleDataButtonClicked() {
Collections.shuffle(tableView.getItems());
}
}
Person.java
package sample;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private final SimpleStringProperty firstName = new SimpleStringProperty("");
private final SimpleStringProperty lastName = new SimpleStringProperty("");
private final SimpleStringProperty email = new SimpleStringProperty("");
public Person() {
this("", "", "");
}
public Person(String firstName, String lastName, String email) {
setFirstName(firstName);
setLastName(lastName);
setEmail(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
i'm new to JavaFX and i want to print some BigDecimal and Bean in TableColumn in my TableView.
The issue is that i get a NullPointerExceptionexception when i try to setItems of the TableView.
Just to be clear i'm using the fxml with scenario builder for the graphic (panel, tableView, etc.) and the java class for link the bean's data to the tableView. I'm using the ObservableList for get the change, and the Bean has the correct getter that return ObjectProperty<BigDecimal> or ObjectProperty<ContoBean>.
I don't know if what i'm using for setCellValueFactory is correct, i've tryed to follow the tutorial here, but in this tutorial the TableColumn are set only as String. I've read some example for do the the setCellValueFactory, but as far as i can see the best procedure is to avoid using PropertyValueFactory and trying to stick to lambda expressions (more safe and keep the data type intact using a cellFactory, correct me if i'm wrong).
My question are:
What's the best practies for use setCellValueFactory of TableColumn with BigDecimal and Bean?
The best way is to create the TableColumns with scenario builder and link them with the controller or create only the TableView, in scenario builder, and create each single TableColumn in the java controller?
If i'm using a Bean that contains other Beans, how the TableColumn will represent the information? Which variable will be used for view the information, all of the Bean's variable or only a single one?
MovimentoOverview.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="900.0" prefWidth="1400.0" stylesheets="#DarkTheme.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="it.evil.money.view.MovimentoOverviewController">
<children>
<SplitPane dividerPositions="0.12857142857142856" prefHeight="300.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<TreeView layoutX="-9.0" layoutY="14.0" prefHeight="891.0" prefWidth="200.0" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0" />
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" styleClass="background">
<children>
<Label layoutX="14.0" layoutY="7.0" styleClass="label-header" text="Person Details" AnchorPane.leftAnchor="5.0" AnchorPane.topAnchor="5.0">
<font>
<Font size="18.0" />
</font></Label>
<ToolBar layoutX="216.0" layoutY="258.0" prefHeight="40.0" styleClass="background" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0">
<items>
<Button mnemonicParsing="false" onAction="#handleNewMovimento" text="New.." />
<Button mnemonicParsing="false" onAction="#handleEditMovimento" text="Edit.." />
<Button alignment="CENTER_RIGHT" mnemonicParsing="false" onAction="#handleDeleteMovimento" text="Delete.." textAlignment="CENTER" />
</items>
</ToolBar>
<TableView layoutX="5.0" layoutY="55.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="100.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="60.0">
<columns>
<TableColumn fx:id="idColumn" prefWidth="75.0" text="ID" />
<TableColumn fx:id="contoColumn" prefWidth="75.0" text="Conto" />
<TableColumn fx:id="dataColumn" prefWidth="75.0" text="Data" />
<TableColumn fx:id="valutaColumn" prefWidth="75.0" text="Valuta" />
<TableColumn fx:id="importoColumn" prefWidth="75.0" text="Importo" />
<TableColumn fx:id="quotaTicketColumn" prefWidth="75.0" text="Quota Ticket" />
<TableColumn fx:id="causaleColumn" prefWidth="75.0" text="Causale" />
<TableColumn fx:id="noteColumn" prefWidth="75.0" text="Note" />
<TableColumn fx:id="tipoPagamentoColumn" prefWidth="75.0" text="Tipo Pagamento" />
<TableColumn fx:id="tipoMovimentoColumn" prefWidth="75.0" text="Tipo Movimento" />
<TableColumn fx:id="spesaInComuneColumn" prefWidth="75.0" text="Spesa in Comune" />
<TableColumn fx:id="spesaPerLavoroColumn" prefWidth="75.0" text="Spesa per Lavoro" />
<TableColumn fx:id="utenteColumn" prefWidth="75.0" text="Utente" />
<TableColumn fx:id="tagColumn" prefWidth="75.0" text="Tag" />
<TableColumn fx:id="bustaPagaColumn" prefWidth="75.0" text="Busta Paga" />
</columns>
</TableView>
</children>
</AnchorPane>
</items>
</SplitPane>
</children>
</AnchorPane>
MovimentoOverviewController
package it.evil.money.view;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import java.math.BigDecimal;
import java.time.LocalDate;
import it.evil.money.MainApp;
import it.evil.money.model.BustaPagaBean;
import it.evil.money.model.CausaleBean;
import it.evil.money.model.ContoBean;
import it.evil.money.model.MovimentoBean;
import it.evil.money.model.TagBean;
import it.evil.money.model.TipoMovimentoBean;
import it.evil.money.model.TipoPagamentoBean;
import it.evil.money.model.UtenteBean;
import it.evil.money.util.DateUtil;
public class MovimentoOverviewController {
#FXML
private TableView<MovimentoBean> movimentoTable;
#FXML
private TableColumn<MovimentoBean, BigDecimal> idColumn;
#FXML
private TableColumn<MovimentoBean, ContoBean> contoColumn;
#FXML
private TableColumn<MovimentoBean, LocalDate> dataColumn;
#FXML
private TableColumn<MovimentoBean, String> valutaColumn;
#FXML
private TableColumn<MovimentoBean, BigDecimal> importoColumn;
#FXML
private TableColumn<MovimentoBean, BigDecimal> quotaTicketColumn;
#FXML
private TableColumn<MovimentoBean, CausaleBean> causaleColumn;
#FXML
private TableColumn<MovimentoBean, String> noteColumn;
#FXML
private TableColumn<MovimentoBean, TipoPagamentoBean> tipoPagamentoColumn;
#FXML
private TableColumn<MovimentoBean, TipoMovimentoBean> tipoMovimentoColumn;
#FXML
private TableColumn<MovimentoBean, Boolean> spesaInComuneColumn;
#FXML
private TableColumn<MovimentoBean, Boolean> spesaPerLavoroColumn;
#FXML
private TableColumn<MovimentoBean, BustaPagaBean> bustaPagaColumn;
#FXML
private TableColumn<MovimentoBean, UtenteBean> utenteColumn;
#FXML
private TableColumn<MovimentoBean, TagBean> tagColumn;
#FXML
private Label idLabel;
#FXML
private Label contoLabel;
#FXML
private Label dataLabel;
#FXML
private Label valutaLabel;
#FXML
private Label importoLabel;
// Reference to the main application.
private MainApp mainApp;
public MovimentoOverviewController() {
}
#FXML
private void initialize() {
idColumn.setCellValueFactory(cellData -> cellData.getValue().idProperty() );
contoColumn.setCellValueFactory(cellData -> cellData.getValue().contoProperty() );
dataColumn.setCellValueFactory(cellData -> cellData.getValue().dataProperty() );
valutaColumn.setCellValueFactory(cellData -> cellData.getValue().valutaProperty() );
importoColumn.setCellValueFactory(cellData -> cellData.getValue().importoProperty() );
quotaTicketColumn.setCellValueFactory(cellData -> cellData.getValue().quotaTicketProperty() );
causaleColumn.setCellValueFactory(cellData -> cellData.getValue().causaleProperty() );
noteColumn.setCellValueFactory(cellData -> cellData.getValue().noteProperty() );
tipoPagamentoColumn.setCellValueFactory(cellData -> cellData.getValue().tipoPagamentoProperty() );
tipoMovimentoColumn.setCellValueFactory(cellData -> cellData.getValue().tipoMovimentoProperty() );
spesaInComuneColumn.setCellValueFactory(cellData -> cellData.getValue().spesaInComuneProperty() );
spesaPerLavoroColumn.setCellValueFactory(cellData -> cellData.getValue().spesaPerLavoroProperty() );
bustaPagaColumn.setCellValueFactory(cellData -> cellData.getValue().bustaPagaProperty() );
utenteColumn.setCellValueFactory(cellData -> cellData.getValue().utenteProperty() );
tagColumn.setCellValueFactory(cellData -> cellData.getValue().tagProperty() );
}
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
movimentoTable.setItems(mainApp.getMovimentoData());
}
}
MainApp
package it.evil.money;
import java.io.IOException;
import it.evil.money.dao.DatabaseManager;
import it.evil.money.dao.MovimentoDao;
import it.evil.money.model.*;
import it.evil.money.view.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private ObservableList<MovimentoBean> movimentoData = FXCollections.observableArrayList();
private MovimentoDao movimentoDao;
public MainApp() {
movimentoDao = new MovimentoDao(DatabaseManager.getConnection());
// Instead of use a empty bean...
// movimentoData.add(new MovimentoBean());
// I get the data for db
movimentoData.addAll(this.movimentoDao.getAll());
this.movimentoDao.distruttore();
}
public ObservableList<MovimentoBean> getMovimentoData() {
return movimentoData;
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("AddressApp");
this.primaryStage.getIcons().add(new Image("file:resources/images/address_book_32.png"));
initRootLayout();
showMovimentoOverview();
}
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void showMovimentoOverview() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/MovimentoOverview.fxml"));
AnchorPane personOverview = (AnchorPane) loader.load();
rootLayout.setCenter(personOverview);
MovimentoOverviewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
MovimentoBean
package it.evil.money.model;
import java.time.LocalDate;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import java.math.BigDecimal;
public class MovimentoBean {
private final ObjectProperty<BigDecimal> id;
private final ObjectProperty<ContoBean> conto;
private final ObjectProperty<LocalDate> data;
private final StringProperty valuta;
private final ObjectProperty<BigDecimal> importo;
private final ObjectProperty<BigDecimal> quotaTicket;
private final ObjectProperty<CausaleBean> causale;
private final StringProperty note;
private final ObjectProperty<TipoPagamentoBean> tipoPagamento;
private final ObjectProperty<TipoMovimentoBean> tipoMovimento;
private final BooleanProperty spesaInComune;
private final BooleanProperty spesaPerLavoro;
private final ObjectProperty<BustaPagaBean> bustaPaga;
private final ObjectProperty<UtenteBean> utente;
private final ObjectProperty<TagBean> tag;
public MovimentoBean() {
this(null, null, null, null, null, null, null, null, null, null, false, false, null, null, null);
}
public MovimentoBean(BigDecimal id, ContoBean conto, LocalDate data, String valuta, BigDecimal importo,
BigDecimal quotaTicket, CausaleBean causale, String note, TipoPagamentoBean tipoPagamento,
TipoMovimentoBean tipoMovimento, boolean spesaInComune, boolean spesaPerLavoro, BustaPagaBean bustaPaga,
UtenteBean utente, TagBean tag) {
this.id = new SimpleObjectProperty<BigDecimal>(id);
this.conto = new SimpleObjectProperty<ContoBean>(conto);
this.data = new SimpleObjectProperty<LocalDate>(data);
this.valuta = new SimpleStringProperty(valuta);
this.importo = new SimpleObjectProperty<BigDecimal>(importo);
this.quotaTicket = new SimpleObjectProperty<BigDecimal>(quotaTicket);
this.causale = new SimpleObjectProperty<CausaleBean>(causale);
this.note = new SimpleStringProperty(note);
this.tipoPagamento = new SimpleObjectProperty<TipoPagamentoBean>(tipoPagamento);
this.tipoMovimento = new SimpleObjectProperty<TipoMovimentoBean>(tipoMovimento);
this.spesaInComune = new SimpleBooleanProperty(spesaInComune);
this.spesaPerLavoro = new SimpleBooleanProperty(spesaPerLavoro);
this.bustaPaga = new SimpleObjectProperty<BustaPagaBean>(bustaPaga);
this.utente = new SimpleObjectProperty<UtenteBean>(utente);
this.tag = new SimpleObjectProperty<TagBean>(tag);
}
public BigDecimal getId(){
return this.id.get();
}
public void setId(BigDecimal id){
this.id.set(id);
}
public ObjectProperty<BigDecimal> idProperty(){
return id;
}
......
When i start the program i get this error:
Exception in Application start method
java.lang.reflect.InvocationTargetException
.......
Caused by: java.lang.NullPointerException
at it.evil.money.view.MovimentoOverviewController.setMainApp(MovimentoOverviewController.java )
at it.evil.money.MainApp.showMovimentoOverview(MainApp.java )
at it.evil.money.MainApp.start(MainApp.java )
What i need:
Need an editable combobox which filters the data on the popup upon typing and first matching item should be highlighted and should set as the text in the combo upon pressing enter.
The popup should be a tableview with 2 or 3 columns. (screen shot attached.)(in the image it is a textfield but i prefer combo so that if the user is not sure about the values, he can click the combo button and see the entire list and select one.)
I will be binding some data as a source to the tableview which should act as the popup for the combobox.
I know i should go for a custom control but dont know where to start?
Reference URL: enter link description here
Thanks in Advance.
What i have tried so far:
Guys,
With the idea you guys gave, I have tried this so far and able to achieve.
(For now, i am not showing the tableview dynamically below the text field (eventually dats wat i want))
1. A tableview with static data is already loaded and added to the scene.
2. Having a text field below the tableview. (this is named as txt)
3. Having another text field below the first text field(this is named as txt1) (when i press tab from the previous text field cursor should come here)
i have a predicate set for the table and i am updating my predicate as the user types in the txt. (working)
Able to filter the table and the first matching row will highlighted. (working)
When the user press either "Tab" or "Enter" the highlighted row in the tableview should be set as the value in the txt.(working)
Needed:
1. When i press "Tab" or "Enter", the highlighted row will be set as the value in the text field (txt) and also the cursor should move to next focusable node. in my case it is the 2nd text field (txt1). I dont want to say txt1.requestFocus() bcoz in realtime, i have many text fields in the scene and this control will be a user control. so cant hardcode anything.
When the user types some text in the text field(not full text. eg: "do" where my table contains "Dom", "Don"), if there are multiple matches, currently both the records will be displayed in the table but the first one will be highlighted. User should be able to select the 2nd row if he wants by pressing the down arrow from the text field itself.
Main.java
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
VBox root = FXMLLoader.load(this.getClass().getResource("MainView.fxml"));
Scene scene = new Scene(root,500,300);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
MainController.java
package application;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Popup;
public class MainController implements Initializable
{
private #FXML TableView<Person> table;
private #FXML TableColumn<Person, String> firstNameCol;
private #FXML TableColumn<Person, String> lastNameCol;
private #FXML TableColumn<Person, String> emailCol;
private #FXML TableColumn<Person, Integer> ageCol;
private #FXML TextField txt;
private #FXML TextField txt1;
private #FXML Button btn;
#Override
public void initialize(URL location, ResourceBundle resources)
{
Platform.runLater(new Runnable() {
#Override
public void run() {
txt.requestFocus();
}
});
ObservableList<Person> obsList =FXCollections.observableArrayList();
obsList.add(new Person("Sam", "P1LasttName", "P1Email#gmail.com", 20));
obsList.add(new Person("Dom", "P2LasttName", "P2Email#gmail.com", 30));
obsList.add(new Person("Ken", "P3LasttName", "P3Email#gmail.com", 40));
obsList.add(new Person("Don", "P4LasttName", "P4Email#gmail.com", 50));
obsList.add(new Person("Tom", "P5LasttName", "P5Email#gmail.com", 60));
FilteredList<Person> filteredList = new FilteredList<>(obsList, p->true);
table.setItems(filteredList);
txt.textProperty().addListener((obs, oldValue, newValue) ->{
filteredList.setPredicate(person-> {
if(newValue == null || newValue.isEmpty())
return true;
if(person.getFirstName().trim().toLowerCase().contains(newValue.toLowerCase()))
return true;
return false;
});
Platform.runLater(new Runnable() {
#Override
public void run()
{
// we don't want repeated selections
table.getSelectionModel().clearSelection();
//get the focus
table.requestFocus();
//select first item in TableView model
table.getSelectionModel().selectFirst();
//set the focus on the first element
table.getFocusModel().focus(0);
//render the selected item in the TableView
//tableClickHandler(null);
}
});
Platform.runLater(new Runnable() {
#Override
public void run()
{
txt.requestFocus();
txt.end();
}
});
});
table.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event)
{
if(event.getCode() == KeyCode.ENTER)
{
txt.setText(table.getSelectionModel().getSelectedItem().getFirstName());
}
}
});
txt.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event)
{
if(event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)
//if(event.getCode() == KeyCode.ENTER)
{
txt.setText(table.getSelectionModel().getSelectedItem().getFirstName());
/*Platform.runLater(new Runnable() {
public void run() {
txt1.requestFocus();
}
});*/
}
}
});
/*txt.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event)
{
if(event.getCode() == KeyCode.TAB)
{
//txt.setText(table.getSelectionModel().getSelectedItem().getFirstName());
if(txt.getSkin() instanceof BehaviorSkinBase)
{
//((BehaviorSkinBase)txt.getSkin()).getBehavior().traverseNext();
BehaviorBase x = ((BehaviorSkinBase)txt.getSkin()).getBehavior();
((TextFieldBehavior)x).callAction("TraverseNext");
}
event.consume();
}
}
});*/
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event)
{
/*
Popup popup = new Popup();
popup.getContent().add(new TableView());
//popup.show(txt, txt.localToScreen(0, 0).getX() + txt.getWidth()/2, txt.localToScreen(0, 0).getY() + txt.getHeight());
popup.show(txt, txt.localToScreen(0, 0).getX(), txt.localToScreen(0, 0).getY() + txt.getHeight() + 2);
*/
Parent vbox = null;
try {
vbox = FXMLLoader.load(this.getClass().getResource("TableView.fxml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Popup popup = new Popup();
popup.getContent().add(vbox);
//popup.show(txt, txt.localToScreen(0, 0).getX() + txt.getWidth()/2, txt.localToScreen(0, 0).getY() + txt.getHeight());
//popup.show(txt, txt.localToScreen(0, 0).getX(), txt.localToScreen(0, 0).getY() + txt.getHeight() + 2);
popup.show(txt, txt.localToScreen(0, 0).getX(), txt.localToScreen(0, 0).getY() + txt.getHeight() + 2);
}
});
}
}
Person.java
package application;
public class Person
{
private String firstName;
private String lastName;
private String email;
private Integer age;
public Person(){}
public Person(String firstName, String lastName, String email, Integer age)
{
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.age = age;
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public Integer getAge()
{
return age;
}
public void setAge(Integer age)
{
this.age = age;
}
}
application.css
.table-row-cell:selected
{
-fx-background-color: lightgreen;
/* the below style will remove the border lines of the selected row */
-fx-table-cell-border-color: transparent;
}
MainView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.VBox?>
<!-- <?import application.Person?> -->
<VBox spacing="10.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
<children>
<TableView fx:id="table" prefHeight="250.0" prefWidth="437.0">
<columns>
<TableColumn fx:id="firstNameCol" prefWidth="120.0" text="First Name">
<cellValueFactory><PropertyValueFactory property="firstName" /></cellValueFactory>
</TableColumn>
<TableColumn fx:id="lastNameCol" prefWidth="120.0" text="Last Name">
<cellValueFactory><PropertyValueFactory property="lastName" /></cellValueFactory>
</TableColumn>
<TableColumn fx:id="emailCol" prefWidth="120.0" text="Email">
<cellValueFactory><PropertyValueFactory property="email" /></cellValueFactory>
</TableColumn>
<TableColumn fx:id="ageCol" prefWidth="75.0" text="Age">
<cellValueFactory><PropertyValueFactory property="age" /></cellValueFactory>
</TableColumn>
</columns>
</TableView>
<Button text="Button" fx:id="btn"/>
<TextField fx:id="txt" promptText="Type to Filter" />
<TextField fx:id="txt1" promptText="Focus should be here when tab is pressed from pervious txt" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
TableView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.VBox?>
<?import application.Person?>
<?import javafx.collections.*?>
<!--
<VBox xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65">
<children>
-->
<!-- <TableView xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:id="table" prefHeight="160.0" prefWidth="440.0"> -->
<TableView xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:id="table" prefHeight="140.0">
<columns>
<TableColumn fx:id="firstNameCol" prefWidth="120.0" text="First Name">
<cellValueFactory><PropertyValueFactory property="firstName" /></cellValueFactory>
</TableColumn>
<TableColumn fx:id="lastNameCol" prefWidth="120.0" text="Last Name">
<cellValueFactory><PropertyValueFactory property="lastName" /></cellValueFactory>
</TableColumn>
<TableColumn fx:id="emailCol" prefWidth="120.0" text="Email">
<cellValueFactory><PropertyValueFactory property="email" /></cellValueFactory>
</TableColumn>
<TableColumn fx:id="ageCol" prefWidth="75.0" text="Age">
<cellValueFactory><PropertyValueFactory property="age" /></cellValueFactory>
</TableColumn>
</columns>
<columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /></columnResizePolicy>
<items>
<FXCollections fx:factory="observableArrayList">
<Person firstName="P1FirstName" lastName="P1LasttName" email="P1Email#gmail.com" age="20"/>
<Person firstName="P2FirstName" lastName="P2LasttName" email="P2Email#gmail.com" age="30"/>
<Person firstName="P3FirstName" lastName="P3LasttName" email="P3Email#gmail.com" age="40"/>
<Person firstName="P4FirstName" lastName="P4LasttName" email="P4Email#gmail.com" age="50"/>
<Person firstName="P5FirstName" lastName="P5LasttName" email="P5Email#gmail.com" age="60"/>
</FXCollections>
</items>
</TableView>
<!--
</children>
</VBox>
-->
Any help is appreciated. Thanks!
I'm currently using an application that allows the user to search through given files for data they might look for, and everything works swimmingly.
The next implementation is to allow the user to populate their own data and save it to a separate file.
Since the view-area of the searched data is identical to how I would make a form for writing new data, I figured that I would just re-use the fields.
However, I have a TableView as one of the items, and I'm not certain how you extract the information from the table.
I was presuming that since the TableView is populated with a custom Row class that I could retrieve the set of Rows that make up the table and deconstruct them that way, but I cannot ascertain how this would best be done.
Concurrently, I'm trying to learn how to override elements of the TableView's cell factories to make the cells editable (because being editable doesn't do anything by default?), so that might be a place to consolidate strategy.
You just need to call getItems() on the table and iterate through the returned list. Assuming everything is set up in the normal "JavaFX way", any properties in the lists elements will be automatically updated by the editing mechanism.
Here is a complete, FXML-based example.
EditableTableExample.fxml (in package application):
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.cell.TextFieldTableCell?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1"
fx:controller="application.EditableTableViewController">
<center>
<TableView fx:id="table" editable="true">
<columns>
<TableColumn text="First Name" prefWidth="150"
fx:id="firstNameColumn">
<cellFactory>
<TextFieldTableCell fx:factory="forTableColumn" />
</cellFactory>
</TableColumn>
<TableColumn text="Last Name" prefWidth="150" fx:id="lastNameColumn">
<cellFactory>
<TextFieldTableCell fx:factory="forTableColumn" />
</cellFactory>
</TableColumn>
<TableColumn text="Email" prefWidth="150" fx:id="emailColumn">
<cellFactory>
<TextFieldTableCell fx:factory="forTableColumn" />
</cellFactory>
</TableColumn>
</columns>
</TableView>
</center>
<bottom>
<HBox alignment="CENTER">
<padding>
<Insets top="10" right="10" left="10" bottom="10" />
</padding>
<children>
<Button onAction="#showData" text="Show Data" />
</children>
</HBox>
</bottom>
</BorderPane>
EditableTableController:
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class EditableTableViewController {
#FXML
private TableView<Person> table ;
#FXML
private TableColumn<Person, String> firstNameColumn ;
#FXML
private TableColumn<Person, String> lastNameColumn ;
#FXML
private TableColumn<Person, String> emailColumn ;
public void initialize() {
firstNameColumn.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
lastNameColumn.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
emailColumn.setCellValueFactory(cellData -> cellData.getValue().emailProperty());
table.getItems().addAll(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
) ;
}
#FXML
private void showData() {
for (Person person : table.getItems()) {
String formatted = String.format("%s %s (%s)", person.getFirstName(), person.getLastName(), person.getEmail());
System.out.println(formatted);
}
System.out.println();
}
}
Model class Person:
package application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
private final StringProperty firstName = new SimpleStringProperty(this, "firstName");
public final String getFirstName() {
return firstNameProperty().get();
}
public final void setFirstName(String firstName) {
firstNameProperty().set(firstName);
}
public StringProperty firstNameProperty() {
return firstName ;
}
private final StringProperty lastName = new SimpleStringProperty(this, "lastName");
public final String getLastName() {
return lastNameProperty().get();
}
public final void setLastName(String lastName) {
lastNameProperty().set(lastName);
}
public StringProperty lastNameProperty() {
return lastName ;
}
private final StringProperty email = new SimpleStringProperty(this, "email");
public final String getEmail() {
return emailProperty().get();
}
public final void setEmail(String email) {
emailProperty().set(email);
}
public StringProperty emailProperty() {
return email ;
}
public Person(String firstName, String lastName, String email) {
this.setFirstName(firstName);
this.setLastName(lastName);
this.setEmail(email);
}
}
Application class:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class EditableTableViewExample extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("EditableTableExample.fxml"));
BorderPane root = loader.load();
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The button is just for demonstration, but pressing it will invoke the showData() method in the controller, which iterates through the table's list of items and retrieves the property values from each one. If you double-click a cell to edit, type to change the value, and then commit the edit with Enter, then pressing the button will show the updated values.
I currently using afterburner.fx to tailor together components of JavaFX based application.
Right now I trying move components in separate fxml files for more comfortable maintenance.
To load such components I using fx:include directive which allow load nested components automatically.
Problem is that with automatic load I loosing possibility get presenter from nested view.
Is there a way to combine automatic load and in same time, be able work with nested components from parent root?
These two seem to work fine together.
Afterburner works by setting a controller factory on the FXML loader, which takes care of instantiating the presenter class and injecting values into it.
The <fx:include> element will propagate the controller factory when loading the included FXML, so you can also inject values into the controller defined in the included FXML. Because afterburner effectively uses a singleton scope for injection, the same instance of injected fields will be used. This means you can readily share your data model between the different presenter classes.
If you want access to the presenter associated with the included FXML, just use the standard technique for "nested controllers".
So, for example:
main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="application.MainPresenter">
<center>
<TableView fx:id="table">
<columns>
<TableColumn text="First Name" prefWidth="150">
<cellValueFactory>
<PropertyValueFactory property="firstName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="Last Name" prefWidth="150">
<cellValueFactory>
<PropertyValueFactory property="lastName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="Email" prefWidth="200">
<cellValueFactory>
<PropertyValueFactory property="email" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</center>
<bottom>
<fx:include source="Editor.fxml" fx:id="editor">
<padding>
<Insets top="5" bottom="5" left="5" right="5"/>
</padding>
</fx:include>
</bottom>
</BorderPane>
editor.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<GridPane xmlns:fx="http://javafx.com/fxml" hgap="5" vgap="10" fx:controller="application.EditorPresenter">
<Label GridPane.rowIndex="0" GridPane.columnIndex="0" text="First Name:"/>
<TextField fx:id="firstNameTextField" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="Last Name"/>
<TextField fx:id="lastNameTextField" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
<Label GridPane.rowIndex="2" GridPane.columnIndex="0" text="Email"/>
<TextField fx:id="emailTextField" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<HBox GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2">
<Button fx:id="addEditButton" onAction="#addEdit" />
</HBox>
</GridPane>
MainPresenter.java:
package application;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
public class MainPresenter {
#FXML
private TableView<Person> table ;
// This is the controller (presenter) for the included fxml
// It is injected by the FXMLLoader; the rule is that "Controller" needs to be
// appended to the fx:id attribute of the <fx:include> tag.
// This is not used in this example but is here to demonstrate how to access it
// if needed.
#FXML
private EditorPresenter editorController ;
#Inject
private DataModel dataModel ;
public void initialize() {
table.setItems(dataModel.getPeople());
table.getSelectionModel().selectedItemProperty().addListener(
(obs, oldPerson, newPerson) -> dataModel.setCurrentPerson(newPerson));
dataModel.currentPersonProperty().addListener((obs, oldPerson, newPerson) -> {
if (newPerson == null) {
table.getSelectionModel().clearSelection();
} else {
table.getSelectionModel().select(newPerson);
}
});
dataModel.getPeople().addAll(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
}
}
EditorPresenter.java:
package application;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javax.inject.Inject;
public class EditorPresenter {
#FXML
private TextField firstNameTextField ;
#FXML
private TextField lastNameTextField ;
#FXML
private TextField emailTextField ;
#FXML
private Button addEditButton ;
#Inject
private DataModel dataModel ;
public void initialize() {
addEditButton.textProperty().bind(
Bindings.when(Bindings.isNull(dataModel.currentPersonProperty()))
.then("Add")
.otherwise("Update")
);
dataModel.currentPersonProperty().addListener((obs, oldPerson, newPerson) -> {
if (newPerson == null) {
firstNameTextField.setText("");
lastNameTextField.setText("");
emailTextField.setText("");
} else {
firstNameTextField.setText(newPerson.getFirstName());
lastNameTextField.setText(newPerson.getLastName());
emailTextField.setText(newPerson.getEmail());
}
});
}
#FXML
private void addEdit() {
Person person = dataModel.getCurrentPerson();
String firstName = firstNameTextField.getText();
String lastName = lastNameTextField.getText();
String email = emailTextField.getText();
if (person == null) {
dataModel.getPeople().add(new Person(firstName, lastName, email));
} else {
person.setFirstName(firstName);
person.setLastName(lastName);
person.setEmail(email);
}
}
}
MainView.java:
package application;
import com.airhacks.afterburner.views.FXMLView;
public class MainView extends FXMLView {
}
Main.java (application class):
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import com.airhacks.afterburner.injection.Injector;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
MainView mainView = new MainView();
Scene scene = new Scene(mainView.getView(), 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() throws Exception {
Injector.forgetAll();
}
public static void main(String[] args) {
launch(args);
}
}
DataModel.java:
package application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class DataModel {
private final ObservableList<Person> people = FXCollections.observableArrayList();
private final ObjectProperty<Person> currentPerson = new SimpleObjectProperty<>(this, "currentPerson");
public ObservableList<Person> getPeople() {
return people ;
}
public final Person getCurrentPerson() {
return currentPerson.get();
}
public final void setCurrentPerson(Person person) {
this.currentPerson.set(person);
}
public ObjectProperty<Person> currentPersonProperty() {
return currentPerson ;
}
}
And the usual Person.java example:
package application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
private final StringProperty firstName = new SimpleStringProperty(this, "firstName");
public final String getFirstName() {
return firstName.get();
}
public final void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName ;
}
private final StringProperty lastName = new SimpleStringProperty(this, "lastName");
public final String getLastName() {
return lastName.get();
}
public final void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName ;
}
private final StringProperty email = new SimpleStringProperty(this, "email");
public final String getEmail() {
return email.get();
}
public final void setEmail(String email) {
this.email.set(email);
}
public StringProperty emailProperty() {
return email ;
}
public Person(String firstName, String lastName, String email) {
setFirstName(firstName);
setLastName(lastName);
setEmail(email);
}
}