JavaFX。如何在表格的底部做一​​个求和线(总行)?

如何在表的底部(TreeTableView – JavaFX或TableView)进行求和? (对不起我的英文)请写一个例子。

Picture(Totals)例如http://sofzh.miximages.com/java/uRLTZ.gif

在每一栏下面,我放了一个标签来显示SUM。但这对我没有好处。

一些FXML`

                                              

将标签绑定到列

 //TreeView_Begin @FXML private TreeTableView treeTableMainStat; @FXML private TreeTableColumn treeProgramNameCol; @FXML private TreeTableColumn treeLastDateCol; @FXML private TreeTableColumn treeLoginCol; @FXML private TreeTableColumn treeAffiliateIDCol; @FXML private TreeTableColumn treeRawClicksCol; @FXML private TreeTableColumn treeUniqueClicksCol; @FXML private TreeTableColumn treeSignupCounterCol; @FXML private TreeTableColumn treeSignupMoneyCol; @FXML private TreeTableColumn treeRebillCounterCol; @FXML private TreeTableColumn treeRebillMoneyCol; @FXML private TreeTableColumn treeRefundChargebackCounterCol; @FXML private TreeTableColumn treeRefundChargebackMoneyCol; @FXML private TreeTableColumn treeTotalMoneyCol; //TreeView_End @FXML Label apNameLab = new Label(); @FXML Label lastDateLab = new Label(); @FXML Label loginLab = new Label(); @FXML Label affilIdLab = new Label(); @FXML Label rawLab = new Label(); @FXML Label uniqLab = new Label(); @FXML Label signCLab = new Label(); @FXML Label signMLab = new Label(); @FXML Label rebillCLab = new Label(); @FXML Label rebillMLab = new Label(); @FXML Label rChCountLab = new Label(); @FXML Label rChMonLab = new Label(); @FXML Label totalLab = new Label(); @FXML private void initialize() throws SQLException { final String pattern = "yyyy-MM-dd"; datePickerStart.setValue(LocalDate.now()); datePickerEnd.setValue(LocalDate.now()); allDownloadsProgressBar.setProgress(0); refreshingIndicator.setVisible(false); StringConverter stringConverter = new StringConverter() { DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern); @Override public String toString(LocalDate date) { if (date != null) { return dateFormatter.format(date); } else { return ""; } } @Override public LocalDate fromString(String string) { if (string != null && !string.isEmpty()) { return LocalDate.parse(string, dateFormatter); } else { return null; } } }; datePickerStart.setConverter(stringConverter); datePickerStart.setPromptText(pattern.toLowerCase()); datePickerEnd.setConverter(stringConverter); datePickerEnd.setPromptText(pattern.toLowerCase()); // устанавливаем тип и значение которое должно хранится в колонке //TreeView_begin treeProgramNameCol.setCellValueFactory(new TreeItemPropertyValueFactory("apName")); treeLastDateCol.setCellValueFactory(new TreeItemPropertyValueFactory("lastDate")); treeLoginCol.setCellValueFactory(new TreeItemPropertyValueFactory("login")); treeAffiliateIDCol.setCellValueFactory(new TreeItemPropertyValueFactory("affiliateID")); treeRawClicksCol.setCellValueFactory(new TreeItemPropertyValueFactory("raw")); treeUniqueClicksCol.setCellValueFactory(new TreeItemPropertyValueFactory("uniq")); treeSignupCounterCol.setCellValueFactory(new TreeItemPropertyValueFactory("signupCounter")); treeSignupMoneyCol.setCellValueFactory(new TreeItemPropertyValueFactory("signup")); treeRebillCounterCol.setCellValueFactory(new TreeItemPropertyValueFactory("rebillCounter")); treeRebillMoneyCol.setCellValueFactory(new TreeItemPropertyValueFactory("rebillMoney")); treeRefundChargebackCounterCol.setCellValueFactory(new TreeItemPropertyValueFactory("refundChargebackCounter")); treeRefundChargebackMoneyCol.setCellValueFactory(new TreeItemPropertyValueFactory("refundChargebackMoney")); treeTotalMoneyCol.setCellValueFactory(new TreeItemPropertyValueFactory("totalMoney")); // заполняем таблицу данными // Platform.runLater(new Runnable() { // @Override // public void run() { // // } // }); new Thread(new Runnable() { @Override public void run() { buildTreeOfStatsFromDB(); //Binding apNameLab.prefWidthProperty().bind(treeProgramNameCol.widthProperty().multiply(1)); lastDateLab.prefWidthProperty().bind(treeLastDateCol.widthProperty().multiply(1)); loginLab.prefWidthProperty().bind(treeLoginCol.widthProperty().multiply(1)); affilIdLab.prefWidthProperty().bind(treeAffiliateIDCol.widthProperty().multiply(1)); rawLab.prefWidthProperty().bind(treeRawClicksCol.widthProperty().multiply(1)); uniqLab.prefWidthProperty().bind(treeUniqueClicksCol.widthProperty().multiply(1)); signCLab.prefWidthProperty().bind(treeSignupCounterCol.widthProperty().multiply(1)); signMLab.prefWidthProperty().bind(treeSignupMoneyCol.widthProperty().multiply(1)); rebillCLab.prefWidthProperty().bind(treeRebillCounterCol.widthProperty().multiply(1)); rebillMLab.prefWidthProperty().bind(treeRebillMoneyCol.widthProperty().multiply(1)); rChCountLab.prefWidthProperty().bind(treeRefundChargebackCounterCol.widthProperty().multiply(1)); rChMonLab.prefWidthProperty().bind(treeRefundChargebackMoneyCol.widthProperty().multiply(1)); totalLab.prefWidthProperty().bind(treeTotalMoneyCol.widthProperty().multiply(1)); getSumLabel(); } }).start(); // buildTreeOfStatsFromDB(); // Enable arrow keys for delete AP treeTableMainStat.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler() { @Override public void handle(KeyEvent keyEvent) { if (keyEvent.getCode() == KeyCode.Y && keyEvent.isControlDown()) { handleDeleteAffiliateProgram(); keyEvent.consume(); } } }); } 

获取所有SUM

 private void getSumLabel() { long rawHitsSum = 0; long uniqHitsSum = 0; long signCountSum = 0; double signMoneySum = 0; long rebillCountSum = 0; double rebillMoneySum = 0; long rChCountSum = 0; double rChMoneySum = 0; double totalMoneySum = 0; ObservableList<TreeItem> allData = rootItem.getChildren(); for (TreeItem apDataFromDBTreeItem : allData) { rawHitsSum += apDataFromDBTreeItem.getValue().getRaw(); uniqHitsSum += apDataFromDBTreeItem.getValue().getUniq(); signCountSum += apDataFromDBTreeItem.getValue().getSignupCounter(); signMoneySum += apDataFromDBTreeItem.getValue().getSignup(); rebillCountSum += apDataFromDBTreeItem.getValue().getRebillCounter(); rebillMoneySum += apDataFromDBTreeItem.getValue().getRebillMoney(); rChCountSum += apDataFromDBTreeItem.getValue().getRefundChargebackCounter(); rChMoneySum += apDataFromDBTreeItem.getValue().getRefundChargebackMoney(); totalMoneySum += apDataFromDBTreeItem.getValue().getTotalMoney(); } final long finalRawHitsSum = rawHitsSum; final long finalUniqHitsSum = uniqHitsSum; final long finalSignCountSum = signCountSum; final long finalSignCountSum1 = signCountSum; final long finalRebillCountSum = rebillCountSum; final double finalRebillMoneySum = rebillMoneySum; final long finalRChCountSum = rChCountSum; final double finalRChMoneySum = rChMoneySum; final double finalTotalMoneySum = totalMoneySum; Platform.runLater(new Runnable() { @Override public void run() { rawLab.setText(String.valueOf(finalRawHitsSum)); uniqLab.setText(String.valueOf(finalUniqHitsSum)); signCLab.setText(String.valueOf(finalSignCountSum1)); signMLab.setText(String.valueOf(finalSignCountSum)); rebillCLab.setText(String.valueOf(finalRebillCountSum)); rebillMLab.setText(String.valueOf(finalRebillMoneySum)); rChCountLab.setText(String.valueOf(finalRChCountSum)); rChMonLab.setText(String.valueOf(finalRChMoneySum)); totalLab.setText(String.valueOf(finalTotalMoneySum)); } }); System.out.println(rawHitsSum); } 

在JavaFX中,它就像在Swing中:最快的方法是创建第二个表。

您可以查看此要点上的摘要表示例代码 。

截图:

在此处输入图像描述

我会通过实现TransformationList来实现这一点, TransformationList在实际数据列表的末尾添加一个额外的元素。

在我的示例中,我有一个显示LineItemTableView (我的模型类),所以我的TransformationList实现如下所示:

 public class LineItemListWithTotal extends TransformationList { private final TotalLine totalLine ; protected LineItemListWithTotal( ObservableList source) { super(source); totalLine = new TotalLine(source); } @Override protected void sourceChanged(Change c) { // no need to modify change: // indexes generated by the source list will match indexes in this list fireChange(c); } @Override public int getSourceIndex(int index) { if (index < getSource().size()) { return index ; } return -1 ; } @Override public LineItem get(int index) { if (index < getSource().size()) { return getSource().get(index); } else if (index == getSource().size()) { return totalLine ; } else throw new ArrayIndexOutOfBoundsException(index); } @Override public int size() { return getSource().size() + 1 ; } } 

您可能会发现需要模型类的特殊子类才能使其轻松工作(在此示例中,我使用TotalLine LineItem子类TotalLine )。

使用提取器创建实际数据列表,该提取器检索在计算“总”行(即该行所依赖的属性)时需要观察的属性:

 ObservableList items = FXCollections.observableArrayList(item -> new Observable[] {item.totalProperty()}); 

然后使用它来创建TransformationList并将TransformationList传递给控件:

 table.setItems(new LineItemListWithTotal(items)); 

我管理实现总数的特殊子类中总行的观察者:

 public class TotalLine extends LineItem { private final ReadOnlyObjectWrapper total = new ReadOnlyObjectWrapper<>(); public TotalLine(ObservableList items) { super("Total", null, null); total.bind(Bindings.createObjectBinding(() -> items.stream().collect(Collectors.summingDouble(LineItem::getTotal)), items)); } @Override public ReadOnlyObjectProperty totalProperty() { return total ; } } 

这样,当在原始数据列表中添加或删除任何内容时,或者如果任何元素的提取器中的任何属性发生更改,则重新计算总行的总数。

完整的例子在这里

在此处输入图像描述

编辑:不是问题的答案。 我误解了这个问题。


我没有一个例子,但我可以解释一下这样做的方法。

  • 使用“TableView”
  • 每列应为“TableColumn”。 这个“TableColumn”应该与“ObsverbableList”相关联:

     YourColumn.setCellValueFactory( cellData ->CellData.getValue().yourObservableList.yourFloatProperty()); 
  • 列表中的数字应为“FloatProperty”。

  • 除了最后一个之外,在所有这些上设置一个监听器。 (你可以循环执行此操作)
    • 每个听众都应该调用你的求和函数。 此函数应计算列表的最后一个元素=列表中其他元素的总和
    • “TableView”会自动更新它。