Sort javaFX Tree table view items

2.4k Views Asked by At

I'm having troubles sorting my JFXTreeTableView (from Jfoenix).
I have created an object named ScanModel which extends Jfoenix's RecursiveTreeObject<ScanModel>.

One of the many properties I'm having there is:
private IntegerProperty id;
Here are its getters and setters

    public final IntegerProperty idProperty() {
    if (id == null) {
        id = new SimpleIntegerProperty();
    }
    return id;
    }

    public final int getId() {
        return idProperty().get();
    }

    public void setId(int value) {
        idProperty().set(value);
    }

Two classes extend the abstract ScanModel class: StudyModel and SeriesModel.
StudyModel (which contains multiple SeriesModels) overrides getChildren() method of Jfoenix RecursiveTreeObject, and returns its series observable list.

Here is how I bind the observable list which contain the items to the table itself:

    protected void createTree(JFXTreeTableView<ScanModel> tree, ObservableList<ScanModel> elements) {
        tree.setRoot(new RecursiveTreeItem<ScanModel>(elements, RecursiveTreeObject::getChildren));
        tree.setShowRoot(false);
        tree.getSelectionModel().clearSelection();
    }

Until now everything worked great, I've added new ScanModel items to the observable list, and it was automatically displyed in the UI.

Now for my issue:
The client requests sorted table: Descending StudyModels, and Ascending SeriesModels.

For first try I only tried to sort the StudyModels.
I've changed the createTree method to this implementation:

protected void createTree(JFXTreeTableView<ScanModel> tree, ObservableList<ScanModel> elements) {
    SortedList<ScanModel> sortedElements = elements.sorted((l, r) -> Integer.compare(l.getId(), r.getId()));
    tree.setRoot(new RecursiveTreeItem<ScanModel>(sortedElements, RecursiveTreeObject::getChildren));
    tree.setShowRoot(false);
    tree.getSelectionModel().clearSelection();
}

The sorted observable list is indeed sorted, but it does not reflect in the UI
Tree table view problem

What am I missing here?
Thanks.

Update
Just in case, here is the fxml of the table

<JFXTreeTableView fx:id="_treeTableView">
        <placeholder>
            <Label text="No Normal Studies to display" />
        </placeholder>
        <columnResizePolicy>
            <JFXTreeTableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
        </columnResizePolicy>
        <columns>
            <JFXTreeTableColumn text="ID" sortable="false"
                minWidth="150" maxWidth="150">
                <cellValueFactory>
                    <TreeTableErrorIndicationCellFactory value="id" />
                </cellValueFactory>
            </JFXTreeTableColumn>

            <JFXTreeTableColumn text="Scan Time" sortable="false"
                minWidth="140" maxWidth="140">
                <cellValueFactory>
                    <TreeTableErrorIndicationCellFactory value="formattedScanTime" />
                </cellValueFactory>
            </JFXTreeTableColumn>
            <JFXTreeTableColumn text="Selected" sortable="false"
                minWidth="60" maxWidth="60">
                <cellValueFactory>
                    <ScanSelectedValueFactory />
                </cellValueFactory>
            </JFXTreeTableColumn>
            <JFXTreeTableColumn sortable="false">

            </JFXTreeTableColumn>
            <JFXTreeTableColumn text="Archived" sortable="false"
                style="-fx-alignment: CENTER-RIGHT;" minWidth="60" maxWidth="60">
                <cellValueFactory>
                    <IsArchivedCellFactory />
                </cellValueFactory>
            </JFXTreeTableColumn>
        </columns>
    </JFXTreeTableView>
1

There are 1 best solutions below

0
On BEST ANSWER

It's been a while since the question was asked, and I see that some people viewed the topic.
Here is an answer. Surely not the best one - but it works.

First of all, while creating the tree - need to setSortPolicy of the tree.
Here is how it looks like in my project:

protected void createTree(JFXTreeTableView<ScanModel> tree, ObservableList<ScanModel> elements) {
    tree.setRoot(new RecursiveTreeItem<ScanModel>(elements, RecursiveTreeObject::getChildren));
    tree.setShowRoot(false);
    tree.getSelectionModel().clearSelection();

    // set sort policy for the table in two levels
    tree.setSortPolicy(t -> {
        Comparator<TreeItem<ScanModel>> studiesComparator = (r1, r2) -> {
            try {
                int r1Value = Integer.parseInt(r1.getValue().getDisplayName());
                int r2Value = Integer.parseInt(r2.getValue().getDisplayName());
                return Integer.compare(r2Value, r1Value);
            } catch (NumberFormatException e) {
                return r2.getValue().getDisplayName().compareToIgnoreCase(r1.getValue().getDisplayName());
            }
        };
        FXCollections.sort(tree.getRoot().getChildren(), studiesComparator);

        for (TreeItem<ScanModel> series : tree.getRoot().getChildren()) {
            Comparator<TreeItem<ScanModel>> seriesComparator = (r1, r2) -> {
                try {
                    int r1Value = Integer.parseInt(r1.getValue().getDisplayName());
                    int r2Value = Integer.parseInt(r2.getValue().getDisplayName());
                    return Integer.compare(r1Value, r2Value);
                } catch (NumberFormatException e) {
                    return r1.getValue().getDisplayName().compareToIgnoreCase(r2.getValue().getDisplayName());
                }
            };
            series.getChildren().sort(seriesComparator);
        }

        return true;
    });

}

Second, For each new item added to the tree - I call the sort method.

/**
 * Sort the table according to the configured sort policy
 * 
 * @param tree
 */
protected void sortTree(JFXTreeTableView<ScanModel> tree) {
    // Keep selected row and set it again after sort
    TreeItem<ScanModel> selectedRow = tree.getSelectionModel().getSelectedItem();
    tree.sort();
    tree.getSelectionModel().select(selectedRow);
}

Hope it will help some future viewers.

Naor