【问题标题】:JavaFX Tableview sort by custom rule, then by column selectionJavaFX Tableview 按自定义规则排序,然后按列选择
【发布时间】:2018-05-01 00:08:07
【问题描述】:

我正在尝试对包含 3 列的 JavaFX TableView 进行排序,一列是日期,一列是名称(字符串),最后一列是标签列(枚举)。我想要做的是使无论表格当前正在对哪一列进行排序,行都将按标签 first 排序(如果它有某个标签,则在行上方排序没有那个特定的标签)。

因此,当按名称进行升序搜索时,表格的顺序如下:

  • “乔治”[标签]
  • 'ZZ' [标签]
  • 'Apple' [无标签]
  • “你好”[无标签]

等等

我查看了列比较器,但是我似乎只能指定该列类型,即我希望能够指定名称列比较器以接收整行的类对象,并且名称-列数据类型(字符串),因此我可以访问该类实例中的标签 - 但是在网上环顾四周后,这似乎是不可能的。

即使选择 tags 列来排序 desc 是否也可以保留此规则(因此它仍然首先放置带有标签的行)。如果没有,我可以禁用标签列的排序

提前感谢任何可以为我指明正确方向的人

【问题讨论】:

  • 查看排序部分in the documentation。实现您所描述的一种方法是按照所述创建SortedList,而不是简单地将其比较器绑定到TableView 的比较器,而是创建一个首先比较标记值的依赖项。
  • 这不起作用,因为 SortedList 要求其比较器绑定到 TableView 的比较器。所以不能在两者之间注入自定义比较器。

标签: java sorting javafx


【解决方案1】:

正如我在评论中提到的,你不能只创建一个绑定,它包装了 TableView 的比较器并将其提供给 SortedList。 SortedList 也是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()));

【讨论】:

    【解决方案2】:

    我同意@Miklos 解决方案。以下是您要求的完整工作示例(基于@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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-06
      • 2012-09-11
      • 2015-01-17
      • 2011-07-31
      • 1970-01-01
      • 2010-12-14
      • 2017-07-30
      相关资源
      最近更新 更多