Null pointer exception between controllers on calling a method javaFX - javafx

Hello I am working on a little project which javaFX, basically, I have two windows. the first one is the user account interface (Account.FXML) which allow the user to access his account and it contains an edit button that shows up the second window (edit.FXML) once is clicked. the second window allows the user to update his infos. what I want to do is to update the tableView in the first window when the user click on edit button in the second window so I am trying to call the UserDetails() metodh from the first window through communication between controllers but I get a Null pointer exception in (EditController.java) at line controller.UserDetails(); can you tell me how to fix this error ?
accountController.java:
public class accountController implements Initializable {
#FXML
private TableColumn<User, Integer> id;
#FXML
private TableColumn<User, String> username;
#FXML
private TableColumn<User, String> email;
#FXML
private TableColumn<User, String> password;
#FXML
private TableView<User> table;
public void userDetails() {
try {
userDao dao = new userDao();
ObservableList<User> list = dao.LoadAll();
id.setCellValueFactory(new PropertyValueFactory<>("id"));
username.setCellValueFactory(new PropertyValueFactory<>("username"));
email.setCellValueFactory(new PropertyValueFactory<>("email"));
password.setCellValueFactory(new PropertyValueFactory<>("password"));
table.setItems(list);
table.setEditable(true);
} catch (Exception ex) {
Logger.getLogger(AccountController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#FXML
void editUserDetails(ActionEvent event) {
UserModel item = table.getSelectionModel().getSelectedItem();
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Edit.fxml"));
Parent root = loader.load();
editController controller = (editController) loader.getController();
controller.txtId.setText(String.valueOf(item.getId()));
controller.txtId.setEditable(false);
controller.txtUserName.setText(item.getUserName());
controller.txtEmail.setText(item.getEmail());
controller.txtPassword.setText(item.getPassword());
Scene scene = new Scene(root);
scene.setFill(Color.TRANSPARENT);
Stage stage = new Stage();
stage.setScene(scene);
stage.initModality(Modality.APPLICATION_MODAL);
stage.initStyle(StageStyle.TRANSPARENT);
stage.showAndWait();
} catch (Exception ex) {
Logger.getLogger(ConsultationController.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void initialize(URL url, ResourceBundle rb) {
UserDetails();
}
}
account.FXML
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.home.accountController">
<children>
<TableView fx:id="table" layoutX="52.0" layoutY="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="col_id" prefWidth="50.0" text="id" />
<TableColumn fx:id="col_username" prefWidth="75.0" text="USER NAME" />
<TableColumn fx:id="col_email" prefWidth="180.0" text="Email" />
<TableColumn fx:id="col_password" prefWidth="180.0" text="Password" />
</columns>
</TableView>
<Button mnemonicParsing="false" onAction="#editUserDetails" prefHeight="40.0" prefWidth="261.0" styleClass="btnAdd" stylesheets="#style.css" text="Edit" />
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" />
</padding>
</AnchorPane>
editController.java
public class editController implements Initializable {
#FXML
protected TextField txtId;
#FXML
protected TextField txtUserName;
#FXML
protected TextField txEmail;
#FXML
protected TextField txtPassowrd;
#FXML
void update(ActionEvent event) {
int id = Integer.parseInt(txtId.getTexT());
String username = txtUserName.getText();
String email = txtEmail.getText();
String password = txtPassword.getText();
User user = new User();
user.setId(id);
user.setUserName(username);
user.setEmail(email);
user.setPassword(password));
try {
int count = userDao.getInstance().update(user); // userDao is the class that contains the SQL statement.
if (count == 1) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("account.fxml"));
accountController controller = (accountController) loader.getController();
controller.userDetails();
} else {
Alert error = new Alert(Alert.AlertType.ERROR, "Faild", ButtonType.OK);
error.showAndWait();
}
} catch (Exception ex) {
Logger.getLogger(EditController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
edit.FXML
<AnchorPane fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="589.0" prefWidth="600.0" style="-fx-border-width: 1px; -fx-border-color: black;" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.home.editController">
<HBox layoutX="137.0" layoutY="42.0" prefHeight="472.0" prefWidth="600.0" style="-fx-background-color: white;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="42.0">
<children> .
.
.
<Button fx:id="update" mnemonicParsing="false" onAction="#update" text="Update" />
<Button fx:id="exit" layoutX="10.0" layoutY="398.0" mnemonicParsing="false" onAction="#exit" text="Quitter" />
</children>
</HBox>
</children>
</AnchorPane>
user.java
public class User {
private final IntegerProperty id = new SimpleIntegerProperty();
private final StringProperty usename = new SimpleStringProperty();
private final StringProperty email = new SimpleStringProperty();
private final StringProperty password = new SimpleStringProperty();
public user(Integer id, String username, String email, String password) {
setId(id);
setUserName(username);
setEmail(email);
setPassword(Password);
}
public User() {
}
public final IntegerProperty IdProperty() {
return this.id;
}
public final java.lang.Integer getId() {
return this.IdProperty().get();
}
public final void setId(final java.lang.Integer id) {
this.idProperty().set(id);
}
public final StringProperty UserNameProperty() {
return this.username;
}
public final java.lang.String getUserNmae() {
return this.UserNameProperty().get();
}
public final void setUserName(final java.lang.String username) {
this.UserNameProperty().set(username);
}
public final StringProperty EmailProperty() {
return this.email;
}
public final java.lang.String getEmail() {
return this.EmailProperty().get();
}
public final void setEmail(final java.lang.String email) {
this.EmailProperty().set(email);
}
public final StringProperty PasswordProperty() {
return this.password;
}
public final java.lang.String getPassword() {
return this.PasswordProperty().get();
}
public final void setPassword(final java.lang.String Password) {
this.PasswordProperty().set(password);
}

Related

JavaFX getController not updating FXML controller

I have two controllers:
Main which contains TableView Tab which displays SQLITE database tables (which contain different number of columns) in tabular format, and
Rem which contains a button which dictates which database to display (there are many such controllers).
Now if I create a method in Main which is responsible for updating and displaying TableView contents, how do I use that method in other controller?
I created two static ObservableList variables columns and rows and bind them to Tab in Main's initialize.
APP.java
public class App extends Application {
private static Scene scene;
public static Connection conn;
#Override
public void start(Stage stage) throws IOException {
try{
conn=java.sql.DriverManager.getConnection("jdbc:sqlite:sample.db");
if(conn!=null){
conn.createStatement().execute("CREATE TABLE IF NOT EXISTS tab1(Field0 TEXT, Field1 TEXT, Field2 TEXT);");
conn.createStatement().execute("CREATE TABLE IF NOT EXISTS tab2(Field3 TEXT, Field4 TEXT);");
}
}catch(Exception ex){
System.out.println(ex);
}
scene = new Scene(loadFXML("main"), 640, 480);
stage.setScene(scene);
stage.show();
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
public static ResultSet getRS(String table){
String sql="SELECT * FROM "+table;
ResultSet rs=null;
try{
rs=conn.createStatement().executeQuery(sql);
}catch(Exception ex){
System.out.println(ex);
}
return rs;
}
}
MAIN.FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nic.testfx.Main">
<children>
<MenuBar>
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#loadRem" text="Load Remaining" />
</items>
</Menu>
</menus>
</MenuBar>
<TableView fx:id="Tab" prefHeight="200.0" prefWidth="200.0" />
<VBox fx:id="remPane" prefHeight="200.0" prefWidth="100.0" />
</children>
</VBox>
MAIN.JAVA
public class Main implements Initializable {
#FXML
public TableView<ObservableList<String>> Tab;
#FXML
private VBox remPane;
#Override
public void initialize(URL url, ResourceBundle rb) {
Tab.itemsProperty().bind(getTabRow());
}
public void makeTable(ResultSet rs){
try{
var rsm=rs.getMetaData();
ObservableList<TableColumn<ObservableList<String>,String>>cols=FXCollections.observableArrayList();
for(int i=0;i<rsm.getColumnCount();i++){
final int j=i;
TableColumn<ObservableList<String>,String> col=new TableColumn(rsm.getColumnName(i+1));
col.setCellValueFactory(param->new SimpleStringProperty(param.getValue().get(j)));
cols.add(col);
}
ObservableList<ObservableList<String>> arows=FXCollections.observableArrayList();
while(rs.next()){
ObservableList<String> row=FXCollections.observableArrayList();
for(int i=1;i<=rsm.getColumnCount();i++){
row.add(rs.getString(i));
}
arows.add(row);
}
setTable(cols,arows);
}catch(Exception ex){
System.out.println(ex);
}
}
private static final ObservableList<TableColumn<ObservableList<String>,String>> columns=FXCollections.observableArrayList();
private static final javafx.beans.property.ListProperty<ObservableList<String>> rows=new javafx.beans.property.SimpleListProperty();
private javafx.beans.property.ListProperty getTabRow(){
Tab.getColumns().clear();
Tab.getColumns().addAll(columns);
return rows;
}
private static void setTable(ObservableList<TableColumn<ObservableList<String>,String>>c,ObservableList<ObservableList<String>> r){
columns.setAll(c);
rows.set(r);
}
#FXML
private void loadRem(ActionEvent event) {
try{
for(int i=remPane.getChildren().size()-1;i>=0;i--){
remPane.getChildren().remove(i);
}
javafx.fxml.FXMLLoader fxmlLoader=new javafx.fxml.FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("rem.fxml"));
javafx.scene.layout.Pane panel=fxmlLoader.load();
remPane.getChildren().add(panel);
makeTable(App.getRS("tab1"));
}catch(Exception ex){
System.out.println(ex);
}
}
}
REM.FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>
<VBox alignment="CENTER" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nic.testfx.Rem">
<children>
<Button fx:id="btn" mnemonicParsing="false" onAction="#loadTab" text="Button" />
</children>
</VBox>
REM.JAVA
public class Rem implements Initializable {
#FXML
private Button btn;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void loadTab(ActionEvent event) {
try{
var fxml=new javafx.fxml.FXMLLoader(App.class.getResource("main.fxml"));
fxml.load();
Main controller=fxml.getController();
var rs=App.getRS("tab2");
controller.makeTable(rs);
}catch(Exception ex){
System.out.println(ex);
}
}
}
OK I got it.
Created a java class which encapsulate method makeTable:
MODEL.JAVA
public class Model{
private final TableView table;
public Model(TableView t){
this.table=t;
}
public void makeTable(ResultSet rs){
ObservableList<TableColumn<ObservableList<String>,String>>tabcols=FXCollections.observableArrayList();
ObservableList<ObservableList<String>>tabrows=FXCollections.observableArrayList();
//Create TableColumns and add to tabcols;
while(rs.next()){
//Create ObservableList<String>, get data from rs, and add to tabrows
}
this.table.getColumns().setAll(tabcols);
this.table.getItems().setAll(tabrows);
}
}
Next, in Controller file Main.java created a static instance of Model:
MAIN.JAVA
public class Main implements Initializable{
#FXML
private TableView<ObservableList<String>> Tab;
static Model model;
#Override
public void initialize (URL url, ResourceBundle rb){
model=new Model(Tab);
}
}
Now I can use model from Rem controller:
REM.JAVA
public class Rem implements Initializable{
#FXML
private Button btn;
#Override
public void initialize (URL url, ResourceBundle rb){
//TODO
}
#FXML
private void loadTab(ActionEvent event){
var rs=App.getRS("tab2");
Main.model.makeTable(rs);
}

JavaFX FXML include fxml causes NullPointerException

I want to extract a button to a new fxml file and change the main label with it. Without extraction it works perfectly.
main.fxml:
<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.example.MainController">
<Label fx:id="label" text="default"/>
<Button onAction="#changeLabel" text="sayHello" />
</VBox>
MainController:
public class MainController {
#FXML
private Label label;
#FXML
private void changeLabel() {
label.setText("Changed");
}
}
With extraction I get NullPointerException in MainController.changeLabel()
main.fxml with include:
<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.example.MainController">
<Label fx:id="label" text="default"/>
<fx:include source="button.fxml"/>
</VBox>
button.fxml:
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.example.MainController">
<Button onAction="#changeLabel" text="sayHello" />
</AnchorPane>
What can cause this NPE?
You should (almost?) always use a different class for controllers for different FXML files. (The only exception I can think of is if you want to define different FXML files to represent different layouts for the same controls.)
One approach is to inject the controller for the included FXML (the "Nested Controller") into the main controller. (See documentation.)
public class MainController {
#FXML
private Label label;
#FXML
private ButtonController buttonController ;
#FXML
private void initialize() {
buttonController.setOnButtonPressed(this::changeLabel);
}
private void changeLabel() {
label.setText("Changed");
}
}
public class ButtonController {
private Runnable onButtonPressed ;
public void setOnButtonPressed(Runnable onButtonPressed) {
this.onButtonPressed = onButtonPressed ;
}
public Runnable getOnButtonPressed() {
return onButtonPressed ;
}
#FXML
private void changeLabel() {
if (onButtonPressed != null) {
onButtonPressed.run();
}
}
}
And then the FXML files look like
<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.example.MainController">
<Label fx:id="label" text="default"/>
<fx:include fx:id="button" source="button.fxml"/>
</VBox>
and
<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.example.ButtonController">
<Label fx:id="label" text="default"/>
<fx:include source="button.fxml"/>
</VBox>
Generally speaking, it's a bad idea for controllers to have references to each other, as it breaks encapsulation and adds unnecessary dependencies. A better approach is to use a MVC design.
public class Model {
private final StringProperty text = new SimpleStringProperty() ;
public StringProperty textProperty() {
return text ;
}
public final String getText() {
return textProperty().get();
}
public final void setText(String text) {
textProperty().set(text);
}
}
Now you can do
public class MainController {
#FXML
private Label label;
private final Model model ;
public MainController(Model model) {
this.model = model ;
}
#FXML
private void initialize() {
label.textProperty().bind(model.textProperty());
}
}
and
public class ButtonController {
private final Model model ;
public ButtonController(Model model) {
this.model = model ;
}
#FXML
private void changeLabel() {
model.setText("Changed");
}
}
The FXML files are as above, and you need to specify a controller factory when you load the FXML (so that the controllers are instantiated by passing the model instance to the constructors):
final Model model = new Model();
FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/main.fxml");
loader.setControllerFactory(type -> {
if (type.equals(MainController.class)) return new MainController(model);
if (type.equals(ButtonController.class)) return new ButtonController(model);
throw new IllegalArgumentException("Unexpected controller type: "+type);
});
Parent root = loader.load();
// ...

JavaFX NullpointerException with FXML in own dialogbox when trying to close window

I am new to JavaFX. I programmed a tableview with a list of persons with their address. Everything worked fine. Then I wanted to write it in the MVC or even better the MVP Design pattern.
I am working with FXML and scenebuilder to layout the scenes.
Now with the MVC I have the problem that I get a NUllpointerException when i.e. I wanna close the confirm dialog box.
And I also can't change the labeltext for the confirmdialog window scene.
I think I know what the problem is but don't know how to solve this properly. The controller gets instantiated twice and therefore the first values of the variables form the fxml are NUll.
So this is how I wrote my little app:
MiniTest.java - my main App
package AddressBook;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MiniTest extends Application {
private static Stage window;
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Adresslist of Clients");
Model model = new Model();
try {
FXMLLoader mainViewloader = new FXMLLoader(getClass().getResource("View.fxml"));
Parent root = (Parent) mainViewloader.load();
MainController mainController = mainViewloader.<MainController>getController();
window.setScene(new Scene(root));
window.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Stage getPrimaryStage() {
return window;
}
public static void main(String[] args) {
launch(args);
}
}
Model.java - this is my model, not sure if the content has to be in here. For the next step I wanna collect the data from a mysql db and save it to the db. For now I have the persons like this.
package AddressBook;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Model {
public ObservableList<Person> getPerson() {
ObservableList<Person> personList = FXCollections.observableArrayList();
Address addressPerson1 = new Address("Jaguarweg 12", "23454", "Bensheim");
Address addressPerson2 = new Address("Friedrich-Ebert-Str. 134", "82635", "Berlin");
Address addressPerson3 = new Address("Adam-Opel-Str. 1", "92364", "Bamberg");
Address addressPerson4 = new Address("Power-Shell-Pfad 21", "10083", "Hamburg");
Address addressPerson5 = new Address("Schwertstr. 76", "749236", "Stuttgart");
Address addressPerson6 = new Address("Hans-Jacob-Weg 4", "66396", "Wiesbaden");
Address addressPerson7 = new Address("Georg-Lucas-Str. 110", "53421", "Wien");
Address addressPerson8 = new Address("Andalusienweg 17", "723612", "Ostfildern");
Address addressPerson9 = new Address("Mercedes-Benz-Str. 9", "883621", "Wolfsburg");
Address addressPerson10 = new Address("Heinrich-Schwein-Str. 43", "134923", "Frankfurt");
Address addressPerson11 = new Address("Engel-Teufel-Str. 66", "083273", "Hildesheim");
personList.add(new Person("Georg Sorresto", addressPerson1));
personList.add(new Person("Flynn Bozzen", addressPerson2));
personList.add(new Person("Bill Klang", addressPerson3));
personList.add(new Person("Wilhelm Busch", addressPerson4));
personList.add(new Person("Gertrud Raven", addressPerson5));
personList.add(new Person("Markus Berg", addressPerson6));
personList.add(new Person("Juergen Schmidt", addressPerson7));
personList.add(new Person("Fritz Titz", addressPerson8));
personList.add(new Person("Bodo Bambino", addressPerson9));
personList.add(new Person("Ortrun Giner", addressPerson10));
personList.add(new Person("Jakob Huber", addressPerson11));
return personList;
}
}
Person.java - my Person class
package AddressBook;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private SimpleStringProperty name;
private Address address;
public Person() {
this.name = new SimpleStringProperty("");
this.address = new Address("", "", "");
}
public Person(String name, Address address) {
this.name = new SimpleStringProperty(name);
;
this.address = address;
}
public String getName() {
return name.get();
}
public void setName(String name2) {
name.set(name2);
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
In MainController.java - for certain things like closing the window or for deleting a person I call a method like this as my own confirmdialogwindow with corresponding String for the Label.
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
and here is the full MainController.java - this is the mainController for the mainView(View.fxml)
package AddressBook;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Callback;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController implements Initializable {
#FXML
private MenuItem exitMenu;
#FXML
private TableView<Person> personTable;
#FXML
private TextField zipInput;
#FXML
private TextField cityInput;
#FXML
private TextField streetInput;
#FXML
private TextField nameInput;
#FXML
private TableColumn<Person, String> cityColumn;
#FXML
private TableColumn<Person, String> zipColumn;
#FXML
private TableColumn<Person, String> streetColumn;
#FXML
private TableColumn<Person, String> nameColumn;
#FXML
private Button addButton;
#FXML
private Button deleteButton;
#FXML
private SimpleStringProperty message;
private Stage window;
private ConfirmDialogBoxController confirmDialogBoxController;
private AlertEmptyNameController alertEmptyNameController;
private Model model;
public MainController(){
model = new Model();
System.out.println("+1 MainController()");
}
public MainController(Model model){
this.model = model;
System.out.println("+1 MainController(model)");
}
#Override
public void initialize(URL location, ResourceBundle resources) {
Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory = (TableColumn<Person, String> p) -> new MainController.EditingCell();
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
nameColumn.setCellFactory(cellFactory);
nameColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setName(t.getNewValue());
}
);
streetColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getStreet()));
streetColumn.setCellFactory(cellFactory);
streetColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setStreet(t.getNewValue());
});
zipColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getZip()));
zipColumn.setCellFactory(cellFactory);
zipColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setZip(t.getNewValue());
});
cityColumn.setCellValueFactory(person -> new
SimpleStringProperty(person.getValue().
getAddress().
getCity()));
cityColumn.setCellFactory(cellFactory);
cityColumn.setOnEditCommit(
(
TableColumn.CellEditEvent<Person, String> t) ->
{
((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setCity(t.getNewValue());
});
personTable.setItems(model.getPerson());
personTable.setEditable(true);
MiniTest.getPrimaryStage().setOnCloseRequest(e -> {
try {
e.consume();
closeWindow(e);
} catch (IOException ex) {
ex.printStackTrace();
}
});
}
public SimpleStringProperty getMessageProperty(){
return message;
}
public void setMessage(String message) {
this.message.setValue(message);
}
public String getMessage() {
return this.message.getValue();
}
#FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
#FXML
public void closeWindowFromMenu(ActionEvent e) throws IOException {
boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
public Stage getPrimaryStage() {
return window;
}
#FXML
public void addNewPerson() throws IOException {
alertEmptyNameController = new AlertEmptyNameController();
Person person = new Person();
person.setName(nameInput.getText());
if(nameInput.getText().isEmpty()){
alertEmptyNameController.alertEmptyName();
}else{
person.getAddress().setStreet(streetInput.getText());
person.getAddress().setZip(zipInput.getText());
person.getAddress().setCity(cityInput.getText());
personTable.getItems().add(person);
}
nameInput.clear();
streetInput.clear();
zipInput.clear();
cityInput.clear();
}
#FXML
public void deletePerson() throws IOException {
boolean answer = confirmDialogBoxController.display("Deleting Entry", "Are you sure you want to delete this entry?");
if (answer) {
ObservableList<Person> personSelected, allPersons;
allPersons = personTable.getItems();
personSelected = personTable.getSelectionModel().getSelectedItems();
personSelected.forEach(allPersons::remove);
}
}
static class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.focusedProperty().addListener((ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) -> {
if (!arg2) {
commitEdit(textField.getText());
}
});
}
private String getString() {
return getItem() == null ? "" : getItem();
}
}
}
View.fxml - this is the main View
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="borderPane" stylesheets="#MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.MainController">
<bottom>
<HBox fx:id="bottomLayout" alignment="CENTER" style="-fx-background-color: #292929;" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<children>
<TextField fx:id="nameInput" promptText="Name" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="8.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="streetInput" layoutX="15.0" layoutY="15.0" promptText="Street" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="zipInput" layoutX="163.0" layoutY="15.0" promptText="Zip" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<TextField fx:id="cityInput" layoutX="312.0" layoutY="15.0" promptText="City" style="-fx-background-radius: 0;">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</TextField>
<Button fx:id="addButton" mnemonicParsing="false" onAction="#addNewPerson" style="-fx-background-color: #5ebcff; -fx-background-radius: 0; -fx-text-fill: white;" text="Add">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
</HBox.margin>
</Button>
<Button fx:id="deleteButton" layoutX="474.0" layoutY="15.0" mnemonicParsing="false" onAction="#deletePerson" style="-fx-background-radius: 0; -fx-background-color: #5ebcff; -fx-text-fill: white;" text="Delete">
<HBox.margin>
<Insets bottom="8.0" left="5.0" right="8.0" top="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</bottom>
<center>
<TableView fx:id="personTable" editable="true" style="-fx-background-color: #5e5e5e;" stylesheets="#MyStyle.css" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="nameColumn" prefWidth="152.0" text="Name" />
<TableColumn fx:id="streetColumn" prefWidth="196.0" text="Street" />
<TableColumn fx:id="zipColumn" prefWidth="88.0" text="Zip" />
<TableColumn fx:id="cityColumn" prefWidth="163.0" text="City" />
</columns>
</TableView>
</center>
<top>
<HBox fx:id="menuLayout" style="-fx-background-color: #292929;" stylesheets="#MyStyle.css" BorderPane.alignment="CENTER">
<children>
<MenuBar fx:id="menuBar" stylesheets="#MyStyle.css">
<menus>
<Menu fx:id="fileMenu" mnemonicParsing="false" text="File">
<items>
<MenuItem fx:id="exitMenu" mnemonicParsing="false" onAction="#closeWindowFromMenu" text="Exit" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</HBox>
</top>
</BorderPane>
ConfirmDialogBoxController.java - this is the controller for the confirm dialog box for closing window with the "X" or in the menu File->Exit and for asking the user if he really wants to delete the entry in the tableview
package AddressBook;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class ConfirmDialogBoxController implements Initializable {
private static Boolean answer;
#FXML
private Button yesButton;
#FXML
private Button noButton;
#FXML
private Label confirmLabel;
#FXML
private Stage stage;
#FXML
private Model model;
public ConfirmDialogBoxController(){
System.out.println("+1 ConfirmDialogBoxController() object instantiated");
}
public ConfirmDialogBoxController(Model model){
this.model = model;
System.out.println("+1 ConfirmDialogBoxController(model) object instantiated");
}
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.confirmLabel.setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
public Label getLabel(){
return confirmLabel;
}
#FXML
public boolean yesButtonClicked(ActionEvent actionEvent) {
answer = true;
stage = (Stage) yesButton.getScene().getWindow();
stage.close();
return answer;
}
#FXML
public boolean noButtonClicked(ActionEvent actionEvent) {
answer = false;
Stage confirmWindow = (Stage) noButton.getScene().getWindow();
confirmWindow.close();
return answer;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
// confirmLabel.textProperty().bindBidirectional(messageProperty);
// System.out.println("messageProperty.getValue(): "+ messageProperty.getValue());
// System.out.println("DEBUG: message is = " + messageProperty.get());
}
}
ConfirmDialogBoxView.fxml - this is the ConfirmDialogBox View
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefWidth="450.0" stylesheets="#MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.ConfirmDialogBoxController">
<children>
<VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label fx:id="confirmLabel" textAlignment="CENTER" />
<HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
<children>
<Button fx:id="yesButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#yesButtonClicked" text="Yes" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
<Button fx:id="noButton" alignment="CENTER" contentDisplay="CENTER" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#noButtonClicked" text="No" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
</children>
<padding>
<Insets bottom="50.0" top="30.0" />
</padding>
</VBox>
</children>
</AnchorPane>
AlertEmptyNameController.java - this is the controller for the view when the name field is empty and you click on add person
package AddressBook;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
public class AlertEmptyNameController {
#FXML
private Button okButton;
#FXML
private Label emptyNameLabel;
private Stage alertEmptyNamestage;
private Model model;
private AlertEmptyNameController alertEmptyNameController;
public AlertEmptyNameController() {
System.out.println("+1 AlertEmptyNameControlle() object instantiated");
}
public AlertEmptyNameController(Model model){
this.model = model;
System.out.println("+1 AlertEmptyNameController(model) object instantiated");
}
public void alertEmptyName() throws IOException {
FXMLLoader alertEmptyNameLoader = new FXMLLoader(getClass().getResource("AlertEmptyNameView.fxml"));
alertEmptyNameLoader.load();
AlertEmptyNameController alertEmptyNameController = alertEmptyNameLoader.getController();
Parent root = alertEmptyNameLoader.getRoot();
alertEmptyNamestage = new Stage();
alertEmptyNamestage.setScene(new Scene(root));
alertEmptyNamestage.setTitle("The Namefield is empty!");
alertEmptyNamestage.initModality(Modality.APPLICATION_MODAL);
alertEmptyNamestage.showAndWait();
}
#FXML
public boolean okButtonClicked(ActionEvent actionEvent) {
boolean answer = true;
alertEmptyNamestage = (Stage) okButton.getScene().getWindow();
alertEmptyNamestage.close();
return answer;
}
}
AlertEmptyNameView.fxml - the view for AlertEmptyName
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<AnchorPane prefHeight="250.0" prefWidth="450.0" stylesheets="#MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.AlertEmptyNameController">
<children>
<VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label fx:id="emptyNameLabel" text="The Namefield cannot be empty!" textAlignment="CENTER" />
<HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
<children>
<Button fx:id="okButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#okButtonClicked" text="Ok" textAlignment="CENTER">
<HBox.margin>
<Insets />
</HBox.margin>
</Button>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
</children>
<padding>
<Insets bottom="50.0" top="30.0" />
</padding>
</VBox>
</children>
</AnchorPane>
And this is for example the NullPointerException when I wanna close the window:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at AddressBook.MainController.closeWindow(MainController.java:163)
at AddressBook.MainController.lambda$initialize$8(MainController.java:137)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at com.sun.javafx.stage.WindowPeerListener.closing(WindowPeerListener.java:88)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:122)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$3(GlassWindowEventHandler.java:151)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:410)
at com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:149)
at com.sun.glass.ui.Window.handleWindowEvent(Window.java:1273)
at com.sun.glass.ui.Window.notifyClose(Window.java:1177)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
at java.lang.Thread.run(Thread.java:748)
I hope that someone can help me.
Cheers
I deleted now the display() method in confirmDialogBoxController.java and put it in mainController.java
...
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.getLabel().setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
#FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
...
Your confirmDialogBoxController in the main controller is null: it is never initialized. The way you have set this up is problematic: the ConfirmDialogBoxController is only initialized when the corresponding FXML is loaded (common to any FXML-controller pair), but the code for loading the FXML is in the ConfirmDialogBoxController class, so you can't load the FXML until you have a controller instance.
It's not really the responsibility of the ConfirmDialogBoxController to display the UI defined by its FXML. You should move the display() method to your MainController class:
public class MainController implements Initializable {
// Existing code omitted...
// updated close method:
#FXML
public void closeWindow(WindowEvent e) throws IOException {
boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
if (answer) {
MiniTest.getPrimaryStage().close();
}
}
public boolean displayConfirmDialog(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.setConfirmMessage(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
// Get the user response (true = Yes button clicked) from controller:
return confirmDialogBoxController.getResponse() ;
}
}
And then update the ConfirmDialogBoxController:
public class ConfirmDialogBoxController implements Initializable {
// existing code omitted...
// This should not be static, and should be a primitive type:
// private static Boolean answer ;
private boolean answer ;
// this method removed:
/*
public boolean display(String title, String message) throws IOException {
FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
confirmViewLoader.load();
ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
confirmDialogBoxController.confirmLabel.setText(message);
Parent root = confirmViewLoader.getRoot();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
System.out.println("MessageVariable in DisplayMethod is:"+message);
stage.showAndWait();
return answer;
}
*/
// This added for convenience:
public void setConfirmMessage(String message) {
confirmLabel.setText(message);
}
// This added to return the response (answer):
public boolean getResponse() {
return answer ;
}
// Note also your event handlers should be void:
#FXML
public void yesButtonClicked(ActionEvent actionEvent) {
answer = true;
stage = (Stage) yesButton.getScene().getWindow();
stage.close();
// return answer;
}
#FXML
public void noButtonClicked(ActionEvent actionEvent) {
answer = false;
Stage confirmWindow = (Stage) noButton.getScene().getWindow();
confirmWindow.close();
// return answer;
}
}
You probably want a similar refactoring for your other dialog.

Can't read text from TextField input from DialogPane, JavaFX

I am trying to create a simple Contacts Application in JavaFX. It has a main window with TableView and a DialogPane opening when I want to create new contact. In the DialogPane there are several TextFields from which I want to collect text in order to create a Contacts List. My problem is that when I want to read the input from the DialogPane (from TextFields), which is the separate fxml file with separate controller (separate from main Controller) the application runs an error (java.lang.NullPointerException). And when I put a TextField in my main window FXML file, then I can access this text from the textField just fine. Why do I get an error when I want to read data from DialogPane (Error-->File: Controller.java, I commented the section where I get an error)?? I am stuck. Can anyone suggest what am I doing wrong? Here is my code:
Main.java
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("mainwindow.fxml"));
primaryStage.setTitle("Your Contacts");
primaryStage.setScene(new Scene(root, 900, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java
public class Controller {
#FXML
private BorderPane mainPanel;
public ObservableList<Contact> contactsList = FXCollections.observableArrayList();
#FXML
public void showAddContactDialog() {
Dialog<ButtonType> dialog = new Dialog<>();
dialog.initOwner(mainPanel.getScene().getWindow());
dialog.setTitle("Add new contact");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("addContactDialog.fxml"));
try {
dialog.getDialogPane().setContent(fxmlLoader.load());
} catch (IOException e) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText(null);
alert.setContentText("Couldn't load the dialog");
alert.showAndWait();
e.printStackTrace();
return;
}
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
if(result.isPresent() && result.get() == ButtonType.OK) {
//========================================================================================
//here is the error, I cannot read values from addContactDialog controller
ContactController contactController = new ContactController();
String firstName = contactController.getNewContact().getFirstName();
String lastName = contactController.getNewContact().getLastName();
String phoneNumber = contactController.getNewContact().getPhoneNumber();
String emailAddress = contactController.getNewContact().getEmailAddress();
Contact newContact = new Contact(firstName, lastName, phoneNumber, emailAddress);
contactsList.add(newContact);
//or alternatively
// Contact newContact = contactController.getNewContact();
// contactsList.add(newContact);
//========================================================================================
}
}
}
ContactController.java
public class ContactController {
#FXML
private TextField firstNameField;
#FXML
private TextField lastNameField;
#FXML
private TextField phoneNumberFiled;
#FXML
private TextField emailField;
public Contact getNewContact() {
String firstName = firstNameField.getText();
String lastName = lastNameField.getText();
String phoneNumber = phoneNumberFiled.getText();
String emailAddress = emailField.getText();
Contact newContact = new Contact(firstName, lastName, phoneNumber, emailAddress);
return newContact;
}
Contact.java
public class Contact {
private SimpleStringProperty firstName = new SimpleStringProperty("");
private SimpleStringProperty lastName = new SimpleStringProperty("");
private SimpleStringProperty phoneNumber = new SimpleStringProperty("");
private SimpleStringProperty emailAddress = new SimpleStringProperty("");
public Contact() {
}
public Contact(String firstName, String lastName, String phoneNumber, String emailAddress) {
this.firstName.set(firstName);
this.lastName.set(lastName);
this.phoneNumber.set(phoneNumber);
this.emailAddress.set(emailAddress);
}
public String getFirstName() {
return firstName.get();
}
public SimpleStringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public SimpleStringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public String getPhoneNumber() {
return phoneNumber.get();
}
public SimpleStringProperty phoneNumberProperty() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber.set(phoneNumber);
}
public String getEmailAddress() {
return emailAddress.get();
}
public SimpleStringProperty emailAddressProperty() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress.set(emailAddress);
}
#Override
public String toString() {
return "Contact{" +
"firstName=" + firstName +
", lastName=" + lastName +
", phoneNumber=" + phoneNumber +
", emailAddress=" + emailAddress +
'}';
}
}
mainwindow.fxml
<BorderPane fx:id="mainPanel" fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml">
<top>
<MenuBar>
<menus>
<Menu text="Contacts">
<items>
<MenuItem text="Add new" onAction="#showAddContactDialog"/>
</items>
<items>
<MenuItem text="Edit" />
</items>
<items>
<MenuItem text="Delete"/>
</items>
<items>
<MenuItem text="Exit"/>
</items>
</Menu>
</menus>
<menus>
<Menu text="Info">
<items>
<MenuItem text="About"/>
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<TableView fx:id="contactsTable">
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
<columns>
<TableColumn text="First Name">
<cellValueFactory>
<PropertyValueFactory property="firstName"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="Last Name">
<cellValueFactory>
<PropertyValueFactory property="lastName"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="Phone Number">
<cellValueFactory>
<PropertyValueFactory property="phoneNumber"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="Email">
<cellValueFactory>
<PropertyValueFactory property="emailAddress"/>
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</center>
</BorderPane>
addContactDialog.fxml
<DialogPane fx:controller="sample.ContactController" xmlns:fx="http://javafx.com/fxml">
<headerText>
Fill in the information for the new Contact
</headerText>
<content>
<GridPane vgap="10" hgap="10">
<Label text="First Name: " GridPane.rowIndex="0" GridPane.columnIndex="0"/>
<TextField fx:id="firstNameField" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
<Label text="Last Name: " GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<TextField fx:id="lastNameField" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
<Label text="Phone Number: " GridPane.rowIndex="2" GridPane.columnIndex="0"/>
<TextField fx:id="phoneNumberField" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<Label text="Notes: " GridPane.rowIndex="3" GridPane.columnIndex="0"/>
<TextField fx:id="notesField" GridPane.rowIndex="3" GridPane.columnIndex="1"/>
</GridPane>
</content>
</DialogPane>
Ok, I found the mistake - I made a typo in the ContactController.java file. It should have phoneNumberField instead of phoneNumberFiled String...
Did you tried putting .toString
like this
String firstName = contactController.getNewContact().getFirstName().toString();

