-2

I have JTable that's supposed to show data that's present in a model that's a custom class that extends DefaultTableModel. It is supposed to start as a blank table, and that works but unfortunately, whenever I try to add new row, it seems like model is not properly assigned to JTable (data doesn't show up on JTable at all).

Here's TableOrdersModel:

public class TableOrdersModel extends AbstractTableModel{
String tableHeaders[] = {"KATEGORIJA", "NAZIV", "CENA", "KOLIČINA"}; 
private LinkedList<Product> products;
private DefaultTableModel tableModel;

public TableOrdersModel(LinkedList<Product> products) {
    this.tableModel = new DefaultTableModel(0, tableHeaders.length);
    this.tableModel.setColumnIdentifiers(tableHeaders);
    this.products = products;
}

public void addRow(Product product) {
    products.add(product);
    tableModel.addRow(new Object[]{product.getCategory(), product.getName(), product.getPrice(), product.getQuantity()});
}

@Override 
public int getColumnCount() { 
    return tableHeaders.length; 
} 
@Override 
public String getColumnName(int index) { 
    return tableHeaders[index]; 
}
@Override
public void setValueAt(Object value, int row, int col) {
    fireTableCellUpdated(row, col);
}


@Override
public Object getValueAt(int rowIndex, int columnIndex) {

    Object value = null;
    Product product = products.get(rowIndex);
    switch (columnIndex) {
        case 0:
            value = product.getCategory();
            break;
        case 1:
            value = product.getName();
            break;
        case 2:
            value = product.getPrice();
            break;
        case 3:
            value = product.getQuantity();
            break;
        default:
            System.err.println("ERROR: Invalid column index.");
    }

    return value;

}
public Product getProductAt(int row) {
    return products.get(row);
}

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

}

And here's how I'm trying to assign it:

void displayOrdersForThisTable(Table selectedTable) {
    LinkedList<Product> products = selectedTable.getOrders();
    Iterator<Product> it = products.iterator();
    
    TableOrdersModel tableModel = (TableOrdersModel) table.getModel();
    
    while(it.hasNext()) {
        Product productIterator = it.next();
        tableModel.addRow(productIterator);
    }

Here is how JTable is initialized:

private JTable getTable() {
    if (table == null) {
        TableOrdersModel tableModel = new TableOrdersModel(new LinkedList<Product>());
        table = new JTable(tableModel) {
            public boolean editCellAt(int row, int column, java.util.EventObject e) {
                return false;
             }
        };
        table.setFont(new Font("Segoe UI", Font.PLAIN, 18));
    }
    return table;
}

Also, the reason why I'm using a custom model is because of this post (How to set a custom object in a JTable row) where I want to retrieve whole row as a Object (in this case an instance of class Product) instead of having to retrieve each cell from same row and peice it together into a Product.

Any help is greatly appericiated, thanks!

Neonify
  • 1
  • 2
  • 1
    `public int getRowCount() { return 0; }` uh oh!! Don't don't ***don't*** do this. Seriously. You're telling the model that it has no data, that it will *never* have data. – Hovercraft Full Of Eels Sep 27 '22 at 22:08
  • addRow(Product product) should not just add data, it should also fire a table data changed event. – Queeg Sep 27 '22 at 22:11
  • getRowCount() was giving me problems and that's why I changed it to 0 but completely overlooked to change it back. Thanks for that! I've edited my question to the most up to date code. Still, nothing happens when I try to add new row. – Neonify Sep 27 '22 at 22:39
  • It seems your question has changed quite a lot, rendering existing answers mostly useless. As of this writing, you have a TableModel defined *inside* your TableModel class. Don’t do that. Your `addRow` method needs to add to the source of data—namely, your `products` List. Then it needs to call `fireTableRowsUpdated` to let the JTable know the model has changed. Under no circumstances should a TableModel contain another TableModel. – VGR Sep 27 '22 at 23:39
  • I will delete those useless fields as it seems that it runs without it. Also, fireTableRowsUpdated helped me quiet a lot since only five mintues ago I've realized that table actually shows new data by having it resized! Thanks! – Neonify Sep 27 '22 at 23:51
  • *I want to retrieve whole row as a Object (in this case an instance of class Product) instead of having to retrieve each cell from same row and peice it together into a Product.* - See [Row Table Model](https://tips4java.wordpress.com/2008/11/21/row-table-model/) for an example of how the Product object can be stored and retrieved as a single object. – camickr Sep 28 '22 at 02:35

1 Answers1

1

Your model returns 0 always from its getRowCount() method, and a JTable made with this model will show no rows of data ever. Instead, if you're overriding DefaultTableModel, then best not to override this method. Let the super's object handle it.

Also, you're trying to use two data nuclei for the model, the super's internal Vector as well as your own linked list of Product, and that's not good. Either use the super's data or extend AbstractTableModel. If you do extend the abstract model, then yes, override getRowCount and return the count of rows in the data, here the size of your linked list.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 1
    getRowCount() should probably return products.size() – Queeg Sep 27 '22 at 22:12
  • @HiranChaudhuri, yes, and the OP should probably extend AbstractTableModel if they are going to use their own LinkedList. – Hovercraft Full Of Eels Sep 27 '22 at 22:12
  • I'm genuinely wondering, why is it better to have it inherit Abstract and not DefaultTableModel, since I think DefaultTableModel already inherits Abstract? I've deleted unnecessary code (not here) and I added method that fires update since I realized that my data gets updated ONLY when I resized window, so I thought I'd give that a try and it works. – Neonify Sep 27 '22 at 23:52
  • 1
    @Neonify `DefaultTableModel` has it's own internal data management structure, if you already have your data in a model of some kind (like a `LinkedList`), it's often better to use `AbstractTableModel`. `DefaultTableModel` also has a lot of additional functionality which you may not want to support and `AbstractTableModel` gives you a better starting point for customisation ie - you could add functionality which dealt only with the expected data of the model and did not support `Object` or `Vector` or arrays – MadProgrammer Sep 28 '22 at 01:19
  • 1
    @Neonify: it is *not* genuinely better to inherit from AbstractTableModel, but you can't have your cake and eat it too. You either use DefaultTableModel and accept its internal data nucleus or you use your own data nucleus and extend AbstractTableModel. That's your choice, but you can't have it both ways. – Hovercraft Full Of Eels Sep 28 '22 at 02:33