Reputation: 591
... where T
is the generic type of the TableView
.
I'm implementing a file-listview with three columns, so far. Each of type java.nio.file.Path
. For the name column, I wrote a Comparator<Path>
which sorts the files with directories-first and case-insensitiv. The other two comparators sort by last-modified-time and file-size. For this they compare on long
fields.
But the comparatorProperty
of a column is based on Comparator<String>
. Which, I think, sorts based on the displayed text...
So I have to find a way, to use the sort-on-header-click feature with the type of the TableView
?
Upvotes: 2
Views: 2745
Reputation: 1694
While @Christian Rädel answer was correct, it didn't show how to implement it.
I was looking for this implementation because I wanted to sort the columns by a 'sort value' and not the 'displayed value.'
For instance, the Name field is preferred to be displayed as 'FirstName LastName', but you'd like to have the field sorted by 'LastName, FirstName'. Also, you might have a column that is composite as 'TagName [version]' and you'd prefer the version to be sorted numerically instead of alphabetically.
public class SomeView extends SplitPane
{
ToolBar searchBar = new ToolBar();
TextField searchField = new TextField();
TableView<Widget> widgets = new TableView<Widget>();
TableColumn<Widget, String> number_col;
TableColumn<Widget, WidgetTitle> title_col;
TableColumn<Widget, WidgetName> name_col;
TableColumn<Widget, WidgetVersion> version_col;
public SomeView()
{
super();
setOrientation(Orientation.VERTICAL);
setDividerPositions(0.05);
searchField.setPrefWidth(200);
searchField.setMaxWidth(360);
searchField.setMinWidth(80);
searchField.setPrefColumnCount(360);
searchField.setText("");
searchBar.getItems().add(searchField);
number_col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Widget, String>, ObservableValue<String>>() {
@Override public ObservableValue<String> call(TableColumn.CellDataFeatures<Widget, String> p) {
return new ReadOnlyObjectWrapper( (1 + widgets.getItems().indexOf(p.getValue())) + "");
}
});
number_col.setSortable(false);
number_col.setPrefWidth(60);
number_col.setMinWidth(30);
title_col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Widget, WidgetTitle>, ObservableValue<WidgetTitle>>() {
public ObservableValue<WidgetTitle> call(TableColumn.CellDataFeatures<Widget, WidgetTitle> p) {
return new ReadOnlyObjectWrapper<WidgetTitle>( new WidgetTitle(p.getValue()) );
}
});
name_col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Widget, WidgetName>, ObservableValue<WidgetName>>() {
public ObservableValue<WidgetName> call(TableColumn.CellDataFeatures<Widget, WidgetName> p) {
return new ReadOnlyObjectWrapper<WidgetName>( new WidgetName(p.getValue()) );
}
});
version_col.setMinWidth(80.0);
version_col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Widget, WidgetVersion>, ObservableValue<WidgetVersion>>() {
public ObservableValue<WidgetVersion> call(TableColumn.CellDataFeatures<Widget, WidgetVersion> p) {
return new ReadOnlyObjectWrapper<WidgetVersion>( new WidgetVersion(p.getValue()) );
}
});
widgets.getColumns().setAll(number_col, title_col, name_col, version_col, date_col);
ObservableList<Widget> widgetList = widgets.geItems();
widgetList.addAll( /* get List<Widget> */ );
FilteredList<Widget> filtered = new FilteredList<>(widgetList);
searchField.textProperty().addListener((obsv, ovalue, nvalue) -> {
filtered.setPredicate( awidget -> {
if (null == nvalue || nvalue.isEmpty())
return true;
String lcfilter = nvalue.toLowerCase();
if (awidget.getName().toLowerCase().contains(lcfilter)
|| awidget.getTitle().toLowerCase().contains(lcfilter))
return true;
return false;
});
});
SortedList<Widget> sorted = new SortedList<>(filtered);
widgets.setItems(sorted);
sorted.comparatorProperty().bind(widgets.comparatorProperty());
getItems().addAll(searchBar, widgets);
}
// customize the sorting of Title Column
private class WidgetTitle implements Comparable<WidgetTitle>
{
Widget widget;
WidgetTitle(Widget title)
{
widget = title;
}
@Override
public int compareTo(WidgetTitle obj)
{
return widget.getSortTitle().compareTo(obj.widget.getSortTitle());
}
@Override
public String toString()
{
return widget.getTitle();
}
}
// customize the sorting of Name Column
private class WidgetName implements Comparable<WidgetName>
{
Widget widget;
WidgetName(Widget name)
{
widget = name;
}
@Override
public int compareTo(WidgetName obj)
{
return widget.getNameSort().compareTo(obj.widget.getNameSort());
}
@Override
public String toString()
{
return widget.getName();
}
}
// customize the sorting of Version Column
private class WidgetVersion implements Comparable<WidgetVersion>
{
Widget widget;
WidgetVersion(Widget version)
{
widget = version;
}
@Override
public int compareTo(WidgetVersion obj)
{
String ser1 = widget.getVersionName();
String ser2 = obj.widget.getVersionName();
if (null == ser1 && null != ser2)
return -1;
if (null != ser1 && null == ser2)
return 1;
int scompare = ser1.compareTo(ser2);
return (0 == scompare)
? widget.getVersionIndex().compareTo(obj.widget.getVersionIndex()) : scompare;
}
@Override
public String toString()
{
return widget.versionProperty().getValue();
}
}
}
Upvotes: 0
Reputation: 591
You use wrong type parameters, when creating your TableColumn
. If you create a TableColumn<Path, Path>
, you can specify a Comparator<Path>
for that column. Likewise TableColumn<Path, FileTime>
and TableColumn<Path, Long>
to use Comparator<FileTime>
and Comparator<Long>
.
From the docs:
Class TableColumnBase<S,T>
Type Parameters:
S - The type of the UI control (e.g. the type of the 'row').
T - The type of the content in all cells in this table column.
Upvotes: 2