javafx checkBoxTableCell回调

时间:2018-11-18 15:57:18

标签: javafx callback fxml

我想问一下在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配置以类似的方式进行操作?也许还有其他想法?

2 个答案:

答案 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之类的反射类可能会导致问题。