0

As the title says, empty cells are being added to my table when I add something to the underlying list.

Main Class:

import javax.swing.SwingUtilities;

public class Main {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                MainFrame frame = new MainFrame();
            }
        });
    }
}

MainFrame class:

import java.awt.BorderLayout;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JTable;

public class MainFrame extends JFrame {
    private JTable table;
    private ArrayList<String> strings;
    
    public MainFrame() {
        setTitle("Stack Overflow");
        setSize(800, 800);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        setVisible(true);
        
        strings = new ArrayList<String>();
        table = new JTable(new TableModel(strings));
        
        add(table,BorderLayout.CENTER);
        
        for (int i = 0; i < 10; i++) {
            strings.add("data");
        }
    }
}

AbstractTableModel Class:

import java.util.List;

import javax.swing.table.AbstractTableModel;

public class TableModel extends AbstractTableModel {
    private String[] colNames = {"Col1","Col2"};
    
    private List<String> strings;
    
    public TableModel(List<String> strings) {
        this.strings = strings;
    }
    
    @Override
    public String getColumnName(int column) {
        return colNames[column];
    }

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

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

    @Override
    public String getValueAt(int rowIndex, int columnIndex) {
        if (rowIndex*2 + columnIndex >= strings.size()) return "";
        return strings.get(rowIndex*2 + columnIndex);
    }
}

Is there a better way of getting the items from my 1D array so that the table is populated from left to right, top to bottom (without the extra empty cells)?

Why does this problem happen anyway?

Result: Extra empty rows added.

Community
  • 1
  • 1
  • Well, your `getRowCount` is wrong, based on your needs it should be more like `strings.size() / 2`, but, I would use a `List>` instead, so the outer list are the rows and the inner list are the columns for a given row – MadProgrammer Mar 18 '20 at 21:29
  • I can't make any changes to how the strings are stored. A simple `List` is all I get. `strings.size() / 2` kind of works but strings appear in pairs whereas I need them to appear 1 by 1 as they are added – Stanislav Dimitri Mar 18 '20 at 21:46
  • In the real application, the list is updated dynamically using `fireTableDataChanged()` whenever something is added to the list. (I should have added this sorry) – Stanislav Dimitri Mar 18 '20 at 21:51
  • 1
    *"A simple List is all I get"* - Sure, but that's got nothing to do with how the `TableModel` can store and manage it – MadProgrammer Mar 18 '20 at 22:21
  • The TableModel would then update the ArrayList and then invoke either `fireTableRowsInserted(…)`, if you have an odd number of items, or `fireTableRowsUpdated(…), if you have an even number of items. – camickr Mar 18 '20 at 23:43

2 Answers2

1
strings.add("data"); 

You should be using something like:

strings.add("data" + i); 

so the value in each cell is different. This way you can tell if the data is being displayed properly.

The list is updated dynamically using fireTableDataChanged() whenever something is added to the list.

That is wrong. The fireTableDataChanged() method should only ever be invoked by a method inside the TableModel. Once the TableModel is created you forget about the ArrayList and invoke a method on the TableModel to update the ArrayList.

So you need to add a method like addItem(…) to your TableModel. The TableModel would then update the ArrayList and then invoke either fireTableRowsInserted(…), if you have an odd number of items, or fireTableRowsUpdated(…), if you have an even number of items.

Something like:

public void addItem(String item)
{
    strings.add( item );

    if (string.size() % 2 == 0)
        fireTableRowsUpdated(…);
    else
        fireTableRowsInserted(…);
}
camickr
  • 321,443
  • 19
  • 166
  • 288
1

The data you have and the way you model it are two different concerns, don't be afraid to seperate them to achieve your goals, for example:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.table.AbstractTableModel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTable table;
        private SequentialTableModel model;

        public TestPane() {
            setLayout(new BorderLayout());
            model = new SequentialTableModel();
            table = new JTable(model);
            add(new JScrollPane(table));

            Timer timer = new Timer(500, new ActionListener() {
                private int count = 0;
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.add("Data " + (++count));
                }
            });
            timer.start();
        }

    }

    public class SequentialTableModel extends AbstractTableModel {

        private String[] colNames = {"Col1", "Col2"};

        private List<List<String>> rows = new ArrayList<>(32);

        public SequentialTableModel() {
        }

        @Override
        public String getColumnName(int column) {
            return colNames[column];
        }

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

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

        @Override
        public String getValueAt(int rowIndex, int columnIndex) {
            List<String> values = rows.get(rowIndex);
            if (columnIndex >= values.size()) {
                return null;
            }
            return values.get(columnIndex);
        }

        public void add(String value) {
            if (rows.isEmpty()) {
                addNewRow(value);
                return;
            }

            List<String> lastRow = rows.get(rows.size() - 1);
            if (lastRow.size() < 2) {
                lastRow.add(value);
                fireTableCellUpdated(rows.size() - 1, lastRow.size() - 1);
            } else {
                addNewRow(value);
            }
        }

        protected void addNewRow(String value) {
            List<String> row = new ArrayList<>(2);
            row.add(value);
            rows.add(row);
            fireTableRowsInserted(rows.size() - 1, rows.size() - 1);
            return;
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366