1 Reply Latest reply: Nov 2, 2012 8:51 AM by James_D RSS

    Get complete object inside comparator

    964914
      I have a table view with 3 columns. The value for each column is stored inside a map. Column 1's data is stored inside the map with 1 as the key, and so on so forth. Now I need to sort the column by clicking on the header of each column. I have set the comparator for the column and is shown in the below code. The parameters to the compare method of the comparator takes the same parameter as the cell's data which is CellValueFactory 's data type. The code works fine. Now my requirement is I need to access other member data of the Person object to sort the columns. Say for example take the person name into consideration for sorting. Now the question is how do I get hold of person name member variable of Person object inside the comparator method. The comparator method just gets only the values(VOBean<Integer>) member of Person object and not the person name value. Now how to do this? Also, Is it possible to get hold of the entire object inside the compare method?
      TableColumn<Person, VOBean<Integer>> column2 = new TableColumn<>("Column Second");
              column2.setCellValueFactory(new PropertyValueFactory<Person, VOBean<Integer>>("values"));
      
              Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>> myCellFactory2 =
                      new Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>>() {
      
                          @Override
                          public TableCell<Person, VOBean<Integer>> call(TableColumn<Person, VOBean<Integer>> p) {
                              CustomCellFactory cscellFactory = new CustomCellFactory(2, "secondName");
      
                              return cscellFactory;
                          }
                      };
              column2.setCellFactory(myCellFactory2);
              column2.setEditable(true);
              column2.setSortable(true);
              column2.setPrefWidth(200.0);
              column2.setComparator(new Comparator<VOBean<Integer>>() {
                  @Override
                  public int compare(VOBean<Integer> o1, VOBean<Integer> o2) {
                      String s1 = (String) o1.getValue(new Integer(2));
                      String s2 = (String) o2.getValue(new Integer(2));
                      
                      return Collator.getInstance().compare(s1, s2);
                  }
              });
      -- Complete code is given below.
      package test;
       
      import java.io.Serializable;
      import java.util.HashMap;
      import java.util.Map;
      import javafx.application.Application;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.geometry.Insets;
      import javafx.scene.Group;
      import javafx.scene.Scene;
      import javafx.scene.control.Label;
      import javafx.scene.control.TableCell;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.TableView;
      import javafx.scene.control.cell.PropertyValueFactory;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.VBox;
      import javafx.scene.text.Font;
      import javafx.scene.text.Text;
      import javafx.stage.Stage;
      import javafx.util.Callback;
       
      /**
       *
       */
      public class Sample1 extends Application {
       
          private TableView<Person> table = new TableView();
          private final ObservableList<Person> data = populatePersons();
          final HBox hb = new HBox();
       
          private ObservableList<Person> populatePersons() {
              Person p1 = new Person("alex john");
              VOBean<Integer> p1columnValues = p1.getValues();
              p1columnValues.addValue(0, "A13");
              p1columnValues.addValue(1, "alex john Column 1 value");
              p1columnValues.addValue(2, "alex");
       
       
              Person p2 = new Person("ethan williams");
              VOBean<Integer> p2columnValues = p2.getValues();
              p2columnValues.addValue(0, "A14");
              p2columnValues.addValue(1, "ethan williams Column 1 value");
              p2columnValues.addValue(2, "ethan");
       
       
              Person p3 = new Person("isabella johnson");
              VOBean<Integer> p3columnValues = p3.getValues();
              p3columnValues.addValue(0, "A15");
              p3columnValues.addValue(1, "isabella johnson Column 1 value");
              p3columnValues.addValue(2, "isabella");
       
       
              Person p4 = new Person("emma jones");
              VOBean<Integer> p4columnValues = p4.getValues();
              p4columnValues.addValue(0, "A115");
              p4columnValues.addValue(1, "emma jones Column 1 value");
              p4columnValues.addValue(2, "emma");
       
       
              Person p5 = new Person("michael brown");
              VOBean<Integer> p5columnValues = p5.getValues();
              p5columnValues.addValue(0, "A16");
              p5columnValues.addValue(1, "michael brown Column 1 value");
              p5columnValues.addValue(2, "michael");
       
       
              Person p6 = new Person("jacob smith");
              VOBean<Integer> p6columnValues = p6.getValues();
              p6columnValues.addValue(0, "A1");
              p6columnValues.addValue(1, "jacob smith Column 1 value");
              p6columnValues.addValue(2, "jacob");
       
       
              Person p7 = new Person("micheal clark");
              VOBean<Integer> p7columnValues = p7.getValues();
              p7columnValues.addValue(0, "A2");
              p7columnValues.addValue(1, "micheal clark Column 1 value");
              p7columnValues.addValue(2, "micheal");
       
       
              Person p8 = new Person("paul adam");
              VOBean<Integer> p8columnValues = p8.getValues();
              p8columnValues.addValue(0, "A3");
              p8columnValues.addValue(1, "paul adam Column 1 value");
              p8columnValues.addValue(2, "paul");
       
       
              Person p9 = new Person("peter scott");
              VOBean<Integer> p9columnValues = p9.getValues();
              p9columnValues.addValue(0, "Z4");
              p9columnValues.addValue(1, "peter scott Column 1 value");
              p9columnValues.addValue(2, "peter");
       
       
              Person p10 = new Person("scott tiger");
              VOBean<Integer> p10columnValues = p10.getValues();
              p10columnValues.addValue(0, "A5");
              p10columnValues.addValue(1, "scott tiger Column 1 value");
              p10columnValues.addValue(2, "scott");
       
       
              Person p11 = new Person("hello world");
              VOBean<Integer> p11columnValues = p11.getValues();
              p11columnValues.addValue(0, "A6");
              p11columnValues.addValue(1, "hello world Column 1 value");
              p11columnValues.addValue(2, "hello");
       
       
              Person p12 = new Person("james watson");
              VOBean<Integer> p12columnValues = p12.getValues();
              p12columnValues.addValue(0, "A7");
              p12columnValues.addValue(1, "james watson Column 1 value");
              p12columnValues.addValue(2, "james");
       
       
              Person p13 = new Person("harry watson");
              VOBean<Integer> p13columnValues = p13.getValues();
              p13columnValues.addValue(0, "W8");
              p13columnValues.addValue(1, "harry watson Column 1 value");
              p13columnValues.addValue(2, "harry");
       
       
              Person p14 = new Person("issac henry");
              VOBean<Integer> p14columnValues = p14.getValues();
              p14columnValues.addValue(0, "A9");
              p14columnValues.addValue(1, "issac henry Column 1 value");
              p14columnValues.addValue(2, "issac");
              p14.setValues(p14columnValues);
       
              Person p15 = new Person("daniel kate");
              VOBean<Integer> p15columnValues = p15.getValues();
              p15columnValues.addValue(0, "A10");
              p15columnValues.addValue(1, "daniel kate Column 1 value");
              p15columnValues.addValue(2, "daniel");
       
       
              Person p16 = new Person("james cameroon");
              VOBean<Integer> p16columnValues = p16.getValues();
              p16columnValues.addValue(0, "A11");
              p16columnValues.addValue(1, "james cameroon Column 1 value");
              p16columnValues.addValue(2, "james");
       
       
              Person p17 = new Person("victor adams");
              VOBean<Integer> p17columnValues = p17.getValues();
              p17columnValues.addValue(0, "A12");
              p17columnValues.addValue(1, "victor adams Column 1 value");
              p17columnValues.addValue(2, "victor");
       
              ObservableList<Person> allPersonsData = FXCollections.observableArrayList();
              allPersonsData.add(p1);
              allPersonsData.add(p2);
              allPersonsData.add(p3);
              allPersonsData.add(p4);
              allPersonsData.add(p5);
              allPersonsData.add(p6);
              allPersonsData.add(p7);
              allPersonsData.add(p8);
              allPersonsData.add(p9);
              allPersonsData.add(p10);
              allPersonsData.add(p11);
              allPersonsData.add(p12);
              allPersonsData.add(p13);
              allPersonsData.add(p14);
              allPersonsData.add(p15);
              allPersonsData.add(p16);
              allPersonsData.add(p17);
              return allPersonsData;
       
          }
       
          public static void main(String[] args) {
              launch(args);
          }
       
          @Override
          public void start(Stage stage) {
              Scene scene = new Scene(new Group());
              stage.setTitle("Table View Sample");
              stage.setWidth(800);
              stage.setHeight(500);
       
              final Label label = new Label("Table View Sorting");
              label.setFont(new Font("Arial", 20));
       
              table.setEditable(true);
       
              TableColumn<Person, VOBean<Integer>> column0 = new TableColumn("Column Zero");
              column0.setCellValueFactory(new PropertyValueFactory<Person, VOBean<Integer>>("values"));
       
              Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>> myCellFactory0 =
                      new Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>>() {
       
                          @Override
                          public TableCell<Person, VOBean<Integer>> call(TableColumn<Person, VOBean<Integer>> p) {
                              CustomCellFactory cscellFactory = new CustomCellFactory(0, "zeroName");
       
                              return cscellFactory;
                          }
                      };
              column0.setCellFactory(myCellFactory0);
              column0.setEditable(true);
              column0.setSortable(true);
              column0.setPrefWidth(200.0);
       
       
              TableColumn<Person, VOBean<Integer>> column1 = new TableColumn("Column First");
              column1.setCellValueFactory(new PropertyValueFactory<Person, VOBean<Integer>>("values"));
       
              Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>> myCellFactory =
                      new Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>>() {
       
                          @Override
                          public TableCell<Person, VOBean<Integer>> call(TableColumn<Person, VOBean<Integer>> p) {
                              CustomCellFactory cscellFactory = new CustomCellFactory(1, "firstName");
       
                              return cscellFactory;
                          }
                      };
              column1.setCellFactory(myCellFactory);
              column1.setEditable(true);
              column1.setSortable(true);
              column1.setPrefWidth(200.0);
       
              TableColumn<Person, VOBean<Integer>> column2 = new TableColumn("Column Second");
              column2.setCellValueFactory(new PropertyValueFactory<Person, VOBean<Integer>>("values"));
       
              Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>> myCellFactory2 =
                      new Callback<TableColumn<Person, VOBean<Integer>>, TableCell<Person, VOBean<Integer>>>() {
       
                          @Override
                          public TableCell<Person, VOBean<Integer>> call(TableColumn<Person, VOBean<Integer>> p) {
                              CustomCellFactory cscellFactory = new CustomCellFactory(2, "secondName");
       
                              return cscellFactory;
                          }
                      };
              column2.setCellFactory(myCellFactory2);
              column2.setEditable(true);
              column2.setSortable(true);
              column2.setPrefWidth(200.0);
              column2.setComparator(new Comparator<VOBean<Integer>>() {
                  @Override
                  public int compare(VOBean<Integer> o1, VOBean<Integer> o2) {
                      String s1 = (String) o1.getValue(new Integer(2));
                      String s2 = (String) o2.getValue(new Integer(2));
                      
                      return Collator.getInstance().compare(s1, s2);
                  }
              });
      
              table.setItems(data);
              table.getColumns().addAll(column0, column1, column2);
       
              hb.setSpacing(3);
       
              final VBox vbox = new VBox();
              vbox.setSpacing(5);
              vbox.setPadding(new Insets(10, 0, 0, 10));
              vbox.getChildren().addAll(label, table, hb);
       
              ((Group) scene.getRoot()).getChildren().addAll(vbox);
       
              stage.setScene(scene);
              stage.show();
          }
       
          public class Person {
       
              private String personName;
       
              public Person() {
                  super();
              }
              private VOBean<Integer> values = new VOBean();
       
              private Person(String personName) {
                  this.personName = personName;
              }
       
              public String getPersonName() {
                  return personName;
              }
       
              public void setPersonName(String personName) {
                  this.personName = personName;
              }
       
              public VOBean<Integer> getValues() {
                  return values;
              }
       
              public void setValues(VOBean<Integer> values) {
                  this.values = values;
              }
          }
       
          public class VOBean<T> implements Serializable {
       
              private static final long serialVersionUID = 1L;
       
              public VOBean() {
                  super();
              }
              private Map<T, Object> values;
       
              public Map<T, Object> getValues() {
                  return values;
              }
       
              public void setValues(Map<T, Object> values) {
       
                  this.values = values;
       
              }
       
              public Object getValue(T key) {
                  if (getValues() != null) {
                      return getValues().get(key);
                  }
                  return null;
              }
       
              public void addValue(T key, Object value) {
                  if (getValues() == null) {
                      setValues(new HashMap<T, Object>());
                  }
                  getValues().put(key, value);
              }
       
              public Object removeValue(T key) {
                  if (getValues() == null || getValues().isEmpty()) {
                      return null;
                  }
                  return getValues().remove(key);
              }
       
              public boolean isEmpty() {
                  if (getValues() == null || getValues().isEmpty()) {
                      return true;
                  }
                  return false;
              }
       
              @Override
              public String toString() {
                  return "VOBean{" + "values=" + values + '}';
              }
          }
       
          public class CustomCellFactory extends TableCell<Person, VOBean<Integer>> {
       
              private static final long serialVersionUID = 1L;
       
              public CustomCellFactory() {
                  super();
              }
       
              public CustomCellFactory(Integer columnIndex, String columnName) {
                  super();
                  this.columnIndex = columnIndex;
                  this.columnName = columnName;
              }
              private String columnName;
              private Text inputText;
              private Integer columnIndex;
       
              @Override
              public void updateItem(VOBean<Integer> item, boolean empty) {
                  super.updateItem(item, empty);
       
                  if (item != null) {
                      Object cellData = null;
                      cellData = ((VOBean) item).getValues().get(getColumnIndex());
                      if (cellData != null) {
                          inputText = new Text(cellData.toString());
                      } else {
                          inputText = new Text("");
                      }
                      setGraphic(inputText);
                  }
              }
       
              public Integer getColumnIndex() {
                  return columnIndex;
              }
       
              public void setColumnIndex(Integer columnIndex) {
                  this.columnIndex = columnIndex;
              }
       
              public String getColumnName() {
                  return columnName;
              }
       
              public void setColumnName(String columnName) {
                  this.columnName = columnName;
              }
          }
      }
        • 1. Re: Get complete object inside comparator
          James_D
          AFAIK, there isn't a direct way to get hold of the object associated with the "current row" in the comparator. You're kind of pushing the intention of the API here: the comparator provided to the column's setComparator(...) method is intended to define the order of the values in that column. Here your values are the VOBean<Integer> objects, so your comparator is allowed to define the order of those objects, without reference to anything else.

          So the first question is: why do you want to reference values outside of this column when determining the order of values in this column? Tables also support a "Sort order", so if the intention is to break ties, this is already handled by a different part of the API. If it's something else, you might want to reconsider redesigning your data model first.

          If you really want to do this, I can think of two ways to do so. Neither are particularly elegant, but they'll do what you want.

          First, and perhaps simplest, would be to define a reference to the Person in the VOBean<Integer> class. I never like these bidirectional references (Person owns a reference to VOBean and VOBean owns a reference to Person), but it would solve your problem:
          public class VOBean<T> implements Serializable {
            ...
            private Person owner;
            public VOBean(Person owner) {
              this.owner = owner ;
            }
            ...
            // get and set methods for owner...
          }
          then:
          public class Person {
            ...
            private VOBean<Integer> values = new VOBean(this);
            ...
          }
          and in your comparator:
          public void compare(VOBean<Integer> o1, VOBean<Integer> o2) {
            Person p1 = o1.getOwner();
            Person p2 = o2.getOwner();
            // now you have access to all the data you need
          }
          The second option is to make the type of the column a Person, change your cell factory to retrieve the data to display from the Person, rather than the VOBean object, and change the cellValueFactory to trivially wrap the person object:
          TableColumn<Person, Person> column2 = new TableColumn("Column Second");
          column2.setCellValueFactory(new Callback<CellDataFeatures<Person, Person>, ObservableValue<Person>>() {
               public ObservableValue<Person> call(CellDataFeatures<Person, Person> p) {
                   return new ReadOnlyObjectWrapper(p);
               }
           });
          ...
          column2.setComparator(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
              // again, you now have all the data you need...
            }
          });
          public class CustomCellFactory extends TableCell<Person, Person> {
            ...
            @Override
            public void updateItem(Person person, boolean empty) {
              super.updateItem(person, empty);
              VOBean<Integer> item = person.getValues();
              // code as before ...
            }
            ...
          }
          Hope that helps.