Thursday, May 16, 2013

Update ObservableList for TableView, in UI thread and background thread.

In the code example "Detect mouse click on JavaFX TableView and get the details of the clicked item", the content were pre-inserted in start() method. This example show how to add records into ObservableList for TableView. Also show how to do it in FX Application Thread (or UI thread) and in background thread.

Update ObservableList for TableView, in UI thread and background thread.
Update ObservableList for TableView, in UI thread and background thread.


  • To keep track of the record id, introduce a class variable, trackId, in Record class.
  • Output Platform.isFxApplicationThread() in constructor of Record; such that we can know the thread of the operation.
  • Add TextFields for user to enter fields of new records.
  • Add buttons to add record in UI thread and in background thread.

package javafx_testtableview;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
 * @web http://java-buddy.blogspot.com/
 */
public class JavaFX_TestTableView extends Application {

    public static class Record {

        private static int trackId;
        private final SimpleIntegerProperty id;
        private final SimpleStringProperty name;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;

        private Record(String name, String lastName, String email) {
            
            System.out.println("Platform.isFxApplicationThread(): "
                        + Platform.isFxApplicationThread());
            
            this.id = new SimpleIntegerProperty(trackId);
            this.name = new SimpleStringProperty(name);
            this.lastName = new SimpleStringProperty(lastName);
            this.email = new SimpleStringProperty(email);
            trackId++;
        }

        public int getId() {
            return this.id.get();
        }

        public void setId(int id) {
            this.id.set(id);
        }

        public String getName() {
            return this.name.get();
        }

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

        public String getLastName() {
            return this.lastName.get();
        }

        public void setLastName(String lastName) {
            this.lastName.set(lastName);
        }

        public String getEmail() {
            return this.email.get();
        }

        public void setEmail(String email) {
            this.email.set(email);
        }
    }
    private TableView<Record> tableView = new TableView<>();
    private final ObservableList<Record> recordList = FXCollections.observableArrayList();

    private void prepareRecordList() {
        recordList.add(new Record("William", "Austin", "xxx@xxx.xxx"));
        recordList.add(new Record("Chris", "redfield", "yyy@yyy.yyy"));
        recordList.add(new Record("Java", "Buddy", "javabuddy@abc.yyy"));
    }

