我正在尝试对包含 3 列的 JavaFX
TableView
进行排序,一列是日期,一列是名称(字符串),最后一列是标签列(这是一个枚举)。我想要做的是,无论表当前在哪一列排序,行都将按标签排序(如果它具有某个标签,则它会排序在没有该标签的行之上)某些标签)。
因此,当按名称升序搜索时,表格的顺序如下:
“乔治”[标签]
我查看了列比较器,但是我似乎只能指定该列类型,即我希望能够指定名称列比较器以接受整行的类对象和名称列数据类型(字符串),这样我就可以访问该类实例中的标签 - 但是在网上查看后这似乎不可能。
即使选择标签列来排序 desc,是否也可以保留此规则(因此它仍然首先放置带有标签的行)。如果没有,我可以禁用标签列的排序
预先感谢任何可以为我指明正确方向的人
解决方案。以下是您要求的完整工作示例(基于 @Miklos 解决方案),在对所选列进行排序之前首先按标签列进行排序。 [这不是一个完整的解决方案,但这应该为您提供一些开始的方向,并使其根据您的需求完全工作]
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import static javafx.scene.control.TableColumn.SortType.ASCENDING;
public class CustomComparatorTableColumn extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Device> devices = FXCollections.observableArrayList();
devices.add(new Device(1, "Apple", "Zebra", TagType.TAG));
devices.add(new Device(2, "BlackBerry", "Parrot", TagType.TAG));
devices.add(new Device(3, "Amazon", "Yak", TagType.NO_TAG));
devices.add(new Device(4, "Oppo", "Penguin", TagType.NO_TAG));
TableView<Device> tableView = new TableView<>();
TableColumn<Device, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(param -> param.getValue().nameProperty());
TableColumn<Device, String> displayCol = new TableColumn<>("Display");
displayCol.setCellValueFactory(param -> param.getValue().displayProperty());
TableColumn<Device, TagType> tagCol = new TableColumn<>("Tag");
tagCol.setCellValueFactory(param -> param.getValue().tagTypeProperty());
tableView.getColumns().addAll(nameCol, displayCol, tagCol);
tableView.setItems(devices);
tableView.setSortPolicy(tv -> {
final ObservableList<Device> itemsList = tableView.getItems();
if (itemsList == null || itemsList.isEmpty()) {
return true;
}
final List<TableColumn<Device, ?>> sortOrder = new ArrayList<>(tableView.getSortOrder());
if (!sortOrder.isEmpty()) {
// If there is no Tag column in the sort order, always adding as the first sort to consider.
if (!sortOrder.stream().anyMatch(tc -> tc.getText().equals("Tag"))) {
sortOrder.add(0, tagCol);
}
FXCollections.sort(itemsList, new TableColumnComparator<>(sortOrder));
}
return true;
});
Scene sc = new Scene(tableView);
primaryStage.setScene(sc);
primaryStage.show();
}
class TableColumnComparator<S> implements Comparator<S> {
private final List<TableColumn<S, ?>> allColumns;
public TableColumnComparator(final List<TableColumn<S, ?>> allColumns) {
this.allColumns = allColumns;
}
@Override
public int compare(final S o1, final S o2) {
for (final TableColumn<S, ?> tc : allColumns) {
if (!isSortable(tc)) {
continue;
}
final Object value1 = tc.getCellData(o1);
final Object value2 = tc.getCellData(o2);
@SuppressWarnings("unchecked") final Comparator<Object> c = (Comparator<Object>) tc.getComparator();
final int result = ASCENDING.equals(tc.getSortType()) ? c.compare(value1, value2)
: c.compare(value2, value1);
if (result != 0) {
return result;
}
}
return 0;
}
private boolean isSortable(final TableColumn<S, ?> tc) {
return tc.getSortType() != null && tc.isSortable();
}
}
class Device {
IntegerProperty id = new SimpleIntegerProperty();
StringProperty name = new SimpleStringProperty();
StringProperty display = new SimpleStringProperty();
ObjectProperty<TagType> tagType = new SimpleObjectProperty<>();
public Device(int id, String n, String d, TagType tag) {
this.id.set(id);
name.set(n);
tagType.set(tag);
display.set(d);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public ObjectProperty<TagType> tagTypeProperty() {
return tagType;
}
public StringProperty displayProperty() {
return display;
}
}
enum TagType {
TAG, NO_TAG;
}
}
final
所以你不能扩展它。另外,使用自定义
TransformationList
也行不通,因为 TableView
有一些以 if (itemsList instanceof SortedList)
开头的硬编码内容。
这就是我最终得到的结果(为了清楚起见,使用 java7 格式而不是 Labdas): filteredList = new FilteredList<>(yourOriginalList);
table.sortPolicyProperty().set(new Callback<TableView<YourObject>, Boolean>() {
@Override
public Boolean call(TableView<YourObject> param) {
final Comparator<YourObject> tableComparator = transactionTable.getComparator();
// if the column is set to unsorted, tableComparator can be null
Comparator<YourObject> comparator = tableComparator == null ? null : new Comparator<YourObject>() {
@Override
public int compare(YourObject o1, YourObject o2) {
// first sort by your tag
final int tagCompare = o1.getTag().compareTo(o2.getTag());
if (tagCompare == 0) {
// secondly sort by the comparator that was set for the table
return tableComparator.compare(o1, o2);
}
return tagCompare;
}
};
table.setItems(filteredList.sorted(comparator));
return true;
}
});
// you may also need to call
table.setItems(filteredList.sorted(transactionTable.getComparator()));
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();
}
}
}