Sunday, May 12, 2013

Detect mouse click on JavaFX TableView and get the details of the clicked item

The example demonstrate how to detect mouse click event on JavaFX TableView by implement CellFactory, to get the details of the clicked item.

package javafx_testtableview;

import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
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 final SimpleIntegerProperty id;
        private final SimpleStringProperty name;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;

        private Record(int id, String name, String lastName, String email) {
            this.id = new SimpleIntegerProperty(id);
            this.name = new SimpleStringProperty(name);
            this.lastName = new SimpleStringProperty(lastName);
            this.email = new SimpleStringProperty(email);
        }

        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(12, "William", "Austin", "xxx@xxx.xxx"));
        recordList.add(new Record(15, "Chris", "redfield", "yyy@yyy.yyy"));
        recordList.add(new Record(1, "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();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().add(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();
            System.out.println("id = " + recordList.get(index).getId());
            System.out.println("name = " + recordList.get(index).getName());
            System.out.println("lastName = " + recordList.get(index).getLastName());
            System.out.println("email = " + recordList.get(index).getEmail());
        }
    }
}


Detect mouse click on JavaFX TableView and get the details of the clicked item
Detect mouse click on JavaFX TableView and get the details of the clicked item


Next:
- Hide empty cell of TableView with CSS.
- Update ObservableList for TableView, in UI thread and background thread.


9 comments:

  1. really sorry for that ^^ but basically i'm a bit of new to javafx, and just linking the tableview and the database was so hard that i almost destroyed my pc ^^
    and like i first posted, a little help with the combobox not wanting to display images when selecting elements, it just shows me hexa code !!
    Last but not list, i just writen a code of resizing an image before sending it to the database in displaing it in the imageview, problem is that i'm resizing the imageview not the image, and i want after the resize process to upload the image to my database ??
    Is there a way of fixing this ??

    ReplyDelete
    Replies
    1. Do you want code to resize image? Load a re-sized image.

      For ComboBox, I have to study it first. I'm a beginner also.

      Delete
  2. hi man !!
    ah thx again i just thought that i can only resize by bounding the imageview ^^
    So this time, it's basically me stuck with the getting of a single value when selecting a row in my tableview
    http://upload-pics.org/images/04163967738299484431.png
    as yu can see, what i get is the full row not just items !
    Yes, i saw the post of detecting the mouse click and...
    but didn't get it well !!

    Here's the code i wrote !!
    public void getValues(){
    tableview.setOnMouseClicked(new EventHandler(){

    @Override
    public void handle(MouseEvent t) {
    ObservableList table = FXCollections.observableArrayList();
    for(int i = 0;i<=tableview.getColumns().size();i++){
    table.add(tableview.getSelectionModel().getSelectedItems().get(0).toString());
    }
    t1.setText(table.get(0));
    t2.setText(table.get(1));
    t3.setText(table.get(2));
    t4.setText(table.get(3));
    t5.setText(table.get(4));
    t6.setText(table.get(5));


    }


    });
    }

    all i'm trying to get is the id coloumn value when i click on a row ^^
    Plz i've been really doing some search but as you know, javafx is a new approach of programming, not easy, not very found in topics and a little hard ^^

    ReplyDelete
    Replies
    1. Is it means what I get in the example is what you expect?

      In my code, I addEventFilter on each cell using CellFactory, that means there are many EventHandlers for many objects of cell. So you can get the clicked object of cell using t.getSource() in EventHandler. The returned object is TableCell.

      In your code, setOnMouseClicked for tableview. That means the source of event is the whole tableview, not individual cell.

      I modify the code from the example of Edit Cell in http://docs.oracle.com/javafx/2/ui_controls/table-view.htm

      Delete
  3. Well, here is yur problem, yu're filling yur tableview statically not from a database so it's a little bit harder to get a value ^^ especially when it's not the same implementing method that has been used ^^

    ReplyDelete
    Replies
    1. I think it's not difficult to add record in recordList by calling recordList.add(new Record(...)).

      ObservableList object enables the tracking of any changes to its elements, the TableView content automatically updates whenever the data changes.

      Delete
  4. This comment has been removed by a blog administrator.

    ReplyDelete
  5. Nice example! but i have a question. Will this code work for a table created in a task thread not in a main thread??

    ReplyDelete