I have a issue with sorting in table view and seeing a weird behavior. I have a table with 3 columns (Column Zero, Column First, Column Second) and all columns are set to setSortable(true). When I click on the column header on column First or Column Second, it doesn't sort the rows properly.
- Each rows data is stored inside a Person Object.
- Each column data is stored inside a Hashmap with key as the column index. Column 1's data is stored with key as 1 and columns 2 data is stored with key as 2 and so on and so forth.
The problem I am facing is when I click on the header to sort alphabetically, it doesn't sort properly.
Also, Whenever I click on any column header, only column zero is sorted and not the other column.
Sample code attached.
Please help.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
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);
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;
}
}
}