0

У меня есть SetPropertySetProperty не срабатывает событие изменения

private final SetProperty<String> origins = new SimpleSetProperty<>(FXCollections.observableSet(new TreeSet<>())); 

Если я изменить это свойство так все работает, как ожидалось (My TableView уведомляется об изменении)

this.origins.setValue(FXCollections.observableSet(new LinkedHashSet<>(origins))); 

Если я изменяю это свойство таким образом, мой TableView не уведомлен

this.origins.clear(); 
this.origins.addAll(origins); 

Поскольку для этого свойства используется obse rvable, я бы ожидал, что SetProperty будет уведомлен об изменениях базового набора, а также распространит это событие изменения на его слушателей (в данном случае TableView).

TableView создается следующим образом: FXML:

[..] 
<TableView fx:id="table" GridPane.columnIndex="0" 
GridPane.rowIndex="1" editable="true" 
GridPane.hgrow="always" GridPane.vgrow="always"> 
<columns> 
    <TableColumn text="Files"> 
     <cellValueFactory> 
      <PropertyValueFactory property="origins" /> 
     </cellValueFactory> 
    </TableColumn> 
</columns> 
</TableView> 
[..] 

боб данных выглядит следующим образом:

public abstract class AbstractPeakBean extends VeryAbstractPeakBean implements PeakBean { 


private final SetProperty<String> origins = new SimpleSetProperty<>(FXCollections.observableSet(new TreeSet<>())); 


public void addAllOrigins(Collection<String> origins) { 

    this.origins.addAll(origins); 
} 

@Override 
public AbstractPeakBean addOrigin(String origin) { 

    this.origins.add(origin); 
    return this; 
} 

@Override 
public Collection<String> getOrigins() { 

    return Collections.unmodifiableCollection(origins); 
} 

@Override 
public SetProperty<String> originsProperty() { 

    return origins; 
} 

@Override 
public AbstractPeakBean setAllOrigins(Collection<String> origins) { 

    this.origins.clear(); 
    this.origins.addAll(origins); 
    this.origins.setValue(FXCollections.observableSet(new LinkedHashSet<>(origins))); 
    return this; 
} 

public void setOrigins(Collection<String> origins) { 

    this.origins.clear(); 
    this.origins.addAll(origins); 
} 
} 
+2

Вы не указали код, который позволяет нам воспроизвести проблему. Также неясно, как работает «TableView» с набором ... Также набор, содержащий те же элементы, может быть легко сравним с исходным набором ... – fabian

ответ

0

Я сделал небольшой пример, чтобы испытать вас проблемы, и она работает, как ожидалось :

public static void main(String[] args) { 
    SetProperty<String> origins = new SimpleSetProperty<>(FXCollections.observableSet(new TreeSet<>())); 
    origins.addListener((obs, ov, nv) -> System.out.println("ChangeListener was called")); 
    origins.addListener((SetChangeListener.Change<?> change) -> System.out.println("SetListener was called")); 

    origins.set(FXCollections.observableSet(new TreeSet<>())); 
    origins.get().add("Test1"); 
    origins.get().add("Test1"); 
    origins.get().clear(); 
    origins.get().clear(); 
} 

Как вы можете видеть, есть два вида слушателей стенд ard ChangeListener и специальный SetChangeListener, который может быть зарегистрирован в заданном свойстве. Стандартный ChangeListener запускается каждый раз, когда список был изменен (добавление или удаление действий) или заменен новым ObservableList. Только SetChangeListener срабатывает, если список был изменен.

Результат:

ChangeListener was called 
ChangeListener was called 
SetListener was called 
ChangeListener was called 
SetListener was called 

Первое действие на примере происходит замена всего списка. Это приводит к призыву ко всем ChangeListeners, но не к SetChangeListeners.

Второе действие добавляет «Test1» к набору, и оба слушателя выполняются.

Третье действие не изменяет набор, потому что «Test1» уже является членом набора, а наборы не содержат дубликатов. Без изменений -> без изменений.

4-е действие удаляет «Test1» из набора и выполняется оба прослушивателя.

5-е действие (опять же) не изменяет набор, поскольку оно уже было пустым.


Update 1

Я сделал небольшой пример приложения, и я мог бы изменить текущий список и поменять весь список в виде таблицы без проблем:

import javafx.application.Application; 
import javafx.beans.property.ReadOnlyObjectWrapper; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

public class Main extends Application { 

    private VBox root; 
    private TableView<String> tableView; 
    private TableColumn<String, Character> lettersColumn; 
    private ObservableList<String> items; 
    private Scene scene; 
    private Button button1; 
    private Button button2; 

    @Override 
    public void start(Stage primaryStage) { 
     items = FXCollections.observableArrayList(); 
     items.addAll("Aa", "Bb", "Cc"); 
     tableView = new TableView<>(items); 
     lettersColumn = new TableColumn<>("FirstLetters"); 
     lettersColumn.setCellValueFactory(cellDataFeature -> 
      new ReadOnlyObjectWrapper<>(cellDataFeature.getValue().charAt(0)) 
     ); 

     tableView.getColumns().add(lettersColumn); 

     button1 = new Button("Add item"); 
     button1.setOnMouseClicked(event -> items.add("Dd")); 

     button2 = new Button("Swap whole list"); 
     button2.setOnMouseClicked(event -> { 
      items = FXCollections.observableArrayList(); 
      items.addAll("1a", "2b", "3c"); 
      tableView.setItems(items); 
     }); 

     root = new VBox(tableView, button1, button2); 
     scene = new Scene(root); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

Я надеюсь, что это помогает найти вашу проблему.


Update 2 Я нашел ошибку в SimpleMapProperty и SimpleSetProperty. Если у вас есть более 1 ChangeListener, и в то же время ни один MapChangeListener/SetChangeListener, зарегистрированный в вашем свойстве, Listeners не будет выполнен. Это ошибка в MapExpressionHelper и SetExpressionHelper.

Если вы хотите обходным путем, просто зарегистрируйте пустую карту/SetChangeListener, и она снова будет работать. Например:

setProperty.addListener((SetChangeListener.Change<?> change) -> {}); 
+0

Большое спасибо за ваши объяснения! Знаете ли вы, какие слушатели зарегистрированы в SetProperty, когда он используется TableView, настроенным через FXML (как показано выше)? – kerner1000

+0

Хм, я нашел только класс WeakListChangeListener в классе TabelView. Но поскольку TableView позволяет обменивать весь список (setItems), он также должен следить за этими событиями. – Zerlono

+0

Решена ли ваша проблема? – Zerlono

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

  • Нет связанных вопросов^_^