Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add button in JavaFX table view

I have searched at Google and Stackoverflow for this and I just don't get the given examples. Can someone please explain it to me.

I want to add a button to the last column of a table view and when it gets clicked it should trigger a listener and pass the object of the buttons row. I just do not get the following example from gist.github.com:

This is my full current code:

public class SchermdeelWerkplaats extends BorderPane{      //ATD moeder klasse met alle collecties etc.     private ATD $;      TableView tabel = new TableView();     Button nieuwTaak = new Button("Nieuwe taak inboeken");     final ObservableList<Task> data = FXCollections.observableArrayList();      public SchermdeelWerkplaats(ATD a) {          $ = a;          data.addAll($.agenda);          tabel.setEditable(false);         tabel.setPlaceholder(new Label("Geen taken"));          TableColumn c1 = new TableColumn("datum");         c1.setMinWidth(200);         TableColumn c2 = new TableColumn("type");         c2.setMinWidth(100);         TableColumn c3 = new TableColumn("uren");         c3.setMinWidth(100);         TableColumn c4 = new TableColumn("klaar");         c4.setMinWidth(200);         TableColumn c5 = new TableColumn("Werknemer");         c5.setMinWidth(100);         TableColumn c6= new TableColumn("Auto");         c6.setMinWidth(400);         TableColumn c7= new TableColumn("Actie");         c7.setMinWidth(400);          TableColumn col_action = new TableColumn<>("Action");          col_action.setCellValueFactory(                 new Callback<TableColumn.CellDataFeatures<Task, Boolean>,                  ObservableValue<Boolean>>() {              @Override             public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Task, Boolean> p) {                 return new SimpleBooleanProperty(p.getValue() != null);             }         });          col_action.setCellFactory(             new Callback<TableColumn<Task, Task>, TableCell<Task, Task>>() {                  @Override                 public TableCell<Task, Task> call(TableColumn<Task, Task> p) {                     return new ButtonCell();                 }             }         );          c1.setCellValueFactory(             new PropertyValueFactory<Task,Date>("date")         );         c2.setCellValueFactory(             new PropertyValueFactory<Task,Task.TaskType>("type")         );         c3.setCellValueFactory(             new PropertyValueFactory<Task,Double>("hours")         );         c4.setCellValueFactory(             new PropertyValueFactory<Task,Boolean>("done")         );         c5.setCellValueFactory(             new PropertyValueFactory<Task,Employee>("employee")         );         c6.setCellValueFactory(             new PropertyValueFactory<Task,Car>("car")         );          tabel.getColumns().addAll(c1, c2, c3, c4, c5, c6, c7);         tabel.setItems(data);          setCenter(tabel);         setBottom(nieuwTaak);      }      //letterlijk van internet geplukt en datatype aangepast     private class ButtonCell extends TableCell<Task, Task> {           private Button cellButton;          ButtonCell(){               cellButton = new Button("jjhjhjh");             cellButton.setOnAction(new EventHandler<ActionEvent>(){                  @Override                 public void handle(ActionEvent t) {                     // do something when button clicked                     Task record = getItem();                     // do something with record....                 }             });         }          //Display button if the row is not empty         @Override         protected void updateItem(Task record, boolean empty) {             super.updateItem(record, empty);             if(!empty){                 cellButton.setText("Something with "+record);                 setGraphic(cellButton);             } else {                 setGraphic(null);             }         }     }  } 

Now the part where I have to create a ButtonCell extends TableCell is understandable. But how to assign this to the column?

I understand this:

c1.setCellValueFactory(         new PropertyValueFactory<Task,Date>("date")     ); 

But not this:

           TableColumn col_action = new TableColumn<>("Action");              col_action.setCellValueFactory(                     new Callback<TableColumn.CellDataFeatures<Task, Boolean>,                      ObservableValue<Boolean>>() {                  @Override                 public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Task, Boolean> p) {                     return new SimpleBooleanProperty(p.getValue() != null);                 }             });              col_action.setCellFactory(                 new Callback<TableColumn<Task, Task>, TableCell<Task, Task>>() {                      @Override                     public TableCell<Task, Task> call(TableColumn<Task, Task> p) {                         return new ButtonCell();                     }                 }             ); 
like image 889
botenvouwer Avatar asked Apr 07 '15 10:04

botenvouwer


People also ask

How do you add a button to a scene in JavaFX?

