-2

I am stuck on how to add table footer or column footer in JavaFX TableView. I am looking to add a TableView which will show purchased items with quantities and sells price in columns and total items count and total sum at the TableView footer. I looked at various resources, but could not find footer property associated with TableView. Any idea how to do it?

What I am looking to achieve

Model Class

    package javafxapplication8;
    
    public class TestModel {
    
        private String itemName = null;
    
        private int pricePerUnit = 0;
    
        private double quantity = 0.0;
    
        private double amount = 0.0;
    
        public TestModel() {
        }
    
        public TestModel(String argitemName, int argpricePerUnit, double argquantity, double argamount) {
            itemName = argitemName;
            pricePerUnit = argpricePerUnit;
            quantity = argquantity;
            amount = argamount;
    
        }
    
        public void setItemName(String argitemName) {
            itemName = argitemName;
        }
    
        public void setPricePerUnit(int argpricePerUnit) {
            pricePerUnit = argpricePerUnit;
        }
    
        public void setQuantity(double argquantity) {
            quantity = argquantity;
        }
    
        public void setAmount(double argamount) {
            amount = argamount;
        }
    
        public String getItemName() {
            return itemName;
        }
    
        public int getPricePerUnit() {
            return pricePerUnit;
        }
    
        public double getQuantity() {
            return quantity;
        }
    
        public double getAmount() {
            return amount;
        }
    
        @Override
        public String toString() {
            return this.itemName + "" + this.pricePerUnit + "" + this.quantity + "" + this.amount;
        }
    
    }

XML Code

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<AnchorPane id="AnchorPane" fx:id="anchor" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication8.TVCTestModel">
    <children>
        <VBox prefHeight="564.0" prefWidth="857.0">
            <children>
                <HBox alignment="BOTTOM_LEFT" prefHeight="100.0" prefWidth="1613.0" spacing="20.0" />            
                <BorderPane prefHeight="695.0" prefWidth="1618.0">
                    <center>
                        <VBox prefHeight="544.0" prefWidth="772.0">
                            <children>
                                <HBox prefHeight="65.0" prefWidth="1618.0" />
                                <HBox prefHeight="426.0" prefWidth="857.0">
                                    <children>
                                        <HBox alignment="CENTER" prefHeight="225.0" prefWidth="857.0">
                                            <children>                  
                                                <TableView fx:id="myTableView" prefHeight="419.0" prefWidth="816.0">
                                                    <columns>
                                                        <TableColumn fx:id="itemName" prefWidth="200.0" text="Item Name" />
                                                        <TableColumn fx:id="pricePerUnit" prefWidth="200.0" text="Price Per Unit" />
                                                        <TableColumn fx:id="quantity" prefWidth="200.0" text="Quantity" />
                                                        <TableColumn fx:id="amount" prefWidth="200.0" text="Amount" />
                                                    </columns>
                                                </TableView>
                                            </children>
                                        </HBox>
                                    </children>
                                </HBox>
                            </children>
                        </VBox>              
                    </center>
                    <bottom>

                    </bottom>
                </BorderPane>         
            </children>
        </VBox>
    </children>
</AnchorPane>

Controller Class

package javafxapplication8;

import java.net.URL;

import java.util.ResourceBundle;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;

import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;

public class TVCTestModel implements Initializable {

    @FXML
    private TableColumn<TestModel, String> itemName;

    @FXML
    private TableColumn<TestModel, Integer> pricePerUnit;

    @FXML
    private TableColumn<TestModel, Double> quantity;

    @FXML
    private TableColumn<TestModel, Double> amount;
    @FXML
    private TableView<TestModel> myTableView;
    public ObservableList<TestModel> objList = FXCollections.observableArrayList();
    @FXML
    private AnchorPane anchor;
    private static TestModel curTestModel;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        this.itemName.setCellValueFactory(new PropertyValueFactory<>("itemName"));
        this.pricePerUnit.setCellValueFactory(new PropertyValueFactory<>("pricePerUnit"));
        this.quantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
        this.amount.setCellValueFactory(new PropertyValueFactory<>("amount"));

        objList.add(new TestModel("Item 1", 10, 4, 400));
        objList.add(new TestModel("Item 2", 20, 5, 1000));
        objList.add(new TestModel("Item 3", 30, 6, 1800));
        objList.add(new TestModel("Item 4", 400, 7, 2800));
        System.out.println(objList.size());
        myTableView.setItems(objList);
    }

}

