JavaFX:自定义等于方法导致TableView中没有刷新

时间:2016-10-13 23:06:53

标签: java javafx actionlistener fxml

在这种情况下:我有一个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);
}
}

1 个答案:

答案 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;
    }