You can create a Button by instantiating the javafx. scene. control. Button class of this package and, you can set text to the button using the setText() method.

What is TableView in JavaFX?

The TableView class provides built-in capabilities to sort data in columns. Users can alter the order of data by clicking column headers. The first click enables the ascending sorting order, the second click enables descending sorting order, and the third click disables sorting. By default, no sorting is applied.


2 Answers

To be able to render the column, TableColumn needs cellValueFactory. But the "action" column does not exist in underlying data model. In this case, I just give some dummy value to cellValueFactory and move on:

public class JustDoIt extends Application {      private final TableView<Person> table = new TableView<>();     private final ObservableList<Person> data             = FXCollections.observableArrayList(                     new Person("Jacob", "Smith"),                     new Person("Isabella", "Johnson"),                     new Person("Ethan", "Williams"),                     new Person("Emma", "Jones"),                     new Person("Michael", "Brown")             );      public static void main(String[] args) {         launch(args);     }      @Override     public void start(Stage stage) {         stage.setWidth(450);         stage.setHeight(500);          TableColumn firstNameCol = new TableColumn("First Name");         firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));          TableColumn lastNameCol = new TableColumn("Last Name");         lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));          TableColumn actionCol = new TableColumn("Action");         actionCol.setCellValueFactory(new PropertyValueFactory<>("DUMMY"));          Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory                 = //                 new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {             @Override             public TableCell call(final TableColumn<Person, String> param) {                 final TableCell<Person, String> cell = new TableCell<Person, String>() {                      final Button btn = new Button("Just Do It");                      @Override                     public void updateItem(String item, boolean empty) {                         super.updateItem(item, empty);                         if (empty) {                             setGraphic(null);                             setText(null);                         } else {                             btn.setOnAction(event -> {                                 Person person = getTableView().getItems().get(getIndex());                                 System.out.println(person.getFirstName()                                         + "   " + person.getLastName());                             });                             setGraphic(btn);                             setText(null);                         }                     }                 };                 return cell;             }         };          actionCol.setCellFactory(cellFactory);          table.setItems(data);         table.getColumns().addAll(firstNameCol, lastNameCol, actionCol);          Scene scene = new Scene(new Group());          ((Group) scene.getRoot()).getChildren().addAll(table);          stage.setScene(scene);         stage.show();     }      public static class Person {          private final SimpleStringProperty firstName;         private final SimpleStringProperty lastName;          private Person(String fName, String lName) {             this.firstName = new SimpleStringProperty(fName);             this.lastName = new SimpleStringProperty(lName);         }          public String getFirstName() {             return firstName.get();         }          public void setFirstName(String fName) {             firstName.set(fName);         }          public String getLastName() {             return lastName.get();         }          public void setLastName(String fName) {             lastName.set(fName);         }      } } 
like image 104
Uluk Biy Avatar answered Sep 19 '22 20:09

Uluk Biy


Here is my example using awesome Java 8 Functionality and extending TableCell class.

Let me give a quick explanation of what I am doing: I created a ActionButtonTableCell class that extends TableCell. And then you can use java 8 lamda functions to create an Action for the button.

import java.util.function.Function; import javafx.event.ActionEvent; import javafx.scene.control.Button; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.util.Callback;  public class ActionButtonTableCell<S> extends TableCell<S, Button> {      private final Button actionButton;      public ActionButtonTableCell(String label, Function< S, S> function) {         this.getStyleClass().add("action-button-table-cell");          this.actionButton = new Button(label);         this.actionButton.setOnAction((ActionEvent e) -> {             function.apply(getCurrentItem());         });         this.actionButton.setMaxWidth(Double.MAX_VALUE);     }      public S getCurrentItem() {         return (S) getTableView().getItems().get(getIndex());     }      public static <S> Callback<TableColumn<S, Button>, TableCell<S, Button>> forTableColumn(String label, Function< S, S> function) {         return param -> new ActionButtonTableCell<>(label, function);     }      @Override     public void updateItem(Button item, boolean empty) {         super.updateItem(item, empty);          if (empty) {             setGraphic(null);         } else {                             setGraphic(actionButton);         }     } } 

The implementation is then as simple as this, This is a sample button to remove the item from the table:

column.setCellFactory(ActionButtonTableCell.<Person>forTableColumn("Remove", (Person p) -> {     table.getItems().remove(p);     return p; }));     
like image 26
Darrel K. Avatar answered Sep 20 '22 20:09

Darrel K.