属性更新时JavaFX TableView排序一致性

属性更新时JavaFX TableView排序一致性,java,javafx,javafx-8,Java,Javafx,Javafx 8,我有一个数据异步更改的TableView。TableView有一个排序,我希望更新的行按照当前排序。添加到模型中的新行已正确排序,但更改数据不会反映在当前排序中 是在每次数据更新后调用TableView.sort()的唯一解决方案吗 import javafx.application.Application; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringP

我有一个数据异步更改的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);
    }
}
导入javafx.application.application;
导入javafx.beans.property.SimpleIntegerProperty;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.collections.transformation.SortedList;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
公共类排序输出扩展了应用程序{
@凌驾
public void start(Stage primaryStage)引发异常{
ObservableList data=FXCollections.observableArrayList();
人员c=新人员(“c”,120);
数据加总(新人(“A”,100),新人(“B”,50),c,新人(“D”,25));
TableColumn Name column=新的TableColumn(“名称”);
nameColumn.setCellValueFactory(param->param.getValue().name);
TableColumn ageColumn=新的TableColumn(“年龄”);
ageColumn.setCellValueFactory(param->param.getValue().age);
TableView表格=新的TableView(数据);
table.getColumns().addAll(nameColumn,ageColumn);
table.getSortOrder().add(ageColumn);
SortedList SortedList=新的SortedList(数据);
sortedList.comparatorProperty().bind(table.comparatorProperty());
表.集合项目(分类列表);
按钮修改=新按钮(“修改C年龄”);
修改.setOnAction(e->c.setAge(c.getAge()==120?75:120));
按钮添加=新按钮(“添加”);
add.setOnAction(e->data.add(newperson(“e”,(int)(Math.random()*100)));
VBox框=新的VBox(10);
框。设置对齐(位置中心);
box.getChildren().addAll(表,修改,添加);
场景=新场景(框);
初级阶段。场景(场景);
primaryStage.show();
}
公共阶层人士{
私有最终SimpleStringProperty名称=新SimpleStringProperty(“”);
私有最终SimpleIntegerProperty年龄=新SimpleIntegerProperty(0);
公众人物(字符串名称,整数年龄){
集合名(名称);
设置(年龄);
}
公共字符串getName(){
返回name.get();
}
公共void集合名(字符串名){
this.name.set(name);
}
公共无效设置(整数期限){
此.age.set(年龄);
}
公共整数getAge(){
returnage.get();
}
}
公共静态void main(字符串[]args){
发射(args);
}
}

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

当您更改现有元素中的值时,表无法自动重新排序,因为您没有为
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();
    }
}
并使用创建基础列表,以便在感兴趣的属性更改时触发事件:

ObservableList<Person> data = FXCollections.observableArrayList(p -> 
    new Observable[] {p.nameProperty(), p.ageProperty()});
observeListData=FXCollections.observearraylist(p->
新的可观察[]{p.nameProperty(),p.ageProperty()});

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

我认为类似的方法也可以。您可以将列表中的更改绑定到表
sort()
函数。但对我来说这似乎有点过头了。你为什么不想在
修改
中使用
排序()
按钮
操作
?你必须同意前面的评论。使用一行代码(
TableView.sort()
)来完成此任务似乎是一个足够好的解决方案。@Enigo,谢谢。您链接到的解决方案有效。我想我有点惊讶,该表将根据列表中的新条目进行排序,而不是根据列表中已有条目的更新进行排序。上面的例子是人为的。真实的示例会有许多异步数据更新,我不希望每次更新后都调用sort()。@AlexColomb,这对您来说很酷)除非
SortedList
接收到这些更改实际发生的信息,否则表不能对基础数据中的更改重新排序。提取器正是这样做的:如果提取器提供的属性发生更改,它会导致基础列表触发事件。这一更改比在事件处理程序imo中手动调用
sort()
要好得多,因为它将确保表保持排序,无论这些数据如何更改。如果您在数据更改时尝试自己调用
sort()
,那么当您稍后添加更多功能时,代码会很快变得无法维护;在对OP的评论中讨论之后,我只想澄清,使用提取器创建列表是唯一需要的更改;列表中不需要任何进一步的绑定或侦听器,
SortedList
已经实现了所有这些。