0

I'm trying to display a single JTable, but I keep getting many new JTables everytime I insert a new product: https://i.stack.imgur.com/gyNsn.png

How can I display just one JTable and also make the column names visible?

Here is the method that creates the table:

 public JTable populate(Product p) {
        Vector<Vector<Object>> data = new Vector<Vector<Object>>();
        Vector<Object> row = new Vector<Object>();
        Vector<String> headers = new Vector<String>();
            headers.add("Product name");
            headers.add("Price");
            headers.add("In stock");
            row.add(p.getProductName());
            row.add(p.getPrice());
            row.add(p.getStock());
            data.add(row);
             productsTable = new JTable(data, headers);
      return (new JTable(data, headers));
    }

And here is a part from the GUI class:

 addProductBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
      Product product = new Product(insertProductName.getText(), Integer.parseInt(insertPrice.getText()), Integer.parseInt(insertStock.getText())); 
                    warehouse.addProduct(product); // by using a TreeSet
                   productsTable = warehouse.populate(product); // here I call the earlier defined method
                   warehouse.initFile(); // I wrote the productsTable content into a binary file, so that it can act like a database
        warehouse.readFile(); 
        warehouse.populate(product);
                    manageProductsPanel.add(productsTable);
});
Dave
  • 3
  • 3

1 Answers1

1

The populate method you posted creates a new JTable every time it is called. Given this is called every time the ActionListener is called, a new JTable will be added. You should consider creating your own TableModel - extend AbstractTableModel and override the necessary methods, returning the appropriate values for each row/column. A simple example is below, making some assumptions about project structure for demo's sake (for instance warehouse is an instance of a List):

public class MyTableModel extends AbstractTableModel{

    @Override
    public int getColumnCount() {
        return 3;
    }

    @Override
    public int getRowCount() {
        return warehouse.size();
    }

    @Override
    public Object getValueAt(int arg0, int arg1) {
        switch(arg1){
        case 0:
            return warehouse.get(arg0).getName();
        case 1:
            return warehouse.get(arg0).getPrice();
        default:
            return warehouse.get(arg0).isInStock();
        }
    }

    @Override
    public String getColumnName(int col){
        switch(col){
        case 0:
            return "Name";
        case 1:
            return "Price";
        default:
            return "In STock";
        }
    }

}

You can then create an instance of this class, and set the table model for the JTable. Every time the backed List is updated, you can update the Listeners of the TableModel

MyTableModel tableModel = new MyTableModel();
myTable.setMOdel(tableModel);
.......
//when an item is added to 
warehouse.add(item);
tableModel.fireTableDataChanged();

There are more demonstrations for how to customize a JTable in the Oracle Tutorials

copeg
  • 8,290
  • 19
  • 28
  • Thank you for the AbstractTableModel idea :) I have one question though. When you called methods like warehouse.get(arg0).getName(), you assumed I have a get(int) method in my Warehouse class? Because I don't have any, and the getName() method is in the Product class. What did you mean actually by writing the first part - warehouse.get(arg0)? The second part I get it. – Dave Apr 12 '15 at 21:05
  • Yes - hence my disclaimer 'making some assumptions'. One assumption is that warehouse is an instance of a List (or the class has some way of obtaining a Product at a particular index in the Warehouse). If the Products are store in another way then please elaborate. – copeg Apr 12 '15 at 21:09
  • The Warehouse class stores objects of type Product by using a TreeSet strucure: private TreeSet products = new TreeSet(); The class has 2 methods: addProduct(Product p) for adding a Product p into the TreeSet and removeProduct(Product p) for removing it from the TreeSet. The class also has a method that searches through the TreeSet for a specific product – Dave Apr 12 '15 at 21:17
  • TreeSet has no way to get an item at an index, so it's not really appropriate for a List like display (like a JTable). That being said, you can mimic the behavior by creating a List in parallel to the TreeSet (for instance, create an ArrayList and pass the TreeSet instance to the constructor). Every time a product is added or removed, you can add/remove the item from the List as well (to maintain ordering, it may be easier to just recreate the List or clear/addAll) – copeg Apr 12 '15 at 21:31
  • 2
    @copeg: A similar approach was suggested in this [answer](http://stackoverflow.com/a/29585019/230513) to the [duplicate](http://stackoverflow.com/q/29582246/230513). – trashgod Apr 12 '15 at 23:06
  • @copeg never to call models notifiers outside of models definitions e.g. tableModel.fireTableDataChanged();, must be member of the model, this isn't just the desingn issue, because it has many side effects – mKorbel Apr 13 '15 at 04:00