【问题标题】:Bind column to multiplication of other columns [duplicate]将列绑定到其他列的乘法[重复]
【发布时间】:2016-06-20 20:30:04
【问题描述】:

我想将金额列绑定到价格和数量列,以便每次数量或价格时,金额都会更新。

    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.event.EventHandler;
    import javafx.geometry.Insets;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.control.TableColumn;
     import javafx.scene.control.TableColumn.CellEditEvent;
     import javafx.scene.control.TableView;
     import javafx.scene.control.cell.PropertyValueFactory;
     import javafx.scene.control.cell.TextFieldTableCell;
     import javafx.scene.layout.HBox;
     import javafx.scene.layout.VBox;
     import javafx.scene.text.Font;
     import javafx.stage.Stage;
     import javafx.util.converter.NumberStringConverter;

   /**
    *
    * @author Yunus
    */
public class ColumnBinding  extends Application{
   private TableView<Product> table = new TableView<Product>();
   private final ObservableList<Product> data = FXCollections.observableArrayList();
   final HBox hb = new HBox();

public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage primaryStage) throws Exception {
    Scene scene = new Scene(new Group());
    primaryStage.setTitle("Book Store Sample");
    primaryStage.setWidth(650);
    primaryStage.setHeight(550);

    final Label label = new Label("Testing");
    label.setFont(new Font("Arial", 20));

    table.setEditable(true);

    TableColumn priceCol = new TableColumn("Price");
    priceCol.setMinWidth(100);
    priceCol.setCellValueFactory(
            new PropertyValueFactory<Product, String>("price"));
    priceCol.setCellFactory(TextFieldTableCell.<Product, Number>forTableColumn(new NumberStringConverter()));
    priceCol.setOnEditCommit(
            new EventHandler<CellEditEvent<Product, Number>>() {
                @Override
                public void handle(CellEditEvent<Product, Number> t) {
                    ((Product) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setPrice(t.getNewValue().intValue());
                }
            }
    );

    TableColumn quantityCol = new TableColumn("Quantity");
    quantityCol.setMinWidth(200);
    quantityCol.setCellValueFactory(
            new PropertyValueFactory<Product, Number>("quantity"));
    quantityCol.setCellFactory(TextFieldTableCell.<Product, Number>forTableColumn(new NumberStringConverter()));
    quantityCol.setOnEditCommit(
            new EventHandler<CellEditEvent<Product, Number>>() {
                @Override
                public void handle(CellEditEvent<Product, Number> t) {
                    ((Product) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setQuantity(t.getNewValue().intValue());
                }
            }
    );

    TableColumn amount = new TableColumn("Amount");
    amount.setMinWidth(200);
    amount.setCellValueFactory(
            new PropertyValueFactory<Product, String>("amount"));

    data.addAll(new Product(10, 12, 120),
                new Product(20, 12, 240),
                new Product(30, 12, 360),
                new Product(40, 12, 480),
                new Product(50, 12, 600));
    table.setItems(data);
    table.getColumns().addAll(priceCol, quantityCol, amount);
    final VBox vbox = new VBox();
    vbox.setSpacing(5);
    vbox.setPadding(new Insets(10, 0, 0, 10));
    vbox.getChildren().addAll(label, table, hb);

    ((Group) scene.getRoot()).getChildren().addAll(vbox);
    primaryStage.setScene(scene);
    primaryStage.show();
}

public static class Product{
    Product(){}

    public Product(float quantity, float price, float amount) {
        this.quantity = quantity;
        this.price = price;
        this.amount = amount;
    }

    private float quantity;
    private float price;
    private float amount;

    public float getQuantity() {
        return quantity;
    }

    public void setQuantity(float quantity) {
        this.quantity = quantity;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public float getAmount() {
        return amount;
    }

    public void setAmount(float amount) {
        this.amount = amount;
    }


}
 }

挑战在于不使用属性字段更改 POJO 类(产品)

【问题讨论】:

  • “挑战不是用属性字段改变 POJO 类”。为什么?为什么要限制自己使用专门为您的目的而提供的 API?
  • 因为我猜我将不得不更改源代码中的许多其他地方,因为我使用没有参数的构造函数,并且属性值需要在构造函数上初始化
  • 您为什么需要更改其他内容?唯一的公共方法仍然存在,并且仍然具有完全相同的功能(这是 JavaFX 属性模式设计的重点)。
  • 可以使用建议我在 POJO 中需要更改的内容并仍然保持未参数化的构造
  • 做显而易见的事。我使用这种方法提供了一个答案。请注意,尽管您的类实际上没有任何意义,因为如果amount 依赖于quantityprice,则为amountsetAmount 方法设置构造函数参数没有任何意义。我删除了解决方案中的那些。

标签: javafx


【解决方案1】:

我只会在模型类中使用 JavaFX 属性。然后就可以在模型中通过绑定来建立关系了:

public static class Product{

    private final FloatProperty quantity  = new SimpleFloatProperty();
    private final FloatProperty price  = new SimpleFloatProperty();
    private final ReadOnlyFloatWrapper amount  = new ReadOnlyFloatWrapper();

    Product(){
        this(0f, 0f);
    }

    // if amount is supposed to depend on quantity and price, it makes
    // no sense at all to have a constructor taking parameters for all 
    // three values...
    public Product(float quantity, float price) {
        setQuantity(quantity);
        setPrice(price);
        this.amount.bind(this.quantity.multiply(this.price));
    }

    public float getQuantity() {
        return quantityProperty().get();
    }

    public void setQuantity(float quantity) {
        quantityProperty().set(quantity);
    }

    public FloatProperty quantityProperty() {
        return quantity ;
    }

    public float getPrice() {
        return priceProperty().get();
    }

    public void setPrice(float price) {
        priceProperty().set(price);
    }

    public FloatProperty priceProperty() {
        return price ;
    }

    public float getAmount() {
        return amountProperty.get();
    }

    // Again, it makes no sense at all to have this method
    // if amount depends on the other values
    // public void setAmount(float amount) {
    //     this.amount = amount;
    // }

    public ReadOnlyFloatProperty amountProperty() {
        return amount.getReadOnlyProperty();
    }

}

现在您的表格列很简单:

TableColumn<Product, Float> priceColumn = new TableColumn<>("Price");
priceColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty().asObject());

TableColumn<Product, Float> quantityColumn = new TableColumn<>("Quantity");
quantityColumn.setCellValueFactory(cellData -> cellData.getValue().quantityProperty().asObject());

TableColumn<Product, Float> amountColumn = new TableColumn<>("Amount");
amountColumn.setCellValueFactory(cellData -> cellData.getValue().amountProperty().asObject());

【讨论】:

  • 这解决了我的问题,但我想知道这段代码如何:this.amount.bind(this.quantity.multiply(this.price)); 移动到setCellValueFactory 进行绑定。
猜你喜欢
  • 2018-03-25
  • 2013-03-18
  • 2015-03-23
  • 1970-01-01
  • 1970-01-01
  • 2019-07-06
  • 2022-01-25
  • 2014-06-26
  • 1970-01-01
相关资源
最近更新 更多