JTable es uno de los componentes más potentes y complejos de Swing. Usa el patrón MVC: el modelo (TableModel) gestiona los datos, y la vista (JTable) los renderiza.
JTable básico con DefaultTableModel
String[] columnas = {"Nombre", "Edad", "Ciudad"};
Object[][] datos = {
{"Ana García", 32, "Madrid"},
{"Carlos López", 28, "Barcelona"},
{"María Pérez", 45, "Sevilla"}
};
DefaultTableModel modelo = new DefaultTableModel(datos, columnas) {
@Override
public Class<?> getColumnClass(int col) {
return switch (col) {
case 1 -> Integer.class; // columna numérica
default -> String.class;
};
}
@Override
public boolean isCellEditable(int row, int col) { return false; } // solo lectura
};
JTable tabla = new JTable(modelo);
tabla.setRowHeight(28);
tabla.setFillsViewportHeight(true);
tabla.getTableHeader().setReorderingAllowed(false);
JScrollPane scroll = new JScrollPane(tabla); // siempre en JScrollPane
TableModel personalizado
record Producto(String nombre, double precio, boolean disponible) {}
public class ProductoTableModel extends AbstractTableModel {
private final List<Producto> productos;
private static final String[] COLS = {"Nombre", "Precio", "Disponible"};
public ProductoTableModel(List<Producto> productos) {
this.productos = new ArrayList<>(productos);
}
@Override public int getRowCount() { return productos.size(); }
@Override public int getColumnCount() { return COLS.length; }
@Override public String getColumnName(int col) { return COLS[col]; }
@Override
public Class<?> getColumnClass(int col) {
return switch (col) { case 1 -> Double.class; case 2 -> Boolean.class; default -> String.class; };
}
@Override
public Object getValueAt(int row, int col) {
Producto p = productos.get(row);
return switch (col) { case 0 -> p.nombre(); case 1 -> p.precio(); case 2 -> p.disponible(); default -> null; };
}
public void addProducto(Producto p) {
productos.add(p);
fireTableRowsInserted(productos.size()-1, productos.size()-1);
}
}
Ordenación y filtrado
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<>(modelo);
tabla.setRowSorter(sorter);
// Filtrar por texto
JTextField filtro = new JTextField();
filtro.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) { filtrar(); }
public void removeUpdate(DocumentEvent e) { filtrar(); }
public void changedUpdate(DocumentEvent e) { filtrar(); }
void filtrar() {
String texto = filtro.getText().trim();
sorter.setRowFilter(texto.isEmpty() ? null : RowFilter.regexFilter("(?i)" + texto));
}
});
TableCellRenderer personalizado
// Colorear filas según condición
tabla.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable t, Object val,
boolean selected, boolean focused, int row, int col) {
Component c = super.getTableCellRendererComponent(t, val, selected, focused, row, col);
if (!selected) {
double precio = (double) t.getValueAt(row, 1);
c.setBackground(precio > 100 ? new Color(255, 200, 200) : Color.WHITE);
}
return c;
}
});
