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?
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;
}
}
}