有一个订单的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);
你可以做以下工作。
创建一个 ObservableList
附带 extractor
映射到 costProperty()
,并将其作为该表的 items
列表。
tableView.setItems(FXCollections.observableArrayList(
order -> new Observable[] { order.costProperty() }));
这确保了如果有任何一个人,列表就会触发更新事件。costProperty
列表中的元素发生变化时的事件(除此之外,当元素从列表中添加或删除时,通常的事件会被触发,等等)。
创建一个 DoubleBinding
绑定到列表上,并计算总成本。
DoubleBinding totalCost = Bindings.createDoubleBinding(() -> {
double total = 0 ;
for (Order order : tableView.getItems()) {
total = total + order.getCost();
}
return total ;
}, tableView.getItems());
绑定标签的 textProperty()
的总成本。
totalCostLabel.textProperty().bind(totalCost.asString());
你可以提供一个 format
至 asString()
方法,如果你想要更多的控制它的显示方式。
下面是一个完整的例子,根据你的代码改编。
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();
}
}