gpt4 book ai didi

JavaFx:如何正确触发 TableCell 中的 updateItem

转载 作者:行者123 更新时间:2023-11-29 08:22:32 28 4
gpt4 key购买 nike

我必须实现大量自定义 TableCell,其行为依赖于模型的更改。我可以设法以某种方式获得预期的结果,但我认为在许多情况下这是一种变通方法,而不是一个非常好的解决方案。我已使用绑定(bind)/监听器来实现预期结果,但我面临的问题是我可能会多次添加监听器/绑定(bind)属性,这会造成内存泄漏。

这是我的意思的一个例子。

Controller :

public class Controller implements Initializable {

@FXML private TableView<Model> table;
@FXML private TableColumn<Model, String> column;
@FXML private Button change;

@Override
public void initialize(URL location, ResourceBundle resources) {

column.setCellValueFactory(data -> data.getValue().text);
column.setCellFactory(cell -> new ColoredTextCell());

Model apple = new Model("Apple", "#8db600");

table.getItems().add(apple);
table.getItems().add(new Model("Banana", "#ffe135"));

change.setOnAction(event -> apple.color.setValue("#ff0800"));

}

@Getter
private class Model {
StringProperty text;
StringProperty color;

private Model(String text, String color) {
this.text = new SimpleStringProperty(text);
this.color = new SimpleStringProperty(color);
}
}

private class ColoredTextCell extends TableCell<Model, String> {

@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
setGraphic(null);
return;
}
Model model = (Model) getTableRow().getItem();
Text text = new Text(item);
text.setFill(Color.web(model.getColor().getValue()));

// This way I add the listener evey item updateItem is called.
model.getColor().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
text.setFill(Color.web(newValue));
} else {
text.setFill(Color.BLACK);
}
});
setGraphic(text);
}
}

}

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="stackoverflow.tabpane.Controller">
<VBox>
<Button fx:id="change" text="Change color"/>
<TableView fx:id="table">
<columns>
<TableColumn fx:id="column" prefWidth="200"/>
</columns>
</TableView>
</VBox>
</AnchorPane>

由于单元格不能直接观察到颜色属性,因此如果它发生变化,则不会调用 updateItem,因此我必须以某种方式进行监听。我需要在 color 更改后触发 updateItem。这将导致对监听器内容的单次调用。

有没有办法在同一个单元格中监听模型的另一个变化,或者以某种方式调用更新项,以便呈现变化。

最佳答案

使用监听器和绑定(bind)不会导致任何问题,只要您记得在不再需要时删除它们即可。为了让它更安全,你应该使用弱监听器(绑定(bind)使用弱监听器)。当您想根据行项目的不同属性更改单元格文本的颜色时,我认为使用绑定(bind)会更容易。请注意,TableCell 继承自 Labeled,这意味着它具有 textFill 属性;无需创建 Text 节点来更改文本的颜色。

这是一个例子:

import javafx.beans.binding.Bindings;
import javafx.scene.control.TableCell;
import javafx.scene.paint.Color;

public class ColoredTextCell extends TableCell<Model, String> {

@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);

/*
* I was getting a NullPointerException without the "getTableRow() == null"
* check. I find it strange that a TableCell's "updateItem" method would be
* invoked before it was part of a TableRow... but the added null check seems
* to solve the problem (at least when only having two items in the table and
* no scrolling).
*/
if (empty || item == null || getTableRow() == null) {
setText(null);
textFillProperty().unbind();
} else {
setText(item);

Model rowItem = getTableRow().getItem();
textFillProperty().bind(Bindings.createObjectBinding(
() -> Color.valueOf(rowItem.getColor()),
rowItem.colorProperty()
));
}
}

}

调用 textFillProperty().unbind() 将防止内存泄漏。并且在绑定(bind)属性时,先前的绑定(bind)(如果有)将被删除。如果你真的很偏执,你也可以在 bind(...) 之前调用 unbind()。如果您真的,真的偏执,那么您可以将 ObjectBinding 存储在一个字段中并调用 dispose()在适当的时候(甚至取消它)。

关于JavaFx:如何正确触发 TableCell 中的 updateItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56376551/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com