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 )