Wie lassen sich Swing-Komponenten in eine JTable einbetten?

Mit Hilfe von CellRenderern und CellEditoren lassen sich Swing-Komponenten in Java-Tabellen vom Typ JTable einbetten. Dabei regeln die Renderer die Erscheinung der unselektierten Zelle, während die Editoren die Erscheinung der selektierten Zellen handhaben.

Das Beispiel zeigt eine von JFrame abgeleitete Klasse, in deren Konstruktor eine Tabelle erzeugt und in einem JScrollPane auf die Oberfläche gesetzt wird. Der Inhalt der Tabelle wird in einem Tabellen-Model verwaltet, das zwei Arrays mit dem Inhalt und den Spaltentiteln übergeben bekommt. Über einen Button kann das Model gewechselt werden. Dies geschieht in der Methode reload(), die nachweist, dass zum Wechsel des Tabelleninhaltes einfach das Model mit dem geänderten Inhalt der Tabelle zugewiesen werden muss.
Den Spalten mit dem Titel Haute Cuisine bzw. Berufe bekommen jeweils einen CellRenderer und einen CellEditor übergeben. Die beiden Klassen sind für die Einbettung der Buttons in die angesprochene Spalte zuständig.

Die Klasse ButtonRenderer implementiert die Schnittstelle TableCellRenderer , die lediglich eine Methode getTableCellRendererComponent() deklariert. In dieser wird die beabsichtigte Erscheinung mit Hilfe der Parameter festgelegt. Zurückgegeben wird die Komponente, die als neues Element die Zelle füllen soll. Hier sollte darauf geachtet werden, dass entweder der Renderer selbst die gewünschte Komponente erweitert oder dass in ihr - wie hier - die gewählte Komponente als Instanzvariable deklariert wird, um sie nicht bei jedem Aufruf der Methode erneut zu generieren.
Soll ein Tooltip-Text gezeigt werden, so kann dieser hier der Komponente hinzugefügt werden.

Abb.: JTable mit Button-Spalte

Da der Renderer im Beispiel einen JButton verwendet, sollte diesem natürlich auch eine Funktionalität mitgegeben werden. Hier die Anmeldung beim ActionListener vorzunehmen, ist jedoch wenig sinnvoll und bleibt funktionslos, da die Aktivierung des Buttons in der selektierten Zelle erfolgt und somit im Editor platziert werden muss.

Die Klasse ButtonEditor erweitert die abstrakte Klasse AbstractCellEditor und implementiert TableCellEditor , in dessen Methode getTableCellEditorComponent() die Buttonaufschrift gesetzt wird. Wieder wird hier, ähnlich wie in getTableCellRendererComponent() , der Button zurück gegeben. Das Button-Objekt selbst wird im Konstruktor gebildet und beim ActionListener angemeldet.

Alle weiteren hier deklarierten Methoden regeln die Funktionalität des Editors:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventObject;

import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

public class TableMitButtonsClass extends JFrame {
    final JTable table;
    final DefaultTableModel model;

    String[][] data1 = { new String[] { "Hund", "Pizza", "Rudern" },
            new String[] { "Pferd", "Hamburger", "Gewichtheben" },
            new String[] { "Fadenwurm", "Foie gras", "Fingerhakeln" } };
    String[] colNames1 = new String[] { "Viecher", "Haute Cuisine",
            "Kraftmeierei" };

    String[][] data2 = { new String[] { "BMW", "Schreiner", "Frau" },
            new String[] { "Ducati", "Metzger", "Mann" },
            new String[] { "Megola", "Stellmacher", "Zwitter" } };
    String[] colNames2 = new String[] { "Mopeds", "Berufe", "Geschlechter" };

    public TableMitButtonsClass() {
        model = new DefaultTableModel();
        table = new JTable(model);
        reload();
        JScrollPane sPane = new JScrollPane(table);

        getContentPane().add(sPane, BorderLayout.CENTER);
        JButton butt = new JButton("Neues TableModel");
        butt.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                reload();
            }
        });
        getContentPane().add(butt, BorderLayout.SOUTH);
        this.setSize(600, 250);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    private void reload() {
        if (table.getColumnCount() == 0
                || table.getColumnName(1).equals("Berufe")) {
            model.setDataVector(data1, colNames1);
        } else {
            model.setDataVector(data2, colNames2);
        }
        table.getColumn(table.getColumnName(1)).setCellRenderer(
                new JButtonRenderer());
        table.getColumn(table.getColumnName(1)).setCellEditor(
                new JButtonEditor());
    }

    public static void main(String[] args) {
        new TableMitButtonsClass();
    }
}

class JButtonRenderer implements TableCellRenderer {

    JButton button = new JButton();

    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        table.setShowGrid(true);
        table.setGridColor(Color.LIGHT_GRAY);
        button.setText(value.toString());
        button.setToolTipText("Press " + value.toString());
        return button;
    }
}

class JButtonEditor extends AbstractCellEditor implements TableCellEditor {
    JButton button;
    String txt;

    public JButtonEditor() {
        super();
        button = new JButton();
        button.setOpaque(true);
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("Buttontext: " + button.getText());
            }
        });
    }

    public Object getCellEditorValue() {
        return null;
    }

    public boolean isCellEditable(EventObject anEvent) {
        return true;
    }

    public boolean shouldSelectCell(EventObject anEvent) {
        return false;
    }

    public boolean stopCellEditing() {
        return super.stopCellEditing();
    }

    public void cancelCellEditing() {
    }

    public void addCellEditorListener(CellEditorListener l) {
    }

    public void removeCellEditorListener(CellEditorListener l) {
    }

    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int row, int column) {
        txt = (value == null) ? "" : value.toString();
        button.setText(txt);
        return button;
    }
}