Demo:
import java.awt.BorderLayout;
import java.awt.Color;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.table.AbstractTableModel;
public class ModernTableUsage2 extends JFrame {
@FunctionalInterface
public static interface FooterGenerator {
public String get(int columnIndex);
}
public static class BeanTableModelWithFooter<T> extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private List<T> data;
private FooterGenerator gen;
private List<Method> getter = new ArrayList<Method>();
private List<Method> setter = new ArrayList<Method>();
public BeanTableModelWithFooter(Class<T> clz, List<T> data, FooterGenerator gen, String... flds) {
this.data = data;
this.gen = gen;
for(String fld : flds) {
try {
getter.add(clz.getDeclaredMethod("get" + fld));
setter.add(clz.getDeclaredMethod("set" + fld, String.class));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
@Override
public int getRowCount() {
return data.size() + 1;
}
@Override
public int getColumnCount() {
return getter.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
try {
if(rowIndex < getRowCount() - 1) {
return getter.get(columnIndex).invoke(data.get(rowIndex));
} else {
return gen.get(columnIndex);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
try {
if(rowIndex < getRowCount() - 1) {
setter.get(columnIndex).invoke(data.get(rowIndex), aValue);
this.fireTableDataChanged();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
if(rowIndex < getRowCount() - 1) {
return true;
} else {
return false;
}
}
}
public static class Data {
private String name;
private BigDecimal amount;
public Data() {
this("", BigDecimal.ZERO);
}
public Data(String name, BigDecimal amount) {
this.name = name;
this.amount = amount;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public void setAmount(String amount) {
this.amount = new BigDecimal(amount);
}
@Override
public String toString() {
return String.format("(%s,%s)", name,amount);
}
}
private static final long serialVersionUID = 1L;
public ModernTableUsage2() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Moden table usage");
setLayout(new BorderLayout());
List<Data> data = new ArrayList<Data>(List.of(new Data("A", new BigDecimal("1.11")), new Data("BB", new BigDecimal("2.22")), new Data("CCC", new BigDecimal("3.33"))));
BeanTableModelWithFooter<Data> model = new BeanTableModelWithFooter<Data>(Data.class,
data,
ix -> { if(ix == 1) return data.stream().map(Data::getAmount).reduce(BigDecimal::add).get().toString(); else return "Total"; },
"Name", "Amount");
JTable table = new JTable(model);
table.setShowGrid(true);
table.setGridColor(Color.BLACK);
table.setBorder(new LineBorder(Color.BLACK, 2));
JPanel wrapper = new JPanel();
wrapper.setBorder(new EmptyBorder(10, 10, 10, 10));
wrapper.add(table);
add(wrapper, BorderLayout.CENTER);
JPanel buttons = new JPanel();
buttons.setBorder(new EmptyBorder(10, 10, 10, 10));
JButton test = new JButton("Test");
test.addActionListener(e -> JOptionPane.showMessageDialog(null, data.stream().map(Data::toString).collect(Collectors.joining("\r\n"))));
buttons.add(test);
JButton add = new JButton("Add row");
add.addActionListener(e -> { data.add(new Data()); model.fireTableDataChanged(); });
buttons.add(add);
add(buttons, BorderLayout.SOUTH);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new ModernTableUsage2();
f.setVisible(true);
}
});
}
}