Didi Didi - 5 months ago 49
SQL Question

Load FXML file on tableview row selection

Please, I would like to load an FXML file on clicking on a tableview row (row selection) and retrieve the values of the row from a database and setting the values on the labels of the FXML file.

The examples I've seen so far doesn't implement thus.

I would appreciate if anybody can help on FXML file loading.

My current code:

package application;

import java.io.IOException;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.paint.Color;

public class Main extends Application {
ObservableList<Person> persons = FXCollections.observableArrayList();
@Override
public void start(Stage primaryStage) {
Parent root = FXMLLoader.load(getClass().getResource("personsTable.fxml"));
Scene scene = new Scene(root);
newStage.setScene(newScene);
newStage.show();
try {
Class.forName("org.apache.derby.jdbc.ClientDriver");
conn=DriverManager.getConnection("jdbc:derby://localhost:1527/Employee","Conduct","ccb");

String rest="select *from Employee";
pstmt=conn.prepareStatement(rest);
rs=pstmt.executeQuery();



while(rs.next()){
persons.add(new Person(
rs.getString("name"),


));

staff.setCellValueFactory(new PropertyValueFactory<>("name"));

personsTable.setItems(persons);
personsTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {

@Override
public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {

// Create a new FXML loader
FXMLLoader loader = new FXMLLoader(getClass().getResource("OnSelection.fxml"));
try {
// Load the another FXML file
Parent newParent = loader.load();
OnSelectionController subController = loader.getController();
// Set the String property
// If you want to use data from the current selection: newValue contains the currently selected Person
// TODO: Get value from DB
subController.textToDisplay.set(newValue.getName());

// newParent contains the root of your other FXML file, do anything that you want to do with it (e.g. add to the current node graph)
// Now I just simply open it in a new window
Stage newStage = new Stage();
Scene newScene = new Scene(newParent);
newStage.setScene(newScene);
newStage.show();

} catch (IOException | SQLException ex) {
Logger.getLogger(ViewController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}

} catch (SQLException | ClassNotFoundException ex) {
Logger.getLogger(ViewController.class.getName()).log(Level.SEVERE, null, ex);
}

}


}

Answer

You could simply add a listener for the selectedItemProperty of the selectionModelProperty of your TableView in which you can lod your another FXML file using FXMLLoader. You can expose some public methods and/or properties on the controller of this FXML file and you can use this methods and/or properties to set the data in the controller returned by getController method of the FXMLLoader.

Minimalistic example with your specification:

In the example the TableView displays Person objects, on selection of the TableView a second FXML file is loaded and displayed on a new Stage.

Main.java

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {

        Group root = new Group();
        Scene scene = new Scene(root, 700, 400, Color.WHITE);
        TableView<Person> personsTable = new TableView<Person>();

        // Add only one Column: Name
        TableColumn<Person, String> nameCol = new TableColumn<Person, String>("Name");
        nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
        personsTable.getColumns().add(nameCol);

        // On selected item
        personsTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {

            @Override
            public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {

                // Create a new FXML loader 
                FXMLLoader loader = new FXMLLoader(getClass().getResource("OnSelection.fxml"));
                try {
                    // Load the another FXML file 
                    Parent newParent = loader.load();
                    OnSelectionController subController = loader.getController();
                    // Set the String property
                    // If you want to use data from the current selection: newValue contains the currently selected Person
                    // TODO: Get value from DB
                    subController.textToDisplay.set("value from DB for Person" + newValue.getName());

                    // newParent contains the root of your other FXML file, do anything that you want to do with it (e.g. add to the current node graph)
                    // Now I just simply open it in a new window
                    Stage newStage = new Stage();
                    Scene newScene = new Scene(newParent);
                    newStage.setScene(newScene);
                    newStage.show();

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        // Create some dummy data for the table
        ObservableList<Person> persons = FXCollections.observableArrayList();
        for (int i = 0; i < 10; i++) {
            Person person = new Person();
            person.setName("Name" + i);
            person.setAddress("Address" + i);
            person.setCountry("Country" + i);
            person.setCourse("Course" + i);
            persons.add(person);

        }
        personsTable.setItems(persons);
    }

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

Person.java

public class Person {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCourse() {
        return course;
    }

    public void setCourse(String course) {
        this.course = course;
    }

    private String name;
    private String address;
    private String country;
    private String course;

}

OnSelectionController.java

public class OnSelectionController implements Initializable {

    @FXML private Label label1;

    public SimpleStringProperty textToDisplay = new SimpleStringProperty("");

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // The text that the label displays is bound to the string property value
        label1.textProperty().bind(textToDisplay);

    }

}

OnSelection.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="191.0" prefWidth="210.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.OnSelectionController">
  <!-- TODO Add Nodes -->
  <children>
    <Label fx:id="label1" layoutX="59.0" layoutY="40.0" text="Label" />
  </children>
</AnchorPane>

Please see the comments in the code snippets.