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
在实际数据列表的末尾添加一个额外的元素。
在我的示例中,我有一个显示LineItem
的TableView
(我的模型类),所以我的TransformationList
实现如下所示:
public class LineItemListWithTotal extends TransformationList { private final TotalLine totalLine ; protected LineItemListWithTotal( ObservableList extends LineItem> source) { super(source); totalLine = new TotalLine(source); } @Override protected void sourceChanged(Change extends LineItem> 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 extends LineItem> 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”会自动更新它。