MainMethod Class

   package javafxapplication8;
    
    import java.io.IOException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class JavaFXApplication8 extends Application {
    
        @Override
        public void start(Stage primaryStage) {
    
            try {
                Parent root = FXMLLoader.load(getClass().getResource("TVCTestModel.fxml"));
                Scene scene = new Scene(root);
                primaryStage.setScene(scene);
                primaryStage.show();
    
            } catch (IOException ex) {
                Logger.getLogger(JavaFXApplication8.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
    }
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Asif Ali
  • 1
  • 2
  • 1
    Does this answer your question? [JavaFX .How to make a line of summation(total row) in the bottom of the table?](https://stackoverflow.com/questions/30506075/javafx-how-to-make-a-line-of-summationtotal-row-in-the-bottom-of-the-table) If this is not a duplicate, please [edit] your question to include a [mcve] that shows your revised approach. – trashgod Oct 16 '21 at 21:10
  • 1
    I see your edits but not your [mre]. – trashgod Oct 17 '21 at 16:29
  • Unless you need the functionality of a TableView, don’t use it, use a GridView instead. It will be much easier for you to create a footer row as part of the grid. If you must use a TableView then don’t try to put the total line in the table, instead make a separate HBox or GridView or another TableView with just one row and put that in a VBox after the table. – jewelsea Oct 18 '21 at 19:09
  • @jewelsea Yes, one can use your approach. But what about the table sorting and column resizing. In my opinion, both of these functions become difficult to achieve when we are using Gridview instead of TableView. – Asif Ali Oct 19 '21 at 15:30
  • @trashgod. It doesn't answer my question. I don't want to add another TableView for a footer. – Asif Ali Oct 19 '21 at 15:36
  • 2
    as you noted, headers/footers are not supported in fx tableView - your options: a) code it yourself (it's not rocket-science but requires a solid understanding of implementation details of table skin) b) use a third-party implementation (like GridView, or maybe TableView2 of ControlsFX c) live with an approximation to your requirement (like the referenced QAs, or maybe a single tableRow outside the table) d) hire a consultant to solve it for you ;) – kleopatra Oct 19 '21 at 15:50
  • 1
    As your table is not editable, I went with the simple approximation (c) [here](https://gist.github.com/trashgod/2fac616057dcdf1b4e444b5a45954673); if you edit your question, please refer to it; note that you should consider migrating to properties in your model class, as suggested [here](https://stackoverflow.com/a/68969223/230513). – trashgod Oct 20 '21 at 04:17
  • Still too broad (wtf is on a re-open quest ;) - don't see what's the problem, _exactly_? Your pic is just a plain table plus to labels under it, presumedly showing the sums you want. Just add them: best first change your data item - as @trashgod suggested - to expose its state as properties, then configure the observabvleList of the data items with an appropriate extractor, listen to change notification from the list, update sum/counter properties and bind the labels' text to them. – kleopatra Oct 20 '21 at 12:26
  • bying a _w_ to change _to_ to _two_ ;) – kleopatra Oct 20 '21 at 12:35
  • 1
    @kleopatra: Thank you, _extractor_ was the key ingredient. As an aside, the OP's update triggered a review; the history is in the [timeline](https://stackoverflow.com/posts/69594347/timeline). – trashgod Oct 20 '21 at 18:16
  • @trashgod after three days and much nudging, it sounds like your _approximate_ solution is actually _exactly_ what the OP is trying to achieve (in fact unrelated to what we know as table/column _footer_ ;) – kleopatra Oct 21 '21 at 10:44

1 Answers1

2

Your updated question was reopened, and the image provided suggests that, instead of a footer, you want two summary fields. As your table is not editable, a simple approximation is illustrated here—add two labels to the view, and iterate the table's model in the controller to establish the localized result:

image

TVCTestModel.fxml:

…
<bottom>
    <HBox alignment="CENTER_RIGHT" style="-fx-spacing: 5px;">
        <children>
            <Label fx:id="labelQ"/>
            <Label fx:id="labelA"/>
        </children>
    </HBox>
</bottom>
…

TVCTestModel.java

@FXML private Label labelQ;
@FXML private Label labelA;

@Override
public void initialize(URL url, ResourceBundle rb) {
    …
    double sumQuantity = 0;
    double sumAmout = 0;
    for (TestModel o : objList) {
        sumQuantity += o.getQuantity();
        sumAmout += o.getAmount();
    }
    labelQ.setText("Quantity: "
        + NumberFormat.getNumberInstance().format(sumQuantity));
    labelA.setText("Amount: "
       + NumberFormat.getCurrencyInstance().format(sumAmout));
}

If you later decide to make your table editable, as shown here, you should consider these modifications:

  • Migrate to observable properties in your model class, as shown here.

  • Create your ObservableList model with an extractor, as shown here and here; your extractor would include properties for quantity and amount; your controller could then update the summary field in a ListChangeListener.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045