背景。我正在使用来自JavaFX 2.1 TableView refresh items的刷新解决方案,因为我正在进行的项目停留在Java 8u40上。我知道在8u60中添加了refresh()
。
我也使用自定义单元格内容,而且内容包含鼠标听众,客户要求离奇,不要问。
问题是在表更新时发生的鼠标事件有时会丢失。 TableCell可以看到该事件,但不是自定义内容。
最后的示例演示了如果您反复点击"自定义内容"标签。我希望总能看到一对事件。
MouseClicked on custom stuff
MouseClicked on TableCell
但是,在某些情况下,我们只会看到MouseClicked on TableCell
。
我只能假设此时表格位于重绘的中间位置,自定义标签目前不是场景图形的一部分。我不明白这是如何发生的,因为鼠标事件和表更新都发生在同一个线程上....
我在更好地解释正在发生的事情和可能的解决方法之后。
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
public class Item {
private int x;
public Item(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
@Override
public int hashCode() {
return x;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Item) {
return x == ((Item) obj).x;
}
return false;
}
}
private static class CustomCell extends TableCell<Item, Integer> {
private Label custom;
public CustomCell() {
super();
setOnMouseClicked(event -> System.out.println("MouseClicked on TableCell"));
custom = new Label("Custom stuff");
custom.setOnMouseClicked(event -> System.out.println("MouseClicked on custom stuff"));
}
@Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setGraphic(custom);
}
}
}
@Override
public void start(Stage primaryStage) throws Exception {
List<Item> original = Arrays.asList(new Item(1), new Item(2));
ObservableList<Item> list = FXCollections.observableArrayList(original);
TableView<Item> tableView = new TableView<Item>(list);
TableColumn<Item, Integer> column = new TableColumn<>();
column.setPrefWidth(100);
column.setCellValueFactory(new PropertyValueFactory<>("x"));
column.setCellFactory(col -> new CustomCell());
tableView.getColumns().add(column);
primaryStage.setScene(new Scene(new HBox(tableView)));
primaryStage.show();
Timeline animation = new Timeline();
animation.setCycleCount(Animation.INDEFINITE);
animation.getKeyFrames().add(new KeyFrame(Duration.millis(400), e -> {
// poor-mans refresh
list.removeAll(list);
list.addAll(original);
}));
animation.play();
}
}
进一步的调查显示,setGraphic(null)
的调用导致了问题,而removeAll()
又引发了问题。在项目到位之前的这段时间内,事件将丢失。
我开发了一种替代刷新机制,它滥用了单元格值工厂并避免了removeAll()调用。
1)将JavaFX属性添加到您的项目模型中,该属性不会用于其他任何内容
private IntegerProperty update = new SimpleIntegerProperty();
public final IntegerProperty updateProperty() {
return this.update;
}
public void update() {
updateProperty().set(update.get() + 1);
}
2)更改所有需要更新的列以使用它,这并不重要,因为所有列都是从多个字段派生它们的值
column.setCellValueFactory(new PropertyValueFactory<>("update"));
3)改变穷人刷新
// poor-mans refresh
for (Item each : list) {
each.update();
}