【问题标题】:JavaFX TableView sorting consistency on property updateJavaFX TableView 在属性更新上的排序一致性
【发布时间】:2017-01-19 05:42:30
【问题描述】:

我有一个数据异步更改的 TableView。 TableView 有一个排序,我希望根据当前排序对更新的行进行排序。添加到模型的新行已正确排序,但更改数据不会反映在当前排序中。

是每次更新数据后调用 TableView.sort() 的唯一解决方案吗?

import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class SortingItOut extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        ObservableList<Person> data = FXCollections.observableArrayList();
        Person c = new Person("C", 120);
        data.addAll(new Person("A", 100), new Person("B", 50), c, new Person("D", 25));

        TableColumn<Person, String> nameColumn = new TableColumn<>("Name");
        nameColumn.setCellValueFactory(param -> param.getValue().name);
        TableColumn<Person, Number> ageColumn = new TableColumn<>("Age");
        ageColumn.setCellValueFactory(param -> param.getValue().age);

        TableView<Person> table = new TableView<>(data);
        table.getColumns().addAll(nameColumn, ageColumn);
        table.getSortOrder().add(ageColumn);

        SortedList<Person> sortedList = new SortedList<>(data);
        sortedList.comparatorProperty().bind(table.comparatorProperty());

        table.setItems(sortedList);

        Button modify = new Button("modify C age");
        modify.setOnAction(e -> c.setAge(c.getAge() == 120 ? 75 : 120));

        Button add = new Button("add");
        add.setOnAction(e -> data.add(new Person("E", (int) (Math.random() * 100))));

        VBox box = new VBox(10);
        box.setAlignment(Pos.CENTER);

        box.getChildren().addAll(table, modify, add);
        Scene scene = new Scene(box);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public class Person {

        private final SimpleStringProperty name = new SimpleStringProperty("");
        private final SimpleIntegerProperty age = new SimpleIntegerProperty(0);

        public Person(String name, Integer age) {
            setName(name);
            setAge(age);
        }

        public String getName() {
            return name.get();
        }

        public void setName(String name) {
            this.name.set(name);
        }

        public void setAge(Integer age) {
            this.age.set(age);
        }

        public Integer getAge() {
            return age.get();
        }
    }

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

【问题讨论】:

  • 我认为像this 这样的东西也可以。您可以将列表中的更改绑定到表sort() 函数。但这对我来说似乎有点开销。为什么你不想在modify 按钮onAction 中使用sort()?
  • 不得不同意前面的评论。使用一行代码 (TableView.sort()) 来完成这似乎是一个足够好的解决方案。
  • @Enigo,谢谢。您链接到的解决方案有效。我想我有点惊讶该表将对列表中的新条目进行排序,但不会对列表中已有条目的更新进行排序。上面的例子是人为的。实际示例会对数据进行许多异步更新,我宁愿不必在每次更新后调用 sort() ..
  • @AlexColomb,很酷,它对你有用)
  • 除非SortedList 接收到这些更改已实际发生的信息,否则该表无法根据基础数据的更改重新排序。提取器正是这样做的:如果提取器提供的属性发生变化,它会导致底层列表触发事件。这一更改比在事件处理程序 imo 中手动调用 sort() 好得多,因为无论这些数据如何更改,它都会确保表保持排序。如果您在数据更改时尝试自己致电sort(),那么随着您稍后添加更多功能,代码会迅速变得无法维护。

标签: java javafx javafx-8


【解决方案1】:

当您更改现有元素中的值时,表格无法自动重新排序,因为您没有提供任何机制让SortedList“知道”这些更改何时发生。

如果您在模型类中公开 JavaFX 属性:

public class Person {

    private final StringProperty name = new SimpleStringProperty("");
    private final IntegerProperty age = new SimpleIntegerProperty(0);

    public Person(String name, Integer age) {
        setName(name);
        setAge(age);
    }

    public StringProperty nameProperty() {
        return name ;
    }

    public IntegerProperty ageProperty() {
        return age ;
    }

    public String getName() {
        return name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public void setAge(Integer age) {
        this.age.set(age);
    }

    public Integer getAge() {
        return age.get();
    }
}

并使用extractor 创建基础列表,以便在感兴趣的属性更改时触发事件:

ObservableList<Person> data = FXCollections.observableArrayList(p -> 
    new Observable[] {p.nameProperty(), p.ageProperty()});

然后SortedList 将在属性更改时接收事件,并且能够根据需要“自动”重新排序元素。

【讨论】:

  • 我知道这几乎等同于链接的答案;在 cmets 中关于 OP 的讨论之后,我只想澄清使用提取器创建列表是 only 需要的更改;您不需要列表中的任何进一步绑定或侦听器 - SortedList 已经实现了所有这些。
【解决方案2】:

正如@Enigo 所指出的,this 解决方案将确保在更新每个列表项中的属性后表格具有正确的排序。

【讨论】:

    猜你喜欢
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 2011-01-01
    • 1970-01-01
    • 2023-03-11
    相关资源
    最近更新 更多