Мне нужно реализовать множество пользовательских таблиц, поведение которых зависит от изменения модели. Мне удалось каким-то образом получить ожидаемый результат, но я думаю, что во многих случаях это был обходной путь, а скорее действительно хорошее решение.
Я использовал привязки / прослушиватели для достижения ожидаемого результата, но проблема, с которой я сталкиваюсь, заключается в том, что я могу добавлять прослушиватели / привязывать свойства несколько раз, и это может привести к утечкам памяти.
Вот пример того, что я имею в виду.
Контроллер:
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>
Поскольку свойство color непосредственно не наблюдается в ячейке, updateItem не вызывается, если оно изменяется, поэтому я должен как-то прослушать.
Мне нужно, чтобы updateItem
был запущен после изменения цвета . Это приведет к единственному обращению к содержимому слушателя.
Есть ли способ прослушать другое изменение модели в той же ячейке или как-то вызвать элемент обновления, чтобы изменение было обработано.