Java 8 javafx谓词仅第一次触发

Java 8 javafx谓词仅第一次触发,java-8,javafx-8,Java 8,Javafx 8,我有一个奇怪的问题,我肯定这是我的代码问题,但无法找到 问题: 我有一个JavaFXTableView,它由一个filteredlist支持,而filteredlist又由一个可观察列表支持。我的要求是根据用户在文本字段中键入的输入过滤tableview数据。因此,我在textfield的textProperty上附加了一个失效监听器,因此我试图根据我的业务条件设置filteredlist的谓词,这很好 见以下代码: externalTradeTableViewDataFilterTextFie

我有一个奇怪的问题,我肯定这是我的代码问题,但无法找到

问题: 我有一个JavaFXTableView,它由一个filteredlist支持,而filteredlist又由一个可观察列表支持。我的要求是根据用户在文本字段中键入的输入过滤tableview数据。因此,我在textfield的textProperty上附加了一个失效监听器,因此我试图根据我的业务条件设置filteredlist的谓词,这很好

见以下代码:

externalTradeTableViewDataFilterTextField.textProperty().addListener((obs) -> { 
//externalTradesFilteredList.setPredicate(somePredicate);
String filterText = externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();
externalTradesFilteredList.setPredicate((ExternalTrade anExternalTrade) -> {
if(filterText == null || filterText.isEmpty() || filterText.equals(""))
return true;
if(anExternalTrade.getOid().toString().contains(filterText))
return true;
else 
if(anExternalTrade.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase().contains(filterText))
return true;
else 
if(anExternalTrade.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase().contains(filterText))
return true;
else 
if(anExternalTrade.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase().contains(filterText))
return true;
return false;
});
});
externalTradeTableViewDataFilterTextField.textProperty().addListener((obs) -> { 
externalTradesFilteredList.setPredicate(somePredicate);
});

private Predicate<ExternalTrade> somePredicate = (ExternalTrade anExternalTrade) -> {
String filterText = externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();

if(filterText.isEmpty() || filterText == null || filterText.equals(""))
            return true;
if(anExternalTrade.getOid().toString().contains(filterText))
       return true;
else if(anExternalTrade.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase().contains(filterText))
            return true;
else if(anExternalTrade.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase().contains(filterText))
            return true;
        else if(anExternalTrade.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase().contains(filterText))
            return true;
return false;
};
自从我实现了我的需求,我就开始专注于代码重构。因此,我计划将谓词逻辑移动到一个单独的谓词,并将谓词移动到另一个类,以便可以重用它。 问题从这里开始

见以下代码:

externalTradeTableViewDataFilterTextField.textProperty().addListener((obs) -> { 
//externalTradesFilteredList.setPredicate(somePredicate);
String filterText = externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();
externalTradesFilteredList.setPredicate((ExternalTrade anExternalTrade) -> {
if(filterText == null || filterText.isEmpty() || filterText.equals(""))
return true;
if(anExternalTrade.getOid().toString().contains(filterText))
return true;
else 
if(anExternalTrade.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase().contains(filterText))
return true;
else 
if(anExternalTrade.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase().contains(filterText))
return true;
else 
if(anExternalTrade.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase().contains(filterText))
return true;
return false;
});
});
externalTradeTableViewDataFilterTextField.textProperty().addListener((obs) -> { 
externalTradesFilteredList.setPredicate(somePredicate);
});

