在这种情况下:我有一个ObservableSet(因为我的数据的ID字段必须是唯一的),它有一个监听器。该侦听器更新ObservableList。反过来,ObservableList由TableView监听。 (根据评论,这是必要的,因为ObservableSet不能用于支持JavaFX中的TableView。)
然而,我们发现,对Set执行多次add
操作会触发TableView的刷新。
这适用于:
但是,编辑该值时,TableView只会在单个add
语句中触发(在下面的示例中,注释掉markStructure.add(new MarkStructureItem(2, 15));
使其工作正常,但之后您只有一个单一的价值)。如果有多个,则TableView不会刷新。
这可以通过在Listener类(tblTable.refresh()
)末尾添加手动刷新来解决。这实际上是它到目前为止的运作方式,但现在开发需要将其删除。
知道发生了什么事吗?为什么TableView上的监听器不会被后续add
触发?数据被放入集合和列表中,已经确定了很多;它只是没有触发刷新。
代码示例(不是生产,而是我整理测试并获得答案的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);
}
}
答案 0 :(得分:2)
问题1:
您的equals
实施不是null
- 安全,您使用引用相等(Integer
)而不是==
来比较equals
。只要您在缓存值范围内并使用自动装箱,这可能会起作用,但在该范围之外停止工作(此范围仅保证为-128到127,请参阅Integer.valueOf(int)
)。 />
由于您在Object
中使用了Set
,因此建议您id
无法修改。否则,您需要在修改它之前从集合中删除该值并将其添加回Set
(哈希代码更改),否则会破坏列表中的顺序,除非您暂时阻止SetChangeListener
从更新列表。
同样使用基本类型可以防止==
的问题。
问题2:
要在marks
中显示TableView
属性中的任何更改,您需要提供一个marksProperty()
方法来返回该属性本身。这是TableView
收听属性更改所必需的。
public class MarkStructureItem {
final SimpleIntegerProperty marks;
final int id;
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object obj) {
return obj != null
&& obj.getClass() == this.getClass()
&& this.id == ((MarkStructureItem) obj).id; // primitive type can be compared using ==
// && this.getId().equals(((MarkStructureItem) obj).getId()); // alternative for non-primitive types
}
public MarkStructureItem(int finishPosition, Integer marks) {
this.marks = new SimpleIntegerProperty(marks);
this.id = finishPosition;
}
public int getId() {
return id;
}
public IntegerProperty marksProperty() {
return marks;
}