JavaFX 应用程序无法在 lambda 表达式上编译

JavaFX Application fails to compile on lambda expression

我正在尝试构建一个 JavaFX 应用程序来显示 TreeTableView。仍在设置这整个事情。我让它在没有 Product class 的情况下只使用一列,但我正在努力使其与 Product class 和两列一起使用。以下代码无法编译:

 col1.setCellValueFactory(
            (TreeTableColumn.CellDataFeatures<Product, String> param) -> param.getValue().getValue().getNameProperty());

并吐出这个错误:

Error:(38, 121) java: incompatible types: bad return type in lambda expression
java.lang.String cannot be converted to javafx.beans.value.ObservableValue<java.lang.String>

这是完整的代码:

public class Controller implements Initializable {

    @FXML
    private TreeTableView<Product> tableView;
    @FXML
    private TreeTableColumn<Product, String> col1;
    @FXML
    private TreeTableColumn<Product, String> col2;

    TreeItem<Product> product1 = new TreeItem<>(new Product("Bread", "300g"));
    TreeItem<Product> product2 = new TreeItem<>(new Product("Eggs", "5"));
    TreeItem<Product> product3 = new TreeItem<>(new Product("Brad Pitt", "One and Only one"));
    TreeItem<Product> product4 = new TreeItem<>(new Product("Moisturizer", "20"));
    TreeItem<Product> product5 = new TreeItem<>(new Product("Horse Lubricant", "4"));

    TreeItem<Product> root = new TreeItem<>(new Product("Name", "Quantity"));

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        root.getChildren().setAll(product1, product2, product3, product4, product5);

        col1.setCellValueFactory(
                (TreeTableColumn.CellDataFeatures<Product, String> param) -> param.getValue().getValue().getNameProperty());
        col2.setCellValueFactory(
                (TreeTableColumn.CellDataFeatures<Product, String> param) -> param.getValue().getValue().getQuantityProperty());

        tableView.setRoot(root);
        tableView.setShowRoot(false);
    }

    public class Product{
        SimpleStringProperty nameProperty;
        SimpleStringProperty quantityProperty;

        public Product(String name, String quantity){
            this.nameProperty = new SimpleStringProperty(name);
            this.quantityProperty = new SimpleStringProperty(quantity);
        }

        public String getNameProperty() {
            return nameProperty.get();
        }

        public SimpleStringProperty namePropertyProperty() {
            return nameProperty;
        }

        public void setNameProperty(String nameProperty) {
            this.nameProperty.set(nameProperty);
        }

        public String getQuantityProperty() {
            return quantityProperty.get();
        }

        public SimpleStringProperty quantityPropertyProperty() {
            return quantityProperty;
        }

        public void setQuantityProperty(String quantityProperty) {
            this.quantityProperty.set(quantityProperty);
        }
    }
}

首先,你的Productclass不符合常规。通常,字段名称匹配 属性 名称(例如 name,而不是 nameProperty)。然后你用 属性 的名字命名你的 getter、setter 和 属性 getter。例如:

import javafx.beans.property.StringProperty;
import javafx.beans.property.SimpleStringProperty;

public class Product {

  private final StringProperty name = new SimpleStringProperty(this, "name");
  public final void setName(String name) { this.name.set(name); }
  public final String getName() { return name.get(); }
  public final StringProperty nameProperty() { return name; }

  private final StringProperty quantity = new SimpleStringProperty(this, "quantity");
  public final void setQuantity(String quantity) { this.quantity.set(quantity); }
  public final String getQuantity() { return quantity.get(); }
  public final StringProperty quantityProperty() { return quantity; }

  public Product() {} // typically Java(FX)Beans provide no-arg constructors as well

  public Product(String name, String quantity) {
    setName(name);
    setQuantity(quantity);
  }
}

注意:你的class是一个非静态嵌套(即内部)class。这意味着每个 Product 实例都需要一个封闭 class 的实例。如果您想将 Product 保留为嵌套的 class,请考虑将其设为静态。我上面的例子假设 Product 在它自己的源文件中。

有了 class,您可以像这样定义单元格值工厂:

TreeTableColumn<Product, String> nameCol = ...;
nameCol.setCellValueFactory(data -> data.getValue().getValue().nameProperty());

TreeTableColumn<Product, String> quantityCol = ...;
quantityCol.setCellValueFactory(data -> data.getValue().getValue().quantityProperty());

注意工厂 return Product 实例的适当 属性。这解决了你的编译错误,因为 StringPropertyObservableValue<String> 的一个实例。这也意味着您的 table 可以直接访问支持模型的 属性,这有助于使 table 保持最新并实现内联编辑。


如果有帮助,这里使用匿名 class 设置 nameCol 的单元格值工厂,它明确显示所有使用的类型:

nameCol.setCellValueFactory(new Callback<>() { // may have to explicitly define type arguments, depending on version of Java

  @Override
  public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<Product, String> data) {
    TreeItem<Product> treeItem = data.getValue();
    Product product = treeItem.getValue();
    return product.nameProperty();
  }
});