private Predicate<ExternalTrade> somePredicate = (ExternalTrade anExternalTrade) -> {
String filterText = externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();

if(filterText.isEmpty() || filterText == null || filterText.equals(""))
            return true;
if(anExternalTrade.getOid().toString().contains(filterText))
       return true;
else if(anExternalTrade.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase().contains(filterText))
            return true;
else if(anExternalTrade.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase().contains(filterText))
            return true;
        else if(anExternalTrade.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase().contains(filterText))
            return true;
return false;
};
externalTradeTableViewDataFilterTextField.textProperty().addListener((obs)->{
setPredicate(somePredicate);
});
私有谓词somePredicate=(ExternalTrade和ExternalTrade)->{
String filterText=externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();
if(filterText.isEmpty()| | filterText==null | | filterText.equals(“”)
返回true;
if(anExternalTrade.getOid().toString().contains(filterText))
返回true;
else if(anExternalTrade.GetExternalTradeSourceId().getExternalTradeSrcName().toLowerCase().contains(filterText))
返回true;
else if(anExternalTrade.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase().contains(filterText))
返回true;
else if(anExternalTrade.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase().contains(filterText))
返回true;
返回false;
};
现在,每次我在textfield中键入新文本时,我的侦听器都会被执行,但谓词逻辑只会第一次被调用。从第二次调用谓词(somePredicate)开始

请帮我做这件事。还建议我的代码是好的还是其他更好的方法,以更好的性能实现这一点。bcoz我确实看到一些使用绑定的代码,表示filteredlist的filteredProperty直接附加到textfield的textProperty

还有一件事。谓词内部的逻辑是检查文本是否包含在任何列中,如果是,则返回行。我有20个专栏。那么我是否需要为所有20列编写if条件,或者以任何其他方式。“for loop”是唯一的方法吗?或者我可以用。foreach做点什么


提前感谢。

过滤器不会重新计算的原因是,从
过滤器列表的角度来看,它不会改变

在伪代码中,
FilteredList
可能看起来像这样:

public class FilteredList<T> {

    private ObjectProperty<Predicate<T>> predicate = new SimpleObjectProperty<>();

    private ObservableList<T> source ;

    public FilteredList<T>(ObservableList<T> source, Predicate<T> predicate) {

        this.source = source ;

        this.predicate.addListener((obs, oldPredicate, newPredicate) ->
            redoFilter());

        this.predicate.set(predicate);
    }

    // ...
}
换句话说,
ChangeListener
s仅在值实际更改时才会收到通知

在您的示例(第二个代码块)中,每当搜索字段中的文本发生更改时,您调用

externalTradesFilteredList.setPredicate(somePredicate);
每次都使用完全相同的引用
somePredicate
。因此,当包含该谓词的筛选列表中的属性进行检查时,它看不到任何更改(完全相同的对象…),因此不会触发更改侦听器,因此筛选列表不知道它必须更新

实际上,您没有更改谓词,只是更改了现有谓词的内部状态

要修复此问题,您可以执行以下操作:

private Predicate<ExternalTrade> createPredicate() {
    return (ExternalTrade anExternalTrade) -> {
        String filterText = externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();

        if(filterText.isEmpty() || filterText == null || filterText.equals(""))
                    return true;
        if(anExternalTrade.getOid().toString().contains(filterText))
               return true;
        else if(anExternalTrade.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase().contains(filterText))
                    return true;
        else if(anExternalTrade.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase().contains(filterText))
                    return true;
                else if(anExternalTrade.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase().contains(filterText))
                    return true;
        return false;
    };

}
或等效地创建一个类:

private static class TradeTableFilter implements Predicate<ExternalTrade> {

    private final String filterText ;

    TradeTableFilter(String filterText) {
        this.filterText = filterText ;
    }

    @Override
    public boolean test(ExternalTrade anExternalTrade) {

        if(filterText.isEmpty() || filterText == null || filterText.equals(""))
                    return true;
        if(anExternalTrade.getOid().toString().contains(filterText))
               return true;
        else if(anExternalTrade.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase().contains(filterText))
                    return true;
        else if(anExternalTrade.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase().contains(filterText))
                    return true;
                else if(anExternalTrade.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase().contains(filterText))
                    return true;
        return false;
    }

}
对于你的另一个问题(顺便说一句,你不应该在这个论坛上把多个问题合并成一个问题:这使得其他用户很难(或不可能)找到相同问题的现有答案),没有真正简单的解决方法

您可以在模型中创建一个属性列表,作为
函数

private final List tradeProperties=Arrays.asList(
t->t.getOid().toString(),
t->t.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase(),
t->t.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase(),
t->t.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase()
);
然后

private Predicate<ExternalTrade> createPredicate() {
    return (ExternalTrade anExternalTrade) -> {
        String filterText = externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();
        return filterText == null ||
               filterText.isEmpty() ||
               tradeProperties().stream().anyMatch(p -> p.apply(anExternalTrade).contains(filterText));
    };
}
私有谓词createPredicate(){
退货(外部交易和外部交易)->{
String filterText=externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();
返回filterText==null||
filterText.isEmpty()||
tradeProperties().stream().anyMatch(p->p.apply(anExternalTrade).contains(filterText));
};
}

根据您的模型类和表的设置方式,您可能能够映射到函数列表中的
ObservableValue
s而不是
String
s,然后您还可以潜在地重用该列表来创建循环中的列。但我对您的设置了解不够,不知道这是否可行。

太棒了,我没有应用n check解决方案,但它是有意义的。让我试试。也很抱歉提出了多个问题。从现在开始我会纠正自己的。嘿,我正在尝试你的解决方案。第一个问题解决了。第二个问题。循环遍历所有列,我不能说tradeProperties().stream().anyMatch(p->p.contains(filterText));其中p.contains不起作用。我无法调用p上的contains方法,p是一个谓词。谢谢James。成功了。谢谢。你介意看一看吗
private final List<Function<ExternalTrade, String>> tradeProperties = Arrays.asList(
    t -> t.getOid().toString(),
    t -> t.getExternalTradeSourceOid().getExternalTradeSrcName().toLowerCase(),
    t -> t.getExternalTradeStatusOid().getExternalTradeStatusName().toLowerCase(),
    t -> t.getExternalTradeStateOid().getExternalTradeStateName().toLowerCase()
);
private Predicate<ExternalTrade> createPredicate() {
    return (ExternalTrade anExternalTrade) -> {
        String filterText = externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase();
        return filterText == null ||
               filterText.isEmpty() ||
               tradeProperties().stream().anyMatch(p -> p.apply(anExternalTrade).contains(filterText));
    };
}