Swing y JFC: guía completa para interfaces gráficas en Java 21

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

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP