我想问一下在TableView中捕获CheckBoxTableCell值变化的最优雅的方法是什么。
我的目标是在示例中显示的DB中保存新值:
printedColumn.setCellValueFactory(f -> f.getValue().getPrintedProperty());
printedColumn.setCellFactory(CheckBoxTableCell.forTableColumn(new Callback<Integer, ObservableValue<Boolean>>() {
@Override
public ObservableValue<Boolean> call(Integer param) {
ProductFx productFx = addProductModel.getProductFxObservableList().get(param);
updateInDatabase(productFx);
return productFx.getPrintedProperty();
}
}));
这很好,但是我认为这不是实现此目标的最佳方法。对于其他专栏,我将按照这种方式进行操作:
@FXML
public void onEditPrice(TableColumn.CellEditEvent<ProductFx, Number> e) {
ProductFx productFx = e.getRowValue();
productFx.setPrice(e.getNewValue().doubleValue());
updateInDatabase(productFx);
}
fxml:
<TableColumn fx:id="priceColumn" onEditCommit="#onEditPrice" prefWidth="75.0" text="%addProductTable.price" />
是否可以使用@FXML带注释的方法和fxml配置以类似的方式进行操作?也许还有其他想法?
答案 0 :(得分:0)
我真的很难把这个想法变成问题的背后。我发布了我认为应该如何执行的代码。如果它不符合您的要求,请详细说明您要达到的目标。
import javafx.application.Application;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.Stage;
public class TableViewApp extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
ObservableList<Product> products = FXCollections.observableArrayList(product -> new ObservableValue[] {product.nameProperty()});
products.add(new Product(1l, "Machine1"));
products.add(new Product(2l, "Machine2"));
products.addListener((ListChangeListener<Product>) change -> {
while (change.next()) {
if (change.wasUpdated()) {
for (int i = change.getFrom(); i < change.getTo(); i++) {
updateInDb(change.getList().get(i));
}
}
}
});
TableView<Product> tableView = new TableView<>(products);
tableView.setEditable(true);
TableColumn<Product, Long> idColumn = new TableColumn<>("Id");
idColumn.setCellValueFactory(cellData -> cellData.getValue().idProperty().asObject());
TableColumn<Product, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
nameColumn.setEditable(true);
tableView.getColumns().add(idColumn);
tableView.getColumns().add(nameColumn);
stage.setScene(new Scene(tableView));
stage.show();
}
private void updateInDb(Product product) {
System.out.println("Update " + product + " in db");
}
}
class Product {
private LongProperty id = new SimpleLongProperty();
private StringProperty name = new SimpleStringProperty();
public Product(long id, String name) {
this.id.set(id);
this.name.set(name);
}
public LongProperty idProperty() {
return id;
}
public long getId() {
return id.get();
}
public StringProperty nameProperty() {
return name;
}
public String getName() {
return name.get();
}
@Override
public String toString() {
return "Product[id=" + getId() + ", name=" + getName() + "]";
}
}
答案 1 :(得分:0)
我不详细了解您如何使代码工作。我猜想它不能按API的设计工作。我可以肯定地回答是否可以使用简单的FXML属性CheckBoxTableCell
:否。
对于CheckBoxTableCell
...单元格不必进入编辑状态(...)。这样做的副作用是将不调用通常的编辑回调(例如在编辑提交时)。如果您想收到更改通知, 建议直接观察以下布尔属性 由CheckBox操纵。
如javadoc所述。
如果printedProperty
类实现了ObservableValue<Boolean>
(如您的代码所述),则应遵循引用的文档并像其上添加一个ChangeListener
printedColumn.setCellValueFactory(f -> f.getValue().getPrintedProperty());
printedColumn.setCellFactory(CheckBoxTableCell.forTableColumn(new Callback<Integer, ObservableValue<Boolean>>() {
@Override
public ObservableValue<Boolean> call(Integer param) {
ProductFx productFx = addProductModel.getProductFxObservableList().get(param);
return productFx.getPrintedProperty();
}
}));
ObservableList<ProductFx> obs = addProductModel.getProductFxObservableList();
obs.addListener(new ListChangeListener<ProductFx>(){
@Override
public void onChanged(Change<? extends ProductFx> c) {
if(c.wasAdded()) {
for (ProductFx s:c.getAddedSubList()) {
s.getPrintedProperty().addListener(new ChangeListener<Boolean>() {
ProductFx localProductFx=s;
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
updateInDatabase(localProductFx);
}
});
}
}
}
});
但这一点都不优雅。
为您解决问题的方法:
每次更新显示的单元格时,都会调用您使用的Callback<Integer, ObservableValue<Boolean>>()
。在TableView
仅保留必要的Cell
实例以填充其视口(doc)时,尤其是在滚动庞大的列表时,会发生这种情况。它们只是在滚动过程中进行更新,并且每次发生这种情况时您的代码都会更新数据库,因此对于大型数据集或速度较慢的数据库,您可能会遇到性能问题。
PS:据我了解您的代码,您没有遵循usual naming conventions的属性。使用诸如PropertyValueFactory
之类的反射类可能会导致问题。