0

I'm attempting to do something related to stackoverflow-17693136. The "first name" table will serve as the frozen columns. I am using a single SortedList in both tables and I have bound the sorted data to the table on the right.

So the data in the first name table is sorted when either column in the right table is sorted. But, I would like to also be able to sort the columns in the right table by clicking on the header in the first name table. I'm currently at a loss to find a good way to bind the comparator for both tables to the sorted data. The commented out code just under 2. Bind the SortedList..., you can see in the TableSort.java code shows what I wish I could do. I currently have set the firstNameColumn to not be sortable (line 45).

This code is similar to an example from Marko Jakob.

TableSort2.java:

package tablesort2;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class TableSort2 extends Application 
{
  private TableView<Person> personTable;
  private TableView<Person> firstNameTable;
  private TableColumn<Person, String> firstNameColumn;     // In firstNameTable
  private TableColumn<Person, String> lastNameColumn;      // In personTable
  private TableColumn<Person, Number> idValueColumn;       // In personTable

  private ObservableList<Person> masterData = FXCollections.observableArrayList();

  @Override
  public void start(Stage primaryStage) 
  {
    // Just add some sample data in the initialization
    masterData.add(new Person("Hans", "Muster", 3210));
    masterData.add(new Person("Ruth", "Mueller", 2625));
    masterData.add(new Person("Heinz", "Kurz", 1234));
    masterData.add(new Person("Cornelia", "Meier", 9999));
    masterData.add(new Person("Werner", "Meyer", 5623));
    masterData.add(new Person("Lydia", "Kunz", 7834));
    masterData.add(new Person("Anna", "Best", 2942));
    masterData.add(new Person("Stefan", "Meier", 9423));
    masterData.add(new Person("Martin", "Mueller", 9122));

    // 0. Initialize the columns
    firstNameColumn = new TableColumn("First Name");
    firstNameColumn.setSortable(false);

    lastNameColumn = new TableColumn("Last Name");
    idValueColumn = new TableColumn("Id Number");

    firstNameColumn.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
    lastNameColumn.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
    idValueColumn.setCellValueFactory(cellData -> cellData.getValue().idValueProperty());

    idValueColumn.setComparator((Number o1, Number o2) -> 
    {
      return (o1.intValue() < o2.intValue() ? -1 : o1.intValue() == o2.intValue() ? 0 : 1);
    });

    firstNameTable = new TableView<>();
    personTable = new TableView<>();

    // 1. Wrap the ObservableList in a SortedList.
    SortedList<Person> sortedData = new SortedList<>(masterData);

    // 2. Bind the SortedList comparator to the TableView(s) comparator.
    //sortedData.comparatorProperty().bind(firstNameTable.comparatorProperty());
    sortedData.comparatorProperty().bind(personTable.comparatorProperty());


    // 3. Add sorted data to the tables.
    firstNameTable.setItems(sortedData);
    personTable.setItems(sortedData);

    firstNameTable.getColumns().add(firstNameColumn);
    personTable.getColumns().addAll(lastNameColumn, idValueColumn);

    HBox tableBox = new HBox(5);
    tableBox.getChildren().addAll(firstNameTable, personTable);

    Scene scene = new Scene(tableBox);
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  public static void main(String[] args) 
  {
    launch(args);
  }
}

Person.java:

package tablesort2;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

/**
 *
 * @author dale
 */
public class Person
{
  private final StringProperty firstName;
  private final StringProperty lastName;
  private final IntegerProperty idValue;

  public Person(String firstName, String lastName, Integer id)
  {
    this.firstName = new SimpleStringProperty(firstName);
    this.lastName = new SimpleStringProperty(lastName);
    this.idValue = new SimpleIntegerProperty(id);
  }

  public String getFirstName()
  {
    return firstName.get();
  }

  public void setFirstName(String firstName)
  {
    this.firstName.set(firstName);
  }

  public StringProperty firstNameProperty()
  {
    return firstName;
  }

  public String getLastName()
  {
    return lastName.get();
  }

  public void setLastName(String lastName)
  {
    this.lastName.set(lastName);
  }

  public StringProperty lastNameProperty()
  {
    return lastName;
  }

  public Integer getIdValue()
  {
    return idValue.get();
  }

  public void setIdValue(Integer id)
  {
    this.idValue.set(id);
  }

  public IntegerProperty idValueProperty()
  {
    return idValue;
  }
}
Community
  • 1
  • 1

1 Answers1

0

I believe that I have found in stackoverflow-25144215, (in the answer from James_D) something that will work. I can use a Label for each column and then use setGraphic with the Label. This allows me to add an event filter for each column. If a MOUSE_PRESSED event is detected, the sortedData.comparatorProperty() is bound to the table where that column exists. This apparently happens before the actual sort. This is shown in the updated TableSort2.java (below).

This won't work for multi-column sorts across tables - but it doesn't cause an exception for this case. (I also see that this requires me to manually adjust the column width to account for the Label size).

package tablesort2;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class TableSort2 extends Application 
{
  private TableView<Person> personTable;
  private TableView<Person> firstNameTable;
  private TableColumn<Person, String> firstNameColumn;     // In firstNameTable
  private Label firstNameLabel;                   

  private TableColumn<Person, String> lastNameColumn;      // In personTable
  private Label lastNameLabel;

  private TableColumn<Person, Number> idValueColumn;       // In personTable
  private Label idValueLabel;

  private ObservableList<Person> masterData = FXCollections.observableArrayList();

  @Override
  public void start(Stage primaryStage) 
  {
    // Just add some sample data in the initialization
    masterData.add(new Person("Hans", "Muster", 3210));
    masterData.add(new Person("Ruth", "Mueller", 2625));
    masterData.add(new Person("Heinz", "Kurz", 1234));
    masterData.add(new Person("Cornelia", "Meier", 9999));
    masterData.add(new Person("Werner", "Meyer", 5623));
    masterData.add(new Person("Lydia", "Kunz", 7834));
    masterData.add(new Person("Anna", "Best", 2942));
    masterData.add(new Person("Stefan", "Meier", 9423));
    masterData.add(new Person("Martin", "Mueller", 9122));

    // 0. Initialize the columns
    firstNameColumn = new TableColumn();
    firstNameLabel = new Label("First Name");
    firstNameColumn.setGraphic(firstNameLabel);
    //firstNameColumn.setSortable(false);

    lastNameColumn = new TableColumn();
    lastNameLabel = new Label("Last Name");
    lastNameColumn.setGraphic(lastNameLabel);

    idValueColumn = new TableColumn();
    idValueLabel = new Label("Id Number");
    idValueColumn.setGraphic(idValueLabel);

    firstNameColumn.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
    lastNameColumn.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
    idValueColumn.setCellValueFactory(cellData -> cellData.getValue().idValueProperty());

    idValueColumn.setComparator((Number o1, Number o2) -> 
    {
      return (o1.intValue() < o2.intValue() ? -1 : o1.intValue() == o2.intValue() ? 0 : 1);
    });

    firstNameTable = new TableView<>();
    personTable = new TableView<>();

    // 1. Wrap the ObservableList in a SortedList.
    SortedList<Person> sortedData = new SortedList<>(masterData);

    // 2. Bind the SortedList comparator (initally) to the personTable comparator.
    //sortedData.comparatorProperty().bind(firstNameTable.comparatorProperty());
    sortedData.comparatorProperty().bind(personTable.comparatorProperty());

    // 2a. Create listenters for each column header label - to update the comparator property
    firstNameLabel.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler()
    {
      @Override
      public void handle(Event event)
      {
        sortedData.comparatorProperty().bind(firstNameTable.comparatorProperty());
      }
    });

    lastNameLabel.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler()
    {
      @Override
      public void handle(Event event)
      {
        sortedData.comparatorProperty().bind(personTable.comparatorProperty());
      }
    });

    idValueLabel.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler()
    {
      @Override
      public void handle(Event event)
      {
        sortedData.comparatorProperty().bind(personTable.comparatorProperty());
      }
    });

    // 3. Add sorted data to the table.
    firstNameTable.setItems(sortedData);
    personTable.setItems(sortedData);

    firstNameTable.getColumns().add(firstNameColumn);
    personTable.getColumns().addAll(lastNameColumn, idValueColumn);

    HBox tableBox = new HBox(5);
    tableBox.getChildren().addAll(firstNameTable, personTable);

    Scene scene = new Scene(tableBox);
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  public static void main(String[] args) 
  {
    launch(args);
  }
}
Community
  • 1
  • 1