JavaFX TableView CheckBoxTableCell с boolean вместо SimpleBooleanProperty
Мне интересно, как я мог бы использовать CheckBoxTableCell без ObservableProperty. Я использую простое логическое выражение, потому что хочу сериализовать данные в свой DerbyDB.
Наверняка была бы возможность сделать SimpleBooleanProperty и аннексировать его с @Transient и обернуть его вокруг моего нормального boolean active.
Мое логическое значение отображается правильно, но я не могу сохранить новое значение после того, как флажок в моем Tableview нажат.
private void setupColActive() {
colActive.setCellValueFactory(new PropertyValueFactory<UserVillage, Boolean>("active"));
colActive.setCellFactory(CheckBoxTableCell.forTableColumn(colActive));
colActive.setEditable(true);
}
Я пробовал это с colActive.setOnEditCancel, colActive.setOnEditCommit и colActive.setOnEditStart в комбинации с печатью контуров, но я не могу поймать новое значение, чтобы сохранить его. Я хотел бы найти способ заставить его работать, не оборачиваясь в @Transient SimpleBooleanProperty active.
1 ответ:
Проблема сериализации не мешает вам использовать свойства JavaFX в классе модели
UserVillage. Я бы рекомендовал использовать эти свойства и просто настроить механизм сериализации, определив методыreadObjectиwriteObject. Вот демонстрация класса, определенного следующим образом:public class Item implements Serializable { private StringProperty name ; private IntegerProperty value ; private BooleanProperty active ; public Item(String name, int value, boolean active) { this.name = new SimpleStringProperty(name) ; this.value = new SimpleIntegerProperty(value); this.active = new SimpleBooleanProperty(active); } public final StringProperty nameProperty() { return this.name; } public final java.lang.String getName() { return this.nameProperty().get(); } public final void setName(final java.lang.String name) { this.nameProperty().set(name); } public final IntegerProperty valueProperty() { return this.value; } public final int getValue() { return this.valueProperty().get(); } public final void setValue(final int value) { this.valueProperty().set(value); } public final BooleanProperty activeProperty() { return this.active; } public final boolean isActive() { return this.activeProperty().get(); } public final void setActive(final boolean active) { this.activeProperty().set(active); } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(getName()); out.writeInt(getValue()); out.writeBoolean(isActive()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { this.name = new SimpleStringProperty((String)in.readObject()); this.value = new SimpleIntegerProperty(in.readInt()); this.active = new SimpleBooleanProperty(in.readBoolean()); } // Quick test: public static void main(String[] args) throws IOException, ClassNotFoundException { Item testItem = new Item("Item", 42, true); ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(testItem); oos.close(); byte[] bytes = out.toByteArray(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes)); Item result = (Item) in.readObject(); System.out.println(result.getName()); System.out.println(result.getValue()); System.out.println(result.isActive()); } }При таком подходе
CheckBoxTableCellбудет автоматически привязываться к свойству, возвращаемомуPropertyValueFactory.Альтернативой является создание
BooleanPropertyспециально для привязки к флажку выбранное состояние. Обратите внимание, что в соответствии с Javadocs , посколькуCheckBoxTableCellникогда не входит и не выходит из состояния редактирования, обратные вызовы редактированияonEditCommitи т. д. Никогда не вызываются:Обратите внимание, что CheckBoxTableCell отображает флажок "live", Что означает что флажок всегда является интерактивным и может быть непосредственно переключен пользователь. Это означает, что нет необходимости, чтобы клетка входила в свою редактирование состояния (обычно пользователь дважды щелкает по ячейке). Один побочный эффект это то, что обычное редактирование обратных вызовов (например, на edit commit) не будет вызван. Если вы хотите, чтобы вас уведомили о изменения, рекомендуется непосредственно наблюдать за булевыми свойствами которые управляются флажком.
Вот демонстрационный пример использования этой техники. Опять же, я не очень рекомендую этот подход, так как вы в конечном итоге создаете кучу
BooleanProperty, которые быстро подходят для сборки мусора. Предполагаемый подход заключается в том, чтобы модель использовала JavaFX свойства.import java.util.stream.IntStream; import javafx.application.Application; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.CheckBoxTableCell; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class TableViewCheckBoxTest extends Application { @Override public void start(Stage primaryStage) { TableView<Item> table = new TableView<>(); table.setEditable(true); table.getColumns().add(createColumn("Name", "name")); table.getColumns().add(createColumn("Value", "value")); TableColumn<Item, Boolean> activeCol = createColumn("Active", "active"); table.getColumns().add(activeCol); activeCol.setCellFactory(col -> { CheckBoxTableCell<Item, Boolean> cell = new CheckBoxTableCell<>(index -> { BooleanProperty active = new SimpleBooleanProperty(table.getItems().get(index).isActive()); active.addListener((obs, wasActive, isNowActive) -> { Item item = table.getItems().get(index); item.setActive(isNowActive); }); return active ; }); return cell ; }); Button listActiveButton = new Button("List active"); listActiveButton.setOnAction(e -> table.getItems().stream() .filter(Item::isActive) .map(Item::getName) .forEach(System.out::println)); IntStream.rangeClosed(1, 100) .mapToObj(i -> new Item("Item "+i, i, false)) .forEach(table.getItems()::add); BorderPane root = new BorderPane(table, null, null, listActiveButton, null) ; BorderPane.setAlignment(listActiveButton, Pos.CENTER); BorderPane.setMargin(listActiveButton, new Insets(10)); Scene scene = new Scene(root, 800, 600); primaryStage.setScene(scene); primaryStage.show(); } private <S,T> TableColumn<S,T> createColumn(String title, String propertyName) { TableColumn<S,T> col = new TableColumn<>(title); col.setCellValueFactory(new PropertyValueFactory<>(propertyName)); return col; } public static class Item implements Serializable { private String name ; private int value ; private boolean active ; public Item(String name, int value, boolean active) { this.name = name ; this.value = value ; this.active = active ; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } } public static void main(String[] args) { launch(args); } }
Comments