2016-08-05 20 views
1

私は奇妙な問題を抱えていますが、それは私のコードの問題ですが、見つけ出すことはできません。javafx述語が初めて初めて起動する

問題: javafx TableViewにはフィルタリストが付いていますが、これには観測可能リストが付いています。私の要件は、テキストフィールドのユーザーが入力した入力に基づいてテーブルビューのデータをフィルタリングすることです。だから私はテキストフィールドのtextPropertyに無効なリスナーを添付して、私は正常に動作する私のビジネス条件に基づいてフィルタリストの述語を設定しようとしている。私はリファクタリングに集中し始めた私の要件を達成しているので

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; 
}; 

は、今私はテキストフィールドに新しいテキストを入力するたびに、私のリスナーが実行取得されますが、述語論理は初回のみと呼ばれます。 2回目から、述語(somePredicate)が呼び出されません。

私を助けてください。また、私のコードが良いかそれとももっと良い方法でこれをより良いパフォーマンスで実現するかを提案する。 bcoz私はフィルタリングされたリストのfilteredPropertyがテキストフィールドのtextPropertyに直接接続されているというバインディングを使用するコードをいくつか見ています。

1つ以上のこと。述部内のロジックは、行を返す場合は、列のいずれかに含まれるテキストをチェックすることです。私は20列あります。だから私はすべての20列または他の方法のすべてのif条件を記述する必要があります。 forループは唯一の方法ですか?または私は.foreachを使用して何かすることができます。

ありがとうございました。

答えて

1

フィルターが再計算されない理由は、FilteredListの観点からは変更されないためです。

は擬似コードでは、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を登録し、それが変更された場合、フィルタを再計算します。 (現実には、それはおそらく、かなり複雑これ以上ですが、そのアイデアがあるでしょう。)

一方、SimpleObjectPropertyは(再び、これは擬似コード)以下を行います。つまり

public class SimpleObjectProperty<T> implements Property<T> { 

    private T value ; 

    public void set(T value) { 
     if (! Objects.equals(this.value, value)) { 
      T oldValue = this.value ; 
      this.value = value ; 
      notifyChangeListeners(oldValue, this.value); 
     } 
    } 
} 

ChangeListenerは、値が実際にに変更された場合にのみ通知されます。あなたの例では

(2番目のコードブロック)、検索フィールドの変更内のテキストが、あなたは毎回正確に同じ参照somePredicate

externalTradesFilteredList.setPredicate(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; 
    }; 

} 

externalTradeTableViewDataFilterTextField.textProperty().addListener((obs) -> 
    externalTradesFilteredList.setPredicate(createPredicate())); 

または同等には、クラスの作成:修正するには

、あなたが行うことができます

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; 
    } 

} 

をして、もちろんやる

externalTradeTableViewDataFilterTextField.textProperty().addListener((obs) -> 
    externalTradesFilteredList.setPredicate(new TradeTableFilter(externalTradeTableViewDataFilterTextField.getText().trim().toLowerCase())); 

あなたの質問には、実際に複数の質問を1つのフォーラムにまとめるべきではありません。他のユーザーが同じ問題に対する既存の回答を見つけるのが難しくなります。あなたはFunction<ExternalTrade, String>として、モデルのプロパティのリストを作成することができ

:あなたのモデルクラスに応じて、どのようにあなたが設定テーブルを持っている

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)); 
    }; 
} 

、あなたは可能性があります関数のリストでStringの代わりにObservableValueにマップすることができます。その場合、そのリストを再利用してループ内に列を作成することもできます。しかし、私はそれが可能かどうかを知るためにあなたの設定について十分に知りません。

+0

素晴らしいですが、私はチェックウルの解決策を適用しませんでしたが、意味があります。私はそれを試してみましょう。また、複数の質問を残して申し訳ありません。私は今から自分自身を修正します。 –

+0

ねえ、私はうまく解決しようとしています。最初に解決した問題。第2の問題。すべての列をループして、私はtradeProperties()と言うことができません。 p.containsは動作しません。私は述語であるpのcontainsメソッドを呼び出すことができません。 –

+0

Jamesに感謝します。出来た。どうもありがとう。 http://stackoverflow.com/questions/38801302/design-to-keep-helper-methods-in-javafx-projectを見てください。 –

関連する問題