【问题标题】:Javafx: Incorrect usage of setPredicate method of a filtered listJavafx:过滤列表的 setPredicate 方法使用不正确
【发布时间】:2015-09-22 17:57:02
【问题描述】:

我有一个包含Person 项目的可观察列表的 TableView。每行显示一个Person 对象,同时还显示其name 属性。

我想将此 observable 传递到过滤列表中并在 name 属性上设置谓词

我想要实现的是: 如果我双击 TableView 中包含Person 项目的任何一行,我将能够提取所选Person 对象的names 属性并将过滤列表的谓词设置为选中名称。

因此过滤后的列表将仅包含 Person 具有所选名称的项目。

下面的代码几乎可以实现我想要的一切。但是,有一个极端情况不能按预期工作。例如,我双击“name = John”的人。过滤后的列表将过滤所有名为“John”的人。现在,如果我将过滤列表中的一个人的名字更改为“Tim”。此人仍保留在过滤列表中。理想情况下,我希望它自动被删除。 但我做不到。

我认为我没有正确使用setPredicate,因为我觉得我在编写多余的代码,应该有更有效的方法来做到这一点,并且会自动在编辑后立即删除具有不同名称的人。

在我的Person 班级内,

private StringProperty Name;
private final BooleanProperty filteredName = new SimpleBooleanProperty() ;  

public final boolean getFilteredName(){
    return filteredNameProperty().getValue();
}

public final BooleanProperty filteredNameProperty(){
    return this.filteredName;
}

public final void setFilteredName(String name){
    if(getName().equals(name)){
        this.filteredNameProperty().set(true);
    } else{
        this.filteredNameProperty().set(false);
    }
} 

在我的控制器中,我有:

        private ObservableList<Person> observableListOfPerson = FXCollections.observableArrayList(p->
        new Observable[]{
                p.nameProperty(),
                p.filteredNameProperty()
        }
    );
        private FilteredList<Person> filterListOfPerson= new FilteredList<>(observableListOfPerson, p-> p.filteredNameProperty().get());

public void initializeFilteredTable(){
        filteredTab.setText("Filtered History");
        filterTable.setItems(filterListOfPerson);

        filterListOfPerson.addListener(new ListChangeListener<Person>(){
              @Override
                public void onChanged(ListChangeListener.Change change) {
                  filterTable.setItems(filterListOfPerson);
              }
        });
        filterTable.setItems(filterListOfPerson);}

在我的AnimatedRow 班级中,我有:

public class AnimatedRow<T> extends TableRow<T> {
    private TabPane fxTabPaneLower;

    /**
     * The data as an observable list of Person.
     */
    private ObservableList<Person> observableListOfPerson;
    private FilteredList<Person> filterListOfPerson;

    public AnimatedRow(Function<T, StringExpression> nameExtractor, ObservableList<Person> observableListOfPerson, FilteredList<Person> filterListOfPerson, TabPane fxTabPaneLower) {
                   setOnMouseClicked(event -> {
            if (event.getClickCount() == 2 && (!isEmpty()) ) {
                final StringExpression nameBE = nameExtractor.apply(getItem());
                for(Person t : observableListOfPerson){
                    t.setFilteredName(nameBE.get());

                }
                filterListOfPerson.setPredicate(p-> p.filteredNameProperty().get());

                fxTabPaneLower.getSelectionModel().select(1);
                ((TableView<Person>)fxTabPaneLower.getTabs().get(1).getContent()).setItems(filterListOfPerson);              
          }
        });
    }
}

【问题讨论】:

  • 难道你不需要在名称更新的提交上过滤列表吗?
  • @purringpigeon 不,您只需要确保基础列表在属性更改时触发更新。
  • 在发布此问题之前,我查看了该问题,并且我在您为该问题发布的答案中做了所有事情。我添加了new ObservableList[] {p -&gt; p.NameProperty()....}
  • 是的,我最初错过了。我真的不明白filteredName 的目的。除了过滤之外,您还使用它吗?
  • 基本上,filteredListOfPerson 是我的第二个表格视图。因此,如果我在包含所有 Person 项目的第一个表视图中单击 Person 的名称,filteredListOfPerson 将按所选名称过滤第一个表中的所有 Person 项目,并在第二个表视图中显示结果。这一切都很好,直到我开始编辑第二个表中的 Person 项目,然后我意识到如果我在 filteredListOfPerson 中更改了 Person 的名称,它仍然会保留在第二个表中。

标签: java javafx


【解决方案1】:

(这本质上是 JavaFX FilteredList, filtering based on property of items in the list 的副本。)

您似乎正试图在您的 Person 类中实现过滤。 FilteredList 的全部意义在于它为您实现了过滤器。

所以我认为你只需完全摆脱 filteredName 属性,然后再做

public AnimatedRow(Function<T, StringExpression> nameExtractor, ObservableList<Person> observableListOfPerson, FilteredList<Person> filterListOfPerson, TabPane fxTabPaneLower) {
    setOnMouseClicked(event -> {
        if (event.getClickCount() == 2 && (!isEmpty()) ) {
            final StringExpression nameBE = nameExtractor.apply(getItem());
            filterListOfPerson.setPredicate(p-> p.getName().equals(nameBE.get()));

            fxTabPaneLower.getSelectionModel().select(1);
            ((TableView<Person>)fxTabPaneLower.getTabs().get(1).getContent()).setItems(filterListOfPerson);              
        }
    });
}

只要您将 name 属性作为基础列表提取器的一部分返回,过滤器就会在名称更改时重新评估。

【讨论】:

  • 在这种情况下你将如何初始化filteredList,因为它需要一个布尔参数?
  • FilteredList 不“接受布尔参数”。它需要 ObservableListPredicate
  • 我的意思是在我的 Controller 类中,当我初始化过滤列表时,我这样做了:private FilteredList&lt;Person&gt; filterListOfPerson = new FilteredList&lt;&gt;(observableListOfPerson, p-&gt; p.nameProperty().get());。它抱怨类型不匹配:字符串无法转换为布尔值。我记得这就是我首先创建布尔属性的原因。
  • 第二个参数是(初始)Predicate。只需给它Predicate 代表您希望如何最初过滤项目。 (坦率地说,您听起来好像只是在盲目地复制代码,却不知道它在做什么。您怎么能期望一个返回名称(即String)的函数来定义过滤器?)
  • 我没有盲目地复制代码。我没有完全理解setPredicate 方法。如果我盲目地复制代码,我就不会创建 booleanProperty 并手动创建过滤步骤。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-22
相关资源
最近更新 更多