I'm trying to create a dynamic JTable in Java Swing where users can add/delete rows and columns as they want. Everything is good, except for deleting the column. I've been at this for hours now and I can't figure out how to completely erase a column and its values.
There are removeColumn(int)
methods in the classes, but they only hide the column from view. I've also searched and found
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
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 MutableTableModel model;
private JTable table;
public TestPane() {
setLayout(new BorderLayout());
JButton addColumnButton = new JButton("Add column");
JButton removeColumnButton = new JButton("Remove column");
addColumnButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
List<Object> rows = new ArrayList<>(100);
for (int row = 0; row < 100; row ) {
rows.add(randomString());
}
String columnName = JOptionPane.showInputDialog(TestPane.this, "Column name");
if (columnName == null || columnName.isBlank()) {
columnName = randomString();
}
int columnIndex = table.getSelectedColumn();
if (columnIndex < 0) {
model.addColumn(columnName, rows);
} else {
model.addColumn(columnName, rows, columnIndex 1);
}
}
});
removeColumnButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int columnIndex = table.getSelectedColumn();
if (columnIndex < 0) {
JOptionPane.showMessageDialog(TestPane.this, "Now column selected");
} else {
model.removeColumn(columnIndex);
}
}
});
JPanel actionPanels = new JPanel(new GridBagLayout());
actionPanels.add(addColumnButton);
actionPanels.add(removeColumnButton);
add(actionPanels, BorderLayout.SOUTH);
String[] columnNames = new String[]{"One", "Two", "Three", "Four", "Five"};
List<List<Object>> rows = new ArrayList<>(100);
for (int row = 0; row < 100; row ) {
List<Object> rowData = new ArrayList<>(columnNames.length);
for (int col = 0; col < columnNames.length; col ) {
rowData.add(randomString());
}
rows.add(rowData);
}
model = new MutableTableModel(Arrays.asList(columnNames), rows);
table = new JTable(model);
add(new JScrollPane(table));
}
private Random random = new Random();
protected String randomString() {
int leftLimit = 48; // numeral '0'
int rightLimit = 122; // letter 'z'
int targetStringLength = 10;
String generatedString = random.ints(leftLimit, rightLimit 1)
.filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
.limit(targetStringLength)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
return generatedString;
}
}
public class MutableTableModel extends AbstractTableModel {
private ArrayList<List<Object>> rows = new ArrayList<>(32);
private ArrayList<String> columnNames = new ArrayList<>(8);
public MutableTableModel() {
}
public MutableTableModel(List<String> columnNames, List<List<Object>> rows) {
this.columnNames = new ArrayList<>(columnNames);
this.rows = new ArrayList<>(rows);
}
public void addColumn(String name) {
addColumn(name, columnNames.size() - 1);
}
public void addColumn(String name, int columnIndex) {
columnIndex = Math.max(0, Math.min(columnIndex, columnNames.size()));
int rowCount = getRowCount();
List<Object> rows = new ArrayList<>(rowCount);
for (int row = 0; row < rowCount; row ) {
rows.add(null);
}
addColumn(name, rows, columnIndex);
}
public void addColumn(String name, List<Object> rows) {
addColumn(name, rows, columnNames.size());
}
public void addColumn(String name, List<Object> newRows, int columnIndex) {
columnIndex = Math.max(0, Math.min(columnIndex, columnNames.size()));
columnNames.add(columnIndex, name);
int rowCount = getRowCount();
for (int row = 0; row < rowCount; row ) {
List<Object> rowData = rows.get(row);
Object value = null;
if (row < newRows.size()) {
value = newRows.get(row);
}
rowData.add(columnIndex, value);
}
fireTableStructureChanged();
}
public void removeColumn(int columnIndex) {
if (columnIndex < 0 || columnIndex >= columnNames.size()) {
return;
}
int rowCount = getRowCount();
for (int row = 0; row < rowCount; row ) {
List<Object> rowData = rows.get(row);
rowData.remove(columnIndex);
}
columnNames.remove(columnIndex);
fireTableStructureChanged();
}
@Override
public int getRowCount() {
return rows.size();
}
@Override
public int getColumnCount() {
return columnNames.size();
}
@Override
public String getColumnName(int column) {
if (column >= columnNames.size()) {
return super.getColumnName(column);
}
return columnNames.get(column);
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return rows.get(rowIndex).get(columnIndex);
}
}
}