Es läuft immer über Listener, weil JTable solche beim TableModel registriert.
Hier mal ein Beispiel in komprimierter Form (Zeilenumbrüche weggelassen, alle Klassen in einer -> normal separat):
[code=Java]
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
public class Test {
static class Customer {
private String id;
private String mail;
public Customer(String id, String mail) {
this.id = id;
this.mail = mail;
}
public Customer(Customer c) {
this.id = c.id;
this.mail = c.mail;
}
public Customer workingCopy() {
return new Customer(this);
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getMail() { return mail; }
public void setMail(String mail) { this.mail = mail; }
}
public class CustomersTableModel extends AbstractTableModel {
private static final String[] COLUMNS = {"ID", "Mail"};
private List<Customer> customers;
public CustomersTableModel(List<Customer> customers) { this.customers = customers; }
// TableModel-Implementierung
// lesend
@Override public int getRowCount() { return customers.size(); }
@Override public int getColumnCount() { return COLUMNS.length; }
@Override public String getColumnName(int col) { return COLUMNS[col]; }
@Override
public Object getValueAt(int row, int col) {
Customer customer = customers.get(row);
switch(col) {
case 0: return customer.getId();
case 1: return customer.getMail();
}
return null;
}
// ab hier das Thema ändern
@Override public boolean isCellEditable(int row, int col) { return true; }
@Override
public void setValueAt(Object value, int row, int col) {
Customer customer = customers.get(row);
String text = value == null ? "" : value.toString();
switch(col) {
case 0: customer.setId(text); break;
case 1: customer.setMail(text); break;
}
fireTableCellUpdated(row, col);
}
// von TableModel unabhängige Methoden,
// so dass die JTable davon mitbekommt
public void add(Customer customer) {
int row = getRowCount();
customers.add(customer);
fireTableRowsInserted(row, row);
}
public void remove(int row) {
if (row < 0 || row >= getRowCount()) return;
customers.remove(row);
fireTableRowsDeleted(row, row);
}
}
public void run() {
List<Customer> customers = new ArrayList<>();
CustomersTableModel model = new CustomersTableModel(customers);
JTable table = new JTable(model);
JButton add = new JButton(" + ");
add.addActionListener(e -> model.add(new Customer("", "")));
JButton remove = new JButton(" - ");
remove.addActionListener(e -> model.remove(table.getSelectedRow()));
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
buttons.add(add);
buttons.add(remove);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.add(buttons, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Test().run());
}
}[/code]
Hier dient die List direkt als "Repository" und die Änderungen gehen unmittelbar in die Customer-Objekte bzw. die List ein.