    @Override
    public void start(Stage primaryStage) {
        Scene scene = new Scene(new Group());
        primaryStage.setTitle("http://java-buddy.blogspot.com/");
        primaryStage.setWidth(400);
        primaryStage.setHeight(500);

        prepareRecordList();

        tableView.setEditable(false);

        Callback<TableColumn, TableCell> integerCellFactory =
                new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn p) {
                MyIntegerTableCell cell = new MyIntegerTableCell();
                cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new MyEventHandler());
                return cell;
            }
        };

        Callback<TableColumn, TableCell> stringCellFactory =
                new Callback<TableColumn, TableCell>() {
            @Override
            public TableCell call(TableColumn p) {
                MyStringTableCell cell = new MyStringTableCell();
                cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new MyEventHandler());
                return cell;
            }
        };

        TableColumn colId = new TableColumn("ID");
        colId.setCellValueFactory(
                new PropertyValueFactory<Record, String>("id"));
        colId.setCellFactory(integerCellFactory);

        TableColumn colName = new TableColumn("Name");
        colName.setCellValueFactory(
                new PropertyValueFactory<Record, String>("name"));
        colName.setCellFactory(stringCellFactory);

        TableColumn colLastName = new TableColumn("Last Name");
        colLastName.setCellValueFactory(
                new PropertyValueFactory<Record, String>("lastName"));
        colLastName.setCellFactory(stringCellFactory);

        TableColumn colEmail = new TableColumn("Email");
        colEmail.setCellValueFactory(
                new PropertyValueFactory<Record, String>("email"));
        colEmail.setCellFactory(stringCellFactory);

        tableView.setItems(recordList);
        tableView.getColumns().addAll(colId, colName, colLastName, colEmail);

        final VBox vbox = new VBox();

        Label label_name = new Label("Name");
        final TextField textField_name = new TextField();
        HBox hBox_name = new HBox();
        hBox_name.setSpacing(10);
        hBox_name.getChildren().addAll(label_name, textField_name);

        Label label_lastname = new Label("Last Name");
        final TextField textField_lastname = new TextField();
        HBox hBox_lastname = new HBox();
        hBox_lastname.setSpacing(10);
        hBox_lastname.getChildren().addAll(label_lastname, textField_lastname);

        Label label_email = new Label("email");
        final TextField textField_email = new TextField();
        HBox hBox_email = new HBox();
        hBox_email.setSpacing(10);
        hBox_email.getChildren().addAll(label_email, textField_email);

        Button button_Add = new Button("Add record");
        button_Add.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {

                //update recordList in UI thread
                recordList.add(new Record(
                        textField_name.getText(),
                        textField_lastname.getText(),
                        textField_email.getText()));

                textField_name.clear();
                textField_lastname.clear();
                textField_email.clear();
            }
        });

        Button button_AddBackGround = new Button("Add record in BACKGROUND");
        button_AddBackGround.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {

                final String bufferName = textField_name.getText();
                final String bufferLastName = textField_lastname.getText();
                final String bufferEmail = textField_email.getText();

                new Thread() {
                    public void run() {

                        //update recordList in Background thread
                        recordList.add(new Record(
                                bufferName,
                                bufferLastName,
                                bufferEmail));
                    };
                }.start();
                
                textField_name.clear();
                textField_lastname.clear();
                textField_email.clear();
            }
        });

        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(hBox_name, hBox_lastname, hBox_email,
                button_Add, button_AddBackGround, tableView);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

    class MyIntegerTableCell extends TableCell<Record, Integer> {

        @Override
        public void updateItem(Integer item, boolean empty) {
            super.updateItem(item, empty);
            setText(empty ? null : getString());
            setGraphic(null);
        }

        private String getString() {
            return getItem() == null ? "" : getItem().toString();
        }
    }

    class MyStringTableCell extends TableCell<Record, String> {

        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            setText(empty ? null : getString());
            setGraphic(null);
        }

        private String getString() {
            return getItem() == null ? "" : getItem().toString();
        }
    }

    class MyEventHandler implements EventHandler<MouseEvent> {

        @Override
        public void handle(MouseEvent t) {
            TableCell c = (TableCell) t.getSource();
            int index = c.getIndex();

            try {
                Record item = recordList.get(index);
                System.out.println("id = " + item.getId());
                System.out.println("name = " + item.getName());
                System.out.println("lastName = " + item.getLastName());
                System.out.println("email = " + item.getEmail());
            } catch (IndexOutOfBoundsException exception) {
                //...
            }

        }
    }
}


1 comment:

  1. hi buddy,
    So this time, i've come with some more details to show my problem !!
    Here is first the code when i implement the method to populate the tableview :

    ObservableList data;
    Connection c ;
    data = FXCollections.observableArrayList();
    try{
    c = connection.ConnecrDb();
    //SQL FOR SELECTING ALL OF CUSTOMER
    String SQL = "select Id as ID,NCin,Prenom as Prénom,Nom,Adresse,employes.Grade,grade_paye.salaire as Salaire from employes,grade_paye where employes.Grade = grade_paye.grade order by Id";
    //ResultSet
    ResultSet rs = c.createStatement().executeQuery(SQL);

    /**********************************
    * TABLE COLUMN ADDED DYNAMICALLY *
    **********************************/
    for(int i=0 ; i,ObservableValue>(){
    public ObservableValue call(TableColumn.CellDataFeatures param) {
    return new SimpleStringProperty(param.getValue().get(j).toString());
    }
    });
    tabview.getColumns().addAll(col);
    //System.out.println("Column ["+i+"] ");

    }
    /********************************
    60
    * Data added to ObservableList *
    61
    ********************************/
    while(rs.next()){
    //Iterate Row
    ObservableList row = FXCollections.observableArrayList();
    for(int i=1 ; i<=rs.getMetaData().getColumnCount(); i++){
    //Iterate Column
    row.add(rs.getString(i));
    }
    //System.out.println("Row [1] added "+row);
    data.add(row);
    }
    //FINALLY ADDED TO TableView
    tabview.setItems(data);
    }catch(Exception e){
    e.printStackTrace();
    System.out.println("Error on Building Data");
    }

    now the problem is when i click on a row in this very tableview, my textfields will be filled with the values of the selectedrow !!
    but i'm not going to use the method yu use !!
    what i'm going to use is just by getting a certain value from my tableview, i'll use it in a sqlquerry like this little example :
    String Table_click = (jTable1.getModel().getValueAt(jTable1.getSelectedRow(), 0).toString());

    so in the selectedrow, i get the value of the first coloun !!
    pretty easy but i haven't found a way to do the same in javafx and database use ^^
    Hope this time, i can find a solution ^^

    ReplyDelete