title: Javafx 8 Tableview selection with checkbox
body: <p>I've set up a multiselection enabled tableview and am trying to attach a listener a checkbox inserted into a column to the selection model of the table.</p>
  
  <pre><code>checkBoxTableColumn.setCellValueFactory(
              cellData -&gt; {
                  CheckBox checkBox = new CheckBox();
                  ObjectProperty&lt;CheckBox&gt; sop = new SimpleObjectProperty&lt;CheckBox&gt;();
                  sop.setValue(checkBox);
                  sop.getValue().setText("");
  
  
  
                  sop.getValue().selectedProperty().addListener(
                          (obsv, oldv, newv) -&gt; {
                              ArrayList&lt;Job&gt; tempSelectionArray = new ArrayList&lt;&gt;();
  
                              if(newv.booleanValue()){
                                  tempSelectionArray.addAll(jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
                                  this.jobTableView.getSelectionModel().clearSelection();
                                  for(Job job: tempSelectionArray){
                                      jobTableView.getSelectionModel().select(job);
                                  }
  
                                  tempSelectionArray.clear();
                              }
                              else{
                                  tempSelectionArray.addAll(this.jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
                                  this.jobTableView.getSelectionModel().clearSelection();
                                  tempSelectionArray.remove(getJobTableView().getFocusModel().getFocusedItem());
                                  for(Job job: tempSelectionArray){
                                      this.jobTableView.getSelectionModel().select(job);
                                  }
                                  tempSelectionArray.clear();
                              }
                          }
                  );
                  ObservableValue&lt;CheckBox&gt; ov = sop;
  
                  return ov;
              }
  </code></pre>
  
  <p>But that doesn't change the table selection.</p>
  
  <p>Edited as jurge stated</p>
  
  <pre><code>        checkBoxTableColumn.setCellFactory(new Callback&lt;TableColumn&lt;Job, Boolean&gt;, TableCell&lt;Job, Boolean&gt;&gt;() {
          @Override
          public TableCell&lt;Job, Boolean&gt; call(TableColumn&lt;Job, Boolean&gt; param) {
              return new CheckBoxCell(jobTableView);
  
  
          }
      });
  </code></pre>
  
  <p>and checkbox cell is as </p>
  
  <pre><code>class CheckBoxCell extends TableCell&lt;Job, Boolean&gt;{
  private CheckBox checkBox;
  private TableView&lt;Job&gt; jobTableView;
  
  public CheckBoxCell(TableView&lt;Job&gt; tableView){
      this.jobTableView = tableView;
  }
  @Override
  public void updateItem(Boolean item, boolean empty) {
      super.updateItem(item, empty);
  
      checkBox = new CheckBox();
      setGraphic(checkBox);
  
      checkBox.selectedProperty().addListener(
              (obsv, oldv, newv) -&gt; {
                  ArrayList&lt;Job&gt; tempSelectionArray = new ArrayList&lt;&gt;();
  
                  if(newv.booleanValue()){
                      tempSelectionArray.addAll(jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
                      this.jobTableView.getSelectionModel().clearSelection();
                      for(Job job: tempSelectionArray){
                          jobTableView.getSelectionModel().select(job);
                      }
  
                      tempSelectionArray.clear();
                  }
                  else{
                      tempSelectionArray.addAll(this.jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
                      this.jobTableView.getSelectionModel().clearSelection();
                      tempSelectionArray.remove(jobTableView.getFocusModel().getFocusedItem());
                      for(Job job: tempSelectionArray){
                          this.jobTableView.getSelectionModel().select(job);
                      }
                      tempSelectionArray.clear();
                  }
              }
      );
  }
  </code></pre>
  
  <p>}</p>
  
  <p>The listener wouldn't work this time.....</p>
  
  <p>edit-#2</p>
  
  <p>in initialize method of controller:</p>
  
  <pre><code>        jobTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
  
  
      checkBoxTableColumn.setEditable(true);
      checkBoxTableColumn.setCellValueFactory(
              new PropertyValueFactory&lt;Job, Boolean&gt;("isContextSelected")
      );
  
      checkBoxTableColumn.setCellFactory(
              new Callback&lt;TableColumn&lt;Job, Boolean&gt;, TableCell&lt;Job, Boolean&gt;&gt;() {
                  @Override
                  public TableCell&lt;Job, Boolean&gt; call(TableColumn&lt;Job, Boolean&gt; param) {
                      return new CheckBoxTableCell&lt;Job, Boolean&gt;(){
                          {
                              setAlignment(Pos.CENTER);
                          }
  
                          @Override
                          public void updateItem(Boolean item, boolean empty){
                              if(!empty){
                                  TableRow row = getTableRow();
  
                                  if(row != null){
                                      Integer rowNumber = row.getIndex();
                                      TableView.TableViewSelectionModel sm = getTableView().getSelectionModel();
  
                                      if(item){
                                          sm.select(rowNumber);
  
                                      }
                                      else{
                                          sm.clearSelection(rowNumber);
  
                                      }
                                  }
                              }
                              super.updateItem(item, empty);
                          }
                      };
                  }
              }
      );
  </code></pre>
  
  <p>the job class:</p>
  
  <pre><code>    private  BooleanProperty isContextSelected;
      public BooleanProperty isContextSelectedProperty() {
      return isContextSelected;
      }
  </code></pre>
  
  <p>edit--
  Ignore the unnecessary parts. The whole code as requested.:
  The controller:</p>
  
  <pre><code> package BillControl.view;
  
  import BillControl.Controller.PopulateView;
  import BillControl.Controller.Validator;
  import BillControl.MainApp;
  import BillControl.model.Article;
  import BillControl.model.Job;
  import javafx.beans.property.*;
  import javafx.beans.value.ObservableValue;
  import javafx.collections.FXCollections;
  import javafx.collections.ListChangeListener;
  import javafx.collections.ObservableList;
  import javafx.fxml.FXML;
  import javafx.geometry.Pos;
  import javafx.scene.control.*;
  import javafx.scene.control.cell.CheckBoxTableCell;
  import javafx.scene.control.cell.PropertyValueFactory;
  import javafx.stage.Stage;
  import javafx.util.Callback;
  
  
  import java.util.ArrayList;
  import java.util.TreeSet;
  
  
  public class ArticleJobAssignmentController {
      private Article article;
      private Stage jobAssignStage;
      private boolean okClicked = false;
      private MainApp mainApp;
      ArrayList&lt;Job&gt; selectedJobList = new ArrayList&lt;&gt;();
      private ObservableList&lt;Job&gt; masterJobList = FXCollections.observableArrayList();
      private ObservableList&lt;Job&gt; currentJobList = FXCollections.observableArrayList();
      private ObservableList&lt;Job&gt; articleEngagementList = FXCollections.observableArrayList();
      private TreeSet rowIndices = new TreeSet();
  @FXML
  private Label articleNameLabel;
  @FXML
  private Label noOfJobsLabel;
  @FXML
  private Button okButton;
  @FXML
  private Button cancelButton;
  @FXML
  private Label errorLabel;
  
  
  
  @FXML
  private TableView&lt;Job&gt; jobTableView;
  @FXML
  private TableColumn&lt;Job, Boolean&gt; checkBoxTableColumn;
  @FXML
  private TableColumn&lt;Job, String&gt; jobNameColumn;
  @FXML
  private TableColumn&lt;Job, String&gt; clientNameColumn;
  @FXML
  private TableColumn&lt;Job, Integer&gt; noOfArticlesColumn;
  @FXML
  private TableColumn&lt;Job, String&gt; alreadyEngagedColumn;
  
  
  public ArticleJobAssignmentController(){
  
  }
  
  public void initialize(){
  
  
      errorLabel.setVisible(false);
      jobTableView.setEditable(true);
      jobTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
  
  
      checkBoxTableColumn.setEditable(true);
      checkBoxTableColumn.setCellValueFactory(
              new PropertyValueFactory&lt;Job, Boolean&gt;("isContextSelected")
      );
  
      checkBoxTableColumn.setCellFactory(
              new Callback&lt;TableColumn&lt;Job, Boolean&gt;, TableCell&lt;Job, Boolean&gt;&gt;() {
                  @Override
                  public TableCell&lt;Job, Boolean&gt; call(TableColumn&lt;Job, Boolean&gt; param) {
                      return new CheckBoxTableCell&lt;Job, Boolean&gt;(){
                          {
                              setAlignment(Pos.CENTER);
                          }
  
                          @Override
                          public void updateItem(Boolean item, boolean empty){
                              if(!empty){
                                  TableRow row = getTableRow();
  
                                  if(row != null){
                                      Integer rowNumber = row.getIndex();
                                      TableView.TableViewSelectionModel sm = getTableView().getSelectionModel();
  
                                      if(item){
                                          sm.select(rowNumber);
  
                                      }
                                      else{
                                          sm.clearSelection(rowNumber);
  
                                      }
                                  }
                              }
                              super.updateItem(item, empty);
                          }
                      };
                  }
              }
      );
  
  
  
      jobNameColumn.setCellValueFactory(
              cellData -&gt; cellData.getValue().nameProperty()
      );
  
      noOfArticlesColumn.setCellValueFactory(
              cellData -&gt; {
                  SimpleIntegerProperty sip = new SimpleIntegerProperty(cellData.getValue().numberOfArticlesProperty().getValue());
                  ObservableValue&lt;Integer&gt; ov = sip.asObject();
                  return ov;
              }
  
      );
  
      alreadyEngagedColumn.setCellValueFactory(
          cellData -&gt; {
              Boolean engaged = false;
              for(Job job: articleEngagementList){
                  if(job.getNumberID().equals(cellData.getValue().getNumberID())){
                      engaged = true;
                  }
              }
  
              if(engaged){
                  SimpleStringProperty sbp = new SimpleStringProperty("Yes");
                  ObservableValue&lt;String&gt; ov = sbp;
                  return ov;
              }
              else {
                  SimpleStringProperty sbp = new SimpleStringProperty("No");
                  ObservableValue&lt;String&gt; ov = sbp;
                  return ov;
              }
          }
      );
  
      jobTableView.getSelectionModel().getSelectedItems().addListener(
              new ListChangeListener&lt;Job&gt;() {
                  @Override
                  public void onChanged(Change&lt;? extends Job&gt; c) {
                      noOfJobsLabel.setText(String.valueOf(c.getList().size()));
                  }
              }
      );
  
  
  
  
  
  
  }
  
  public void filterMasterList(){
      for(Job job : masterJobList){
          if(!job.getIsCompleted()){
              currentJobList.add(job);
          }
      }
  
      for(Job currentJob : currentJobList){
          currentJob.setIsContextSelected(false);
      }
  }
  
  
  @FXML
  public void handleOkClicked(){
      if(!Validator.articleJobAssignment(this)){
  
          for(Job job : jobTableView.getSelectionModel().getSelectedItems()){
              selectedJobList.add(job);
          }
          okClicked = true;
          jobAssignStage.close();
      }
      else {
          errorLabel.setText("Select at least one job");
          errorLabel.setVisible(true);
      }
  }
  
  @FXML
  public void handleCancelClicked(){
      jobAssignStage.close();
  }
  
  public void setArticle(Article article) {
      this.article = article;
      articleNameLabel.setText(article.getName());
  
  }
  
  public void setJobAssignStage(Stage jobAssignStage) {
      this.jobAssignStage = jobAssignStage;
  }
  
  public void setOkClicked(boolean okClicked) {
      this.okClicked = okClicked;
  }
  
  public void setMainApp(MainApp mainApp) {
      this.mainApp = mainApp;
      setMasterJobList(mainApp.getJobObservableList());
      filterMasterList();
      jobTableView.setItems(currentJobList);
  
      if(article != null){
          articleEngagementList = PopulateView.articleCurrentEngagementList(articleEngagementList, article.getId(), mainApp.getClientObservableList());
      }
  }
  
  public Label getArticleNameLabel() {
      return articleNameLabel;
  }
  
  public Label getNoOfJobsLabel() {
      return noOfJobsLabel;
  }
  
  public Button getOkButton() {
      return okButton;
  }
  
  public Button getCancelButton() {
      return cancelButton;
  }
  
  public TableView&lt;Job&gt; getJobTableView() {
      return jobTableView;
  }
  
  public TableColumn&lt;Job, String&gt; getJobNameColumn() {
      return jobNameColumn;
  }
  
  public TableColumn&lt;Job, String&gt; getClientNameColumn() {
      return clientNameColumn;
  }
  
  public TableColumn&lt;Job, Integer&gt; getNoOfArticlesColumn() {
      return noOfArticlesColumn;
  }
  
  public ObservableList&lt;Job&gt; getMasterJobList() {
      return masterJobList;
  }
  
  public void setMasterJobList(ObservableList&lt;Job&gt; masterJobList) {
      this.masterJobList = masterJobList;
  }
  
  public boolean isOkClicked() {
      return okClicked;
  }
  
  public ArrayList&lt;Job&gt; getSelectedJobList() {
      return selectedJobList;
  }
  }
  </code></pre>
  
  <p>the job class(ignore the constructors):</p>
  
  <pre><code>package BillControl.model;
  
  
  import BillControl.Controller.PopulateItems;
  import BillControl.GeneralUtils.DateUtil;
  import javafx.beans.property.*;
  import javafx.collections.ObservableList;
  
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.concurrent.TimeUnit;
  
  
  public class Job {
      private  String numberID;
      private  StringProperty name;
      private  ObjectProperty&lt;Client&gt; client;
      private  StringProperty clientName;
      private  ObjectProperty&lt;Date&gt; startPeriod;
      private  ObjectProperty&lt;Date&gt; endPeriod;
      private  ObjectProperty&lt;Date&gt; startDate;
      private  ObjectProperty&lt;Date&gt; targetDate;
      private  BooleanProperty isDelayed;
      private  LongProperty remainingDays;
      private  LongProperty delayedDays;
      private  BooleanProperty isCompleted;
      private  ObjectProperty&lt;Date&gt; completionDate;
      private  LongProperty daysToComplete;
      private  StringProperty partner;
      private  IntegerProperty numberOfArticles;
      private  BooleanProperty isContextSelected;
  
  private String clientID;
  
  public Job(Client client){
  
  
      this.numberID = null;
  
          this.client = new SimpleObjectProperty&lt;Client&gt;(client);
          this.clientName = new SimpleStringProperty(client.getName());
          this.name = new SimpleStringProperty("");
          this.partner = new SimpleStringProperty("");
          this.startDate = new SimpleObjectProperty&lt;Date&gt;();
          this.targetDate = new SimpleObjectProperty&lt;Date&gt;();
          this.completionDate = new SimpleObjectProperty&lt;Date&gt;();
          this.isCompleted = new SimpleBooleanProperty(false);
          this.startPeriod = new SimpleObjectProperty&lt;Date&gt;();
          this.endPeriod = new SimpleObjectProperty&lt;Date&gt;();
          this.fillOthers(false);
      //        todo check fill others logic
  
  
      }
  
      public Job(ObservableList clientList, String numberID){
          this.numberID = numberID;
  //        this.numberID = null;
          this.name = new SimpleStringProperty("");
          this.partner = new SimpleStringProperty("");
          this.startDate = new SimpleObjectProperty&lt;Date&gt;();
          this.targetDate = new SimpleObjectProperty&lt;Date&gt;();
          this.completionDate = new SimpleObjectProperty&lt;Date&gt;();
          this.isCompleted = new SimpleBooleanProperty(false);
          this.startPeriod = new SimpleObjectProperty&lt;Date&gt;();
          this.endPeriod = new SimpleObjectProperty&lt;Date&gt;();
          this.client = new SimpleObjectProperty&lt;Client&gt;();
          this.clientName = new SimpleStringProperty();
          this.numberOfArticles = new SimpleIntegerProperty();
          this.isContextSelected = new SimpleBooleanProperty(false);
          PopulateItems.populateJob(this);
          Client selectedClient = null;
      for(Object clientObject :  clientList){
          Client queriedClient = (Client) clientObject;
          String name =  queriedClient.getName();
          String queriedName = PopulateItems.clientID2NameHelper(this.getClientID());
          if(name.equals(queriedName)){
              selectedClient = (Client) clientObject;
              break;
          }
      }
      this.setClient(selectedClient);
      this.setClientName(this.getClient().getName());
  
      this.fillOthers(true);
  }
  
  public Job(){
      this.numberID = null;
      this.client = new SimpleObjectProperty&lt;Client&gt;();
      this.clientName = new SimpleStringProperty("");
      this.name = new SimpleStringProperty("");
      this.partner = new SimpleStringProperty("");
      this.startDate = new SimpleObjectProperty&lt;Date&gt;();
      this.targetDate = new SimpleObjectProperty&lt;Date&gt;();
      this.completionDate = new SimpleObjectProperty&lt;Date&gt;();
      this.isCompleted = new SimpleBooleanProperty(false);
      this.startPeriod = new SimpleObjectProperty&lt;Date&gt;();
      this.endPeriod = new SimpleObjectProperty&lt;Date&gt;();
      this.fillOthers(false);
  }
  
  public void fillOthers(Boolean filledJob){
      if(filledJob){
  
          DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
          try {
              Date startDate = this.getStartDate();
              Date completionDate = this.getCompletionDate();
              Date currentDate = DateUtil.getCurrentDate();
              Date targetDate = this.getTargetDate();
  
  
  
              if (this.getIsCompleted()){
  //                completion days
                      this.daysToComplete = new SimpleLongProperty();
                      long duration = completionDate.getTime() - startDate.getTime();
                      long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);
                      this.setDaysToComplete(diffInDays);
  
              }
              else{
                  this.remainingDays = new SimpleLongProperty();
                  this.isDelayed = new SimpleBooleanProperty();
                  if (targetDate.after(currentDate) &amp;&amp; !this.getIsCompleted()){
  
                      //            remaining days
                      long duration = targetDate.getTime() - currentDate.getTime();
                      long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);
                      this.setRemainingDays(diffInDays);
                      this.setIsDelayed(false);
                  }
                  else if (targetDate.before(currentDate) &amp;&amp; !this.getIsCompleted()) {
  //                delayed days
                          this.delayedDays = new SimpleLongProperty();
                          this.setIsDelayed(true);
                          long duration = currentDate.getTime() - targetDate.getTime();
                          long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);
                          this.setRemainingDays(0);
                          this.setDelayedDays(diffInDays);
                      }
                  }
  
              }
  
          catch (Exception e){
              e.printStackTrace();
          }
      }
      else {
  //TODO client creation form job
      }
  
  }
  
  public String getName() {
      return name.get();
  }
  
  public StringProperty nameProperty() {
      return name;
  }
  
  public void setName(String name) {
      this.name.set(name);
  }
  
  public Client getClient() {
      return client.get();
  }
  
  public ObjectProperty&lt;Client&gt; clientProperty() {
      return client;
  }
  
  public void setClient(Client client) {
      this.client.set(client);
  }
  
  public Date getStartDate() {
      return startDate.get();
  }
  
  public ObjectProperty&lt;Date&gt; startDateProperty() {
      return startDate;
  }
  
  public void setStartDate(Date startDate) {
      this.startDate.set(startDate);
  }
  
  public Date getTargetDate() {
      return targetDate.get();
  }
  
  public ObjectProperty&lt;Date&gt; targetDateProperty() {
      return targetDate;
  }
  
  public void setTargetDate(Date targetDate) {
      this.targetDate.set(targetDate);
  }
  
  public boolean getIsDelayed() {
      return isDelayed.get();
  }
  
  public BooleanProperty isDelayedProperty() {
      return isDelayed;
  }
  
  public void setIsDelayed(boolean isDelayed) {
      this.isDelayed.set(isDelayed);
  }
  
  public long getRemainingDays() {
      return remainingDays.get();
  }
  
  public LongProperty remainingDaysProperty() {
      return remainingDays;
  }
  
  public void setRemainingDays(long remainingDays) {
      this.remainingDays.set(remainingDays);
  }
  
  public long getDelayedDays() {
      return delayedDays.get();
  }
  
  public LongProperty delayedDaysProperty() {
      return delayedDays;
  }
  
  public void setDelayedDays(long delayedDays) {
      this.delayedDays.set(delayedDays);
  }
  
  public boolean getIsCompleted() {
      return isCompleted.get();
  }
  
  public BooleanProperty isCompletedProperty() {
      return isCompleted;
  }
  
  public void setIsCompleted(boolean isCompleted) {
      this.isCompleted.set(isCompleted);
  }
  
  public Date getCompletionDate() {
      return completionDate.get();
  }
  
  public ObjectProperty&lt;Date&gt; completionDateProperty() {
      return completionDate;
  }
  
  public void setCompletionDate(Date completionDate) {
      this.completionDate.set(completionDate);
  }
  
  public long getDaysToComplete() {
      return daysToComplete.get();
  }
  
  public LongProperty daysToCompleteProperty() {
      return daysToComplete;
  }
  
  public void setDaysToComplete(long daysToComplete) {
      this.daysToComplete.set(daysToComplete);
  }
  
  public String getPartner() {
      return partner.get();
  }
  
  public StringProperty partnerProperty() {
      return partner;
  }
  
  public void setPartner(String partner) {
      this.partner.set(partner);
  }
  
  public Integer getNumberOfArticles() {
      return numberOfArticles.get();
  }
  
  public IntegerProperty numberOfArticlesProperty() {
      return numberOfArticles;
  }
  
  public void setNumberOfArticles(int numberOfArticles) {
      this.numberOfArticles.set(numberOfArticles);
  }
  
  public String getNumberID() {
      return numberID;
  }
  
  public String getClientName() {
      return clientName.get();
  }
  
  public StringProperty clientNameProperty() {
      return clientName;
  }
  
  public void setClientName(String clientName) {
      this.clientName.set(clientName);
  }
  
  public Date getStartPeriod() {
      return startPeriod.get();
  }
  
  public ObjectProperty&lt;Date&gt; startPeriodProperty() {
      return startPeriod;
  }
  
  public void setStartPeriod(Date startPeriod) {
      this.startPeriod.set(startPeriod);
  }
  
  public Date getEndPeriod() {
      return endPeriod.get();
  }
  
  public ObjectProperty&lt;Date&gt; endPeriodProperty() {
      return endPeriod;
  }
  
  public void setEndPeriod(Date endPeriod) {
      this.endPeriod.set(endPeriod);
  }
  
  public String getClientID() {
      return clientID;
  }
  
  public void setClientID(String clientID) {
      this.clientID = clientID;
  }
  
  public boolean getIsContextSelected() {
      return isContextSelected.get();
  }
  
  public BooleanProperty isContextSelectedProperty() {
      return isContextSelected;
  }
  
  public void setIsContextSelected(boolean isContextSelected) {
      this.isContextSelected.set(isContextSelected);
  }
  }
  </code></pre>