# CellEditor und CellRenderer für eigene Klasse



## mas (30. Nov 2007)

Hallo,

Ich habe folgendes Problem:

Ich habe eine JTable mit verschiedenen Objekten in den einzelnen Spalten. Nun möchte ich für eine eigene Klasse Record den CellRenderer und den CellEditor anpassen damit in der Zelle eine JCheckBox ist, deren Wert die Variable 'recordable' repräsentiert.

Die Klasse Record (vereinfacht):


```
public class Record implements{

  private boolean recordable;
  private boolean recorded;

  public Record(){
    this.recordable = true;
    this.recorded = true;
   }
}
```

In der Klasse wo ich die JTable kreiere, setze ich die Renderer und Editoren für die Klasse Record:


```
table.setDefaultRenderer(Record.class, new RecordCellRenderer(true));
table.setDefaultEditor(Record.class, new RecordCellEditor());
```

Der Editor sieht folgendermassen aus:


```
public class RecordCellEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
    Record currentRecord;
    JCheckBox checkBox;

    public RecordCellEditor() {
        super();
        checkBox = new JCheckBox();
        checkBox.addActionListener(this);
        checkBox.setBorderPainted(false);
    }

    public void actionPerformed(ActionEvent e) {
        if(currentRecord.isRecordable()){
            currentRecord.setRecordable(false);
            checkBox.setSelected (false);
        }
        else{
            currentRecord.setRecordable(true);
            checkBox.setSelected (true);
        }
    }

    public Object getCellEditorValue() {
        return currentRecord;
    }

    public Component getTableCellEditorComponent(JTable table,
                                                 Object value,
                                                 boolean isSelected,
                                                 int row,
                                                 int column) {
        currentRecord = (Record)value;
        if(currentRecord.isRecordable()){
            currentRecord.setRecordable(false);
            checkBox.setSelected (false);
        }
        else{
            currentRecord.setRecordable(true);
            checkBox.setSelected (true);
        }
        return checkBox;
    }
}
```

Und so der Renderer:


```
public class RecordCellRenderer extends JLabel implements TableCellRenderer {
    Border unselectedBorder = null;
    Border selectedBorder = null;
    JCheckBox checkBox;
    boolean isBordered = true;

    public RecordCellRenderer(boolean isBordered) {
        this.isBordered = isBordered;
        setOpaque(true); //MUST do this for background to show up.
    }

    public Component getTableCellRendererComponent(JTable table, Object record, boolean isSelected, boolean hasFocus, int row, int column) {
        Record newRecord = (Record)record;
        checkBox = new JCheckBox();
        checkBox.setSelected(newRecord.isRecordable());
        add(checkBox);
        return this;
    }
}
```

Den Effekt den ich habe ist Folgender. Wenn ich die Zelle anklicke erscheint die Checkbox und wechselt ihren Status (checked, unchecked). Sobald ich aber die Zelle wieder verlasse (Anderen Button wählen oder andere Zelle) verschwindet die Checkbox sofort wieder.

Hat jemand eine Idee? Was mache ich falsch? Ich muss gestehen, dass ich durch die Editor/Renderer-Geschichte noch nicht ganz durchblicke und deshalb komme ich mit der Frage auch zu euch...

Vielen Dank für eure Hilfe! ???


----------



## matzze2000 (30. Nov 2007)

Also ohne mich bisher mit deinem Quelltext auseinander gesetzt zu haben kann ich dir schonmal sagen, dass es wohl an dem Renderer liegt. Der ist nämlich für die Anzeige zuständig wenn die Zelle nicht editiert wird. Ich werde mal drüber gucken...


----------



## matzze2000 (30. Nov 2007)

Du solltest es im Renderer mal so probieren:


```
public class RecordCellRenderer extends JLabel implements TableCellRenderer { 
    Border unselectedBorder = null; 
    Border selectedBorder = null; 
    JCheckBox checkBox; 
    boolean isBordered = true; 

    public RecordCellRenderer(boolean isBordered) { 
        this.isBordered = isBordered;
        checkBox = new JCheckBox();
        setOpaque(true); //MUST do this for background to show up. 
    } 

    public Component getTableCellRendererComponent(JTable table, Object record, boolean isSelected, boolean hasFocus, int row, int column) { 
        checkBox.setSelected((Boolean) value); //holt sich den Wert den die Zelle hat aus dem Tablemodel
        return checkBox; 
    } 
}
```

Also erstmal brauchst du ein Tablemodell in dem du die Werte verwaltest die jede Zelle hat. Wie du es geschrieben hast legst du für jede Zelle ein neues Objekt an, auf das du dann aber nich wirklich zugreifen kannst. Sowas machst du im Tablemodell, nicht im CellRenderer. Am besten guckst du dir mal das Tutorial zur JTable an, das hat mir auch sehr geholfen und da is auch das ganze Zeug mit dem CelRenderer sehr gut erklärt (is glaub ich auch ein Beispiel mit CheckBoxes dabei!)

http://www.java-forum.org/de/viewtopic.php?t=5321


----------



## mas (30. Nov 2007)

Hi,

Danke für Deine Hilfe. Natürlich habe ich ein Tablemodel und ein ColumnModel für meine Tabelle, das speichern und lesen der Werte, respektive das befüllen der Tabelle funktionieren auch gut. Für die anderen Spalten nehme ich aber den DefaultCellRenderer was ja für String, Integer, Boolean, JComboBox und JButton auch gut funktioniert. Wie ich das ganze aber mit einem eigenen Renderer mache habe ich noch nicht ganz geblickt.

So wie ich das sehe, hast Du nur folgendes angepasst:


```
public Component getTableCellRendererComponent(JTable table, Object record, boolean isSelected, boolean hasFocus, int row, int column) {
        checkBox.setSelected((Boolean) value); //holt sich den Wert den die Zelle hat aus dem Tablemodel
        return checkBox;
    }
```

Das ändert nichts an der Funktionalität, leider aber auch nicht an der Darstellung. Nach wie vor wird die Checkbox nur bei Klick auf die zelle direkt getoggelt und angezeigt.

Was ich möchte, ist, dass mein CellRenderer sich gleich verhält wie der DefaultCellRenderer eines Boolean-Werts, wobei eben die Variable 'recordable' jene sein soll, die durch die Checkbox repräsentiert wird.

Das Tutorial sehe ich mir gerade mal an.


----------



## mas (4. Dez 2007)

Ich habe mein Problem, gelöst, danke für die Hilfe.

Anmerkung: Ich muss keinen eigenen Renderer für die Klasse machen, wenn ich das TableModel entsprechend gestalte. Da gebe ich in der Methode getColumnClass den entsprechenden Klassentyp an (Boolean.class) und setze beim zurücklesen (Methode setValueAt) die entsprechende Variable (setRecordable(value))

Auf jeden Fall Danke.


----------