Javafx SceneBuilder Tableview.getSelectionModel not working

Tableview.getSelectionModel not working. After advice form #James_D I have used a Model class (Software) to select columns I need while pulling SQL to a tableview. I searched here, the web, moved code and checked intellisense and the best examples I can find anywhere are commented out in the SoftwareController code below, nothing works?
Prior to using a Model class I had everyting in the SoftwareController where EXAMPLE 4 worked, it gave the cell data of column 0 where ever on the row I clicked, which I use to pull more SQL data. This now errors at newValue.get(0), newValue is not showing get()or getid is available.
I have changed SelectedItem to index and added toString and all that and I get fxml.software#sometext or the row index. EXAMPLE 1 gives me the cell data of any cell, but I just want the first column on the row I choose, which in my case is an ID, not the row index.
I am also now having to use #SuppressWarnings for "Raw" errors, is this because I am in initialize?
Any help or pointers would be appreciated.
SoftwareController
public class SoftwareController extends Application implements Initializable {
private Statement statement;
Connection conn = null;
#FXML Button btnSoftware;
#FXML Label lblTest;
#FXML TableView tblSoftware;
#FXML TableColumn CI_IDcol;
#FXML TableColumn Namecol;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Software.fxml")); //load Software fxml file
Parent root1 = (Parent) fxmlLoader.load();
primaryStage.setScene(new Scene(root1));
primaryStage.show();
}
private static ObservableList<Software>data;
#FXML private TextField txtFilter;
private Object getCellData;
#SuppressWarnings({ "unchecked", "rawtypes" }) //added due to TableView getselecionModel code
#Override
public void initialize(URL location, ResourceBundle resources) {
try {
data = FXCollections.observableArrayList();
conn = DBconnection.makeConnection();
statement = conn.createStatement();
String SQL = "SELECT * FROM Data_CMDB_Main";
ResultSet rs = statement.executeQuery(SQL);
while (rs.next()) {
data.add(new Software(rs.getString("CI_ID"),
rs.getString("Name")));
CI_IDcol.setCellValueFactory(new PropertyValueFactory("CI_ID"));
Namecol.setCellValueFactory(new PropertyValueFactory("Name"));
tblSoftware.setItems(null);
tblSoftware.setItems(data);
//TableView.selection
//get row example 1
/*tblSoftware.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observableValue, Object oldValue, Object newValue) {
if(tblSoftware.getSelectionModel().getSelectedItem() != null) {
TableViewSelectionModel selectionModel = tblSoftware.getSelectionModel();
ObservableList selectedCells = selectionModel.getSelectedCells();
TablePosition tablePosition = (TablePosition) selectedCells.get(0);
Object val = tablePosition.getTableColumn().getCellData(newValue);
//Object val = tblSoftware.getColumns().get(0).toString();
System.out.println(val); //int row = tablePosition.getRow();
}
}
});*/
//get row example 2 only gives index of filtered rows
//tblSoftware.getSelectionModel().selectedIndexProperty().addListener((v, oldValue, newValue) -> System.out.println(newValue)); //gets all row data
//get row example 3 ItemProperty seems correct just not giving readable row identification
//tblSoftware.getSelectionModel().selectedItemProperty().addListener((v, oldValue, newValue) -> System.out.println(newValue)); //gets all row data
///get row example 4
//#Override
/*tblSoftware.getSelectionModel().selectedItemProperty().addListener( //gets any row column
(observable, oldValue, newValue) -> {
if (newValue == null) {
lblTest.setText("");
return;
}
lblTest.setText("Selected Number: " + newValue.get(0));
}
);*/
///get row example 5
/*tblSoftware.getSelectionModel().selectedItemProperty().addListener( //gets any row column
new ChangeListener<IdentifiedName>() {
#Override
public void changed (
ObservableValue<? extends IdentifiedName> observable,
IdentifiedName oldValue,
IdentifiedName newValue
){
if(newValue == null) {
lblTest.setText("");
return;
}
lblTest.setText("Selected Number: " + + newValue.getId(0));
}
}
); */
//filter
txtFilter.setPromptText("Text Filter");
txtFilter.textProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable o) {
tblSoftware.getSelectionModel().clearSelection(); // this gives no errors when switching back to filter box when row previously selected
if(txtFilter.textProperty().get().isEmpty()) {
tblSoftware.setItems(data);
return;
}
ObservableList<Software> tableItems = FXCollections.observableArrayList();
ObservableList<TableColumn<Software, ?>> cols = tblSoftware.getColumns();
for(int i=0; i<data.size(); i++) {
for(int j=0; j<cols.size(); j++) {
TableColumn col = cols.get(j);
String cellValue = col.getCellData(data.get(i)).toString();
cellValue = cellValue.toLowerCase();
if(cellValue.contains(txtFilter.textProperty().get().toLowerCase())) {
tableItems.add(data.get(i));
break;
}
}
}
tblSoftware.setItems(tableItems);
}
});
}
} catch (SQLException e) {
e.printStackTrace();
}
}
protected void setIndex(int selectedIndex) {
// TODO Auto-generated method stub
}
public void btnSoftwarePressed(){
lblTest.setText("Button works");
}
}
Software Class
package fxml;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Software {
private StringProperty CI_ID;
private StringProperty Name;
public Software(String CI_ID, String Name) {
this.CI_ID = new SimpleStringProperty(CI_ID);
this.Name = new SimpleStringProperty(Name);
}
public StringProperty CI_IDProperty() {
return CI_ID;
}
public StringProperty NameProperty() {
return Name;
}
}
Software fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java .util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxml.SoftwareController">
<center>
<TableView fx:id="tblSoftware" prefHeight="200.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="CI_IDcol" prefWidth="100.0" text="CI_ID" />
<TableColumn fx:id="Namecol" prefWidth="150.0" text="Name" />
</columns>
</TableView>
</center>
<top>
<VBox prefHeight="83.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<children>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="btnSoftware" mnemonicParsing="false" onAction="#btnSoftwarePressed" text="Button" />
<Label fx:id="lblTest" prefHeight="28.0" prefWidth="158.0" text="Label" />
<ParallelCamera />
</children>
</HBox>
<HBox>
<children>
<TextField fx:id="txtFilter" />
</children>
</HBox>
</children>
</VBox>
</top>
</BorderPane>
I'm not really sure of what you want exactly to do, but I can give you my approach to insert data from db into a tableview, and after that, to get the data from db using the previous data loaded into the tableview.
I first created a inner class inside the controller, which will represent the instances to save in/load from database:
public static class Detector {
private String name;
private String conn_type;
private int num_detect;
private String serial_port;
private int data_bits;
private int stop_bits;
private String parity;
private String ip;
private int eth_port;
private int historic;
public Detector(String name, String conn_type, int num_detect, String serial_port, int speed,
int data_bits, int stop_bits, String parity, String ip, int eth_port, int his){
this.name = name;
this.conn_type = conn_type;
this.num_detect = num_detect;
this.serial_port = serial_port;
this.data_bits = data_bits;
this.stop_bits = stop_bits;
this.parity = parity;
this.ip = ip;
this.eth_port = eth_port;
this.historic = his;
}
}
Afther that, I declared the tableview
public class Controller implements Initializable {
#FXML
private TableView<Detector> detectors;
.
.
.
And I created the tableview using the data obtained from a query:
DBConnection c = new DBConnection();
c.connect();
try{
String sql = "select * from detector order by name";
ResultSet rs = c.query(sql);
ObservableList<Detector> data = FXCollections.observableArrayList();
while(rs.next()){
data.add(new Detector(rs.getString("name"),
rs.getString("conn_type"),
Integer.parseInt(rs.getString("num_detect")),
rs.getString("serial_port"),
Integer.parseInt(rs.getString("speed")),
Integer.parseInt(rs.getString("data_bits")),
Integer.parseInt(rs.getString("stop_bits")),
rs.getString("parity"),
rs.getString("ip"),
Integer.parseInt(rs.getString("puerto_socket")),
Integer.parseInt(rs.getString("historico"))
));
}
TableColumn colName = new TableColumn("Name");
colName.setCellValueFactory(new PropertyValueFactory<Detector, String>("name"));
detectors.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> loadName(newValue));
detectors.setItems(data);
detectors.getColumns().addAll(nombreCol);
//Add a column for every column data you want to show
Then, you have to define the behaviour of the method called by the listener (in my case, "loadName")
private void loadName(Detector r){
//here you could, for example, generate a sql query with the data received in r
}

Resources