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