【发布时间】:2017-02-23 06:04:53
【问题描述】:
情况如下:我有一个 ObservableSet(因为我的数据的 ID 字段必须是唯一的),它有一个侦听器。该侦听器更新一个 ObservableList。反过来,该 ObservableList 由 TableView 监听。 (根据 cmets 的说法,这都是必要的,因为 ObservableSet 不能用于支持 JavaFX 中的 TableView。)
然而,我们发现,对 Set 执行多个 add 操作不会触发 TableView 的刷新。
这适用于:
- 初始列表人口
- 重复集条目(未触发侦听器,这是预期行为)
但是,在编辑值时,TableView 只会在有单个 add 语句时触发(在下面的示例中,注释掉 markStructure.add(new MarkStructureItem(2, 15)); 使其工作正常,但您只有一个值)。如果有多个,TableView 不会刷新。
这可以通过在 Listener 类 (tblTable.refresh()) 的末尾添加手动刷新来解决。这实际上是它迄今为止的运作方式,但现在开发需要删除它。
知道发生了什么吗?为什么 TableView 上的监听器没有被后续的adds 触发?数据正在被放入 Set 和 List 中,已经确定了很多;它只是没有触发刷新。
代码示例(不是生产,而是我放在一起测试和获得答案的 POC):
public class TestController implements Initializable {
ObservableSet<MarkStructureItem> markStructure = FXCollections.observableSet();
ObservableList<MarkStructureItem> listMarkStructure = FXCollections.observableArrayList();
@FXML
private Pane root;
@FXML
private TableView<MarkStructureItem> tblTable;
@FXML
private TableColumn<MarkStructureItem, Integer> col1;
@FXML
private TableColumn<MarkStructureItem, Integer> col2;
@FXML
private Button btnButton;
private void resetAll() {
markStructure.clear();
markStructure.add(new MarkStructureItem(1, 25));
markStructure.add(new MarkStructureItem(2, 15));
}
@FXML
private void handleButtonAction(ActionEvent event) throws IOException {
Object source = event.getSource();
Button btnSource = (Button) source;
Stage stage = (Stage) root.getScene().getWindow();
switch (btnSource.getId()) {
case "btnButton": {
resetAll();
break;
}
}
}
class MarksUpdater<MarkStructureItem extends configurationeditor.MarkStructureItem> implements SetChangeListener {
@Override
public void onChanged(Change change) {
if (change.wasRemoved()) {
listMarkStructure.remove(change.getElementRemoved());
} else if (change.wasAdded()) {
MarkStructureItem newMarks = (MarkStructureItem) change.getElementAdded();
listMarkStructure.add(newMarks);
}
}
}
@Override
public void initialize(URL url, ResourceBundle rb) {
markStructure.addListener(new MarksUpdater<MarkStructureItem>());
col1.setCellValueFactory(
new PropertyValueFactory<MarkStructureItem, Integer>("id")
);
col2.setCellValueFactory(
new PropertyValueFactory<MarkStructureItem, Integer>("marks")
);
col2.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
col2.setOnEditCommit(
new EventHandler<CellEditEvent<MarkStructureItem, Integer>>() {
@Override
public void handle(CellEditEvent<MarkStructureItem, Integer> t) {
((MarkStructureItem) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setMarks(t.getNewValue());
}
}
);
tblTable.setItems(listMarkStructure);
resetAll();
}
}
markStructure 类:
public class MarkStructureItem {
final SimpleIntegerProperty marks;
final SimpleIntegerProperty id;
@Override
public int hashCode() {
return this.getId().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj.getClass() == this.getClass()) {
MarkStructureItem thisObj = (MarkStructureItem) obj;
return thisObj.getId() == this.getId();
}
return false;
}
public MarkStructureItem(Integer finishPosition, Integer marks) {
this.marks = new SimpleIntegerProperty(marks);
this.id = new SimpleIntegerProperty(finishPosition);
}
public Integer getId() {
return id.get();
}
public void setMarks(Integer value) {
marks.set(value);
}
public Integer getMarks() {
return marks.get();
}
public void setId(Integer value) {
id.set(value);
}
}
【问题讨论】:
-
你能发布
MarkStructureItem类吗?设置更改侦听器的onChanged方法是否被调用以添加到集合中? (除此之外:您对泛型的使用存在严重缺陷,尽管这与实际问题完全不同。) -
将其添加到原始问题中。每次添加都会调用自定义 onChanged。刷新触发器似乎没有从 onChanged 中调用。我对正确使用泛型(PM 或诸如此类)的方向感兴趣......这是继承的代码,我们可以使它更好的任何方式都值得赞赏!谢谢!
-
return thisObj.getId() == this.getId();可能会导致问题,因为 getId() 返回一个对象。由于您在内部使用 IntegerProperty,因此 id 属性的类型实际上应该是 int,而不是 Integer,这将是解决问题的最佳方法。 -
此外,最好遵循JavaFX Properties pattern,即将
idProperty()和marksProperty()方法添加到MarkStructureItem类中。话虽如此,我逐字测试了您的代码,它完全按预期工作......所以也许还有其他地方不正确。你能扩展成minimal reproducible example吗?您的处理程序方法也很奇怪,为什么要打开按钮的 id?无论如何,您应该(几乎总是)将该方法作为处理程序的一个控件。 -
对于泛型,您应该拥有
public class MarksUpdater implements SetChangeListener<MarkStructureItem>和public void onChanged(Change<? extends MarkStructureItem> change) { ... }。然后只需将其实例化为new MarksUpdater(),即可移除change.getElementAdded()上的演员表。
标签: java javafx actionlistener fxml