如何将TableView中的TableColumn的总和绑定到外部Label textProperty()?

问题描述 投票:1回答:1

有一个订单的TableView,其中有一列用于表示订单成本。订单对象的成本属性可以在TableView内改变。也就是说,订单列的单元格有能力通过使用TextFieldTableCell来改变。另外,在TableView外面还有一个Label,它应该代表订单成本的总和。现在的问题是,我不知道如何将订单成本列的总和绑定到Label的文本属性()。

下面是一些代码来说明这个问题。

     class Order {
            private SimpleStringProperty name;
            private SimpleIntegerProperty cost;

            public String getName() {
                return this.name.get();
            }

            public void setName(String name) {
                this.name.set(name);
            }

            public SimpleStringProperty nameProperty() {
                return this.name;
            }

            public Integer getCost() {
                return this.cost.get();
            }

            public void setCost(Integer cost) {
                this.cost.set(cost);
            }

            public SimpleIntegerProperty costProperty() {
                return this.cost;
            }
        }

        TableView<Order> tableView = new TableView<>();

        TableColumn<Order, String> nameColumn = new TableColumn<>();
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());

        TableColumn<Order, String> costColumn = new TableColumn<>();
        costColumn.setCellValueFactory(new PropertyValueFactory<>("cost"));
        costColumn.setCellFactory(TextFieldTableCell.forTableColumn());

        tableView.getColumns().addAll(nameColumn, costColumn);

        Label totalCostLabel = new Label("Total cost should be updated in this label");

        VBox vBox = new VBox();
        vBox.getChildren().addAll(tableView, totalCostLabel);
java javafx binding
1个回答
2
投票

你可以做以下工作。

  1. 创建一个 ObservableList 附带 extractor 映射到 costProperty(),并将其作为该表的 items 列表。

    tableView.setItems(FXCollections.observableArrayList(
        order -> new Observable[] { order.costProperty() }));
    

    这确保了如果有任何一个人,列表就会触发更新事件。costProperty 列表中的元素发生变化时的事件(除此之外,当元素从列表中添加或删除时,通常的事件会被触发,等等)。

  2. 创建一个 DoubleBinding 绑定到列表上,并计算总成本。

    DoubleBinding totalCost = Bindings.createDoubleBinding(() -> {
        double total = 0 ;
        for (Order order : tableView.getItems()) {
            total = total + order.getCost();
        }
        return total ;
    }, tableView.getItems());
    
  3. 绑定标签的 textProperty() 的总成本。

    totalCostLabel.textProperty().bind(totalCost.asString());
    

你可以提供一个 formatasString() 方法,如果你想要更多的控制它的显示方式。

下面是一个完整的例子,根据你的代码改编。

import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.converter.IntegerStringConverter;


public class SummingTable extends Application {


    @Override
    public void start(Stage stage) {
        TableView<Order> tableView = new TableView<>();

        tableView.setItems(FXCollections.observableArrayList(
                order -> new Observable[] { order.costProperty() }));

        tableView.getItems().addAll(
                new Order("Order 1", 10),
                new Order("Order 2", 20));

        tableView.setEditable(true);


        TableColumn<Order, String> nameColumn = new TableColumn<>();
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());

        TableColumn<Order, Integer> costColumn = new TableColumn<>();
        costColumn.setCellValueFactory(cellData -> cellData.getValue().costProperty().asObject());
        costColumn.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));

        tableView.getColumns().addAll(nameColumn, costColumn);

        Label totalCostLabel = new Label("Total cost should be updated in this label");

        DoubleBinding totalCost = Bindings.createDoubleBinding(() -> {
            double total = 0 ;
            for (Order order : tableView.getItems()) {
                total = total + order.getCost();
            }
            return total ;
        }, tableView.getItems());

        totalCostLabel.textProperty().bind(totalCost.asString());

        VBox vBox = new VBox();
        vBox.getChildren().addAll(tableView, totalCostLabel);

        Scene scene = new Scene(vBox);
        stage.setScene(scene);
        stage.show();

    }

    public class Order {
        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty cost = new SimpleIntegerProperty();

        public Order(String name, int cost) {
            setName(name);
            setCost(cost);
        }

        public String getName() {
            return this.name.get();
        }

        public void setName(String name) {
            this.name.set(name);
        }

        public StringProperty nameProperty() {
            return this.name;
        }

        public Integer getCost() {
            return this.cost.get();
        }

        public void setCost(Integer cost) {
            this.cost.set(cost);
        }

        public IntegerProperty costProperty() {
            return this.cost;
        }
    }

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

}
© www.soinside.com 2019 - 2024. All rights reserved.