2015-09-22 2 views
0

У меня есть TableView, который содержит наблюдаемый список из Person элементов. Каждая строка отображает объект Person, а также отображается его атрибут name.Javafx: Неправильное использование метода setPredicate отфильтрованного списка

Я хочу передать это наблюдаемое в отфильтрованный список и установить предикат на атрибут имени.

То, что я хочу добиться того, что: Если я дважды нажмите любую одну строку в TableView, который содержит Person элементов, я смог бы извлечь names атрибуты выбранного Person объекта и установить предикат отфильтрованных чтобы быть выбранным именем.

Таким образом, отфильтрованный список будет содержать только Person элементов с выбранным именем.

Следующий код почти достигает всего, что я хочу. Тем не менее, есть краевой кейс, где он не работает должным образом. Это когда, например, я дважды нажимаю на человека с именем «Name = John». Отфильтрованный список будет фильтровать всех людей с именем «Джон». Теперь, если я изменил одно из имен человека в отфильтрованном списке на «Тим». Этот человек по-прежнему сохраняется в отфильтрованном списке. В идеале, я хочу, чтобы его удаляли автоматически. Но я не могу этого сделать.

Я считаю, что я не использую setPredicate правильно, как я чувствую, что я пишу избыточные коды и должны быть более эффективный способ сделать это и будет автоматически удалить человека с другим именем сразу после Edit.

В моем 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);    
      } 
     }); 
    } 
} 
+0

Вам не нужно было бы фильтровать список при фиксации обновления имени? –

+0

@purringpigeon Нет, вам просто нужно убедиться, что основной список запускает обновления при изменении свойств. –

+0

Я рассмотрел этот вопрос, прежде чем я разместил этот вопрос, и я сделал все, что было в ответе, который вы отправили на вопрос. Я добавил 'new ObservableList [] {p -> p.NameProperty() ....} ' – mynameisJEFF

ответ

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

До тех пор, пока у вас есть имущество возвращается имя как часть экстрактора для основного списка, фильтр будет перепрофилироваться - оценивается при изменении имени.

+0

Как бы вы инициализировали filterList в этом случае, так как ему нужно взять логический аргумент? – mynameisJEFF

+0

['FilteredList'] (http://docs.oracle.com/javase/8/javafx/api/javafx/collections/transformation/FilteredList.html) не« принимает логический аргумент ». Он ожидает «ObservableList» и «Predicate». –

+0

Я имею в виду в моем классе Controller, когда я инициализировал отфильтрованный список, я сделал это: 'private FilteredList filterListOfPerson = new FilteredList <> (observableListOfPerson, p-> p.nameProperty(). Get());'. И он жалуется, что несоответствие типов: String не может быть преобразовано в boolean. Я вспомнил, что именно поэтому я создал логическое свойство в первую очередь. – mynameisJEFF

Смежные вопросы