我有一个SetProperty
private final SetProperty<String> origins = new SimpleSetProperty<>(FXCollections.observableSet(new TreeSet<>()));
如果我以这种方式修改此属性,一切都按预期工作(我的TableView会收到有关更改的通知)
this.origins.setValue(FXCollections.observableSet(new LinkedHashSet<>(origins)));
如果我以这种方式修改此属性,则不会通知我的TableView
this.origins.clear();
this.origins.addAll(origins);
由于此属性的值是一个可观察的集合,因此我希望SetProperty能够通知底层集合的更改,并将此更改事件传播给它的侦听器(在本例中为TableView)。 / p>
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>
[..]
数据bean看起来像这样:
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);
}
}
答案 0 :(得分: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();
}
如您所见,标准ChangeListener和一个特殊的SetChangeListener有两种侦听器,它们可以在set属性上注册。 每次修改列表(添加或删除操作)或由新的ObservableList替换时,标准ChangeListener都会触发。如果列表被修改,则SetChangeListener仅触发。
结果:
ChangeListener was called
ChangeListener was called
SetListener was called
ChangeListener was called
SetListener was called
示例中的第一个操作是替换整个列表。这导致调用所有ChangeListeners但不调用SetChangeListeners。
第二个动作添加&#34; Test1&#34;到集合并且两个侦听器都被执行。
第三个动作不会修改集合,因为&#34; Test1&#34;已经是集合的成员,集合不包含重复项。没有变化 - &gt;没有改变事件。
第4个动作删除&#34; Test1&#34;从集合和两个侦听器都被执行。
第5个动作(再次)没有修改集合,因为它已经是空的。
更新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);
}
}
我希望这有助于找到你的问题。
更新2 我在SimpleMapProperty和SimpleSetProperty中发现了一个错误。如果您有多个ChangeListener并且同时没有在您的属性上注册MapChangeListener / SetChangeListener,则不会执行监听器。这是MapExpressionHelper和SetExpressionHelper中的一个错误。
如果你想解决它只是注册一个空的Map / SetChangeListener,它将再次工作。 E.g:
setProperty.addListener((SetChangeListener.Change<?> change) -> {});