# Darstellungs Problem mit ComboBox in JTable



## Gast (27. Sep 2007)

Hallo,

Ich benutze für meine Table einen eigenen Renderer und Editor um ComboBoxen in der Tabelle darstellen zu können.
Ich will eigentlich folgendes haben: Wenn die Zelle nicht angeklickt ist soll man die Combobox nicht sehen nur wenn man darauf klickt. Das aktuelle Problem ist das man zwar auf eine Zelle klicken kann und auch etwas aus der Box auswählen kann doch beim verlassen der Zelle ist die Auswahl weg und man hat wieder ein leeres Feld.
Hier mal der Code:

```
table.getColumnModel().getColumn(1).setCellEditor(new ComboBoxEditor());
table.getColumnModel().getColumn(1).setCellRenderer(new ComboBoxRenderer());

class ComboBoxRenderer extends DefaultTableCellRenderer
{
    public Component getTableCellRendererComponent(JTable table,final Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    {
        return this;
    }

}

class ComboBoxEditor extends JComboBox implements TableCellEditor
{
    protected JComponent editorComponent = null;
    private Vector listeners = new Vector();
    protected EventListenerList listenerList = new EventListenerList();
    protected transient ChangeEvent changeEvent = null;
    
    public ComboBoxEditor()
    {
        super(new Object[] {"","Eins","Zwei","Drei"});
    }
    
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 
    {
        return this;       
    }

    public Object getCellEditorValue() 
    {
        return editorComponent;
    }

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

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

    public boolean stopCellEditing() 
    {
        fireEditingStopped();
        return true;
    }

    public void cancelCellEditing() 
    {
       fireEditingCanceled(); 
    }

    public void addCellEditorListener(CellEditorListener l) 
    {
    }

    public void removeCellEditorListener(CellEditorListener l) 
    {
    }
   
    protected void fireEditingCanceled()
  {
    ChangeEvent e = new ChangeEvent(this);
    for(int i = 0,n = listeners.size();i<n;i++)
      ((CellEditorListener)listeners.get(i)).editingCanceled(e);
  }

  protected void fireEditingStopped()
  {
    ChangeEvent e = new ChangeEvent(this);
    for(int i = 0,n = listeners.size();i<n;i++)
      ((CellEditorListener)listeners.get(i)).editingStopped(e);
  }
        
}
```

Also irgendwas stimmt wohl am Renderer nicht, hab aber momentan nicht so den Plan an was es liegen könnte.
Also hab auch noch andere Sachen ausprobiert die aber alle massig Fehler mit sich brachten. Das oben funktioniert soweit auch, mal davon abgesehen das die Zellen immer leer bleiben ausser wenn man sie editiert.
Hab auch schon so was wie setText((String)value); über der return this; Zeile im Renderer versucht, hat aber null gebracht.


----------



## Gast (28. Sep 2007)

Also wenns irgendwelche Fragen geben sollte zum Problem, bitte stellen. Ich werd mich bemühen alles zu beantworten.


----------



## Beni (28. Sep 2007)

Wenn fertig editiert ist, ruft die JTable "getCellEditorValue" auf, und schreibt den Rückgabewert mit Hilfe von "setValueAt" in das TableModel.

:arrow: getCellEditorValue richtig implementierten. Hier sollte die Selektion der ComboBox zurückgegeben werden, nicht die ComboBox selbst.
:arrow: sicherstellen, dass die Methode setValueAt auch im Model implementiert ist.

Ein anderes Thema ist, dass dein ComboBoxRenderer *überhaupt garnichts macht*.

:arrow: Der Renderer soll das Argument "value" in "getTableCellRendererComponent" nicht einfach ignorieren.


----------



## André Uhres (28. Sep 2007)

http://www.java-forum.org/de/userfiles/user3690/TableComboboxes.java


----------



## Gast (29. Sep 2007)

Also muss getCellEditorValue folgendes zurückgeben
return this.getSelectedItem(); ?
Was müsste denn in die setValueAt Methode im TableModel reingeschrieben werden?
Brauch ich denn überhaupt einen eigenen Renderer wenn ich nur will das ein Label in der Zelle steht und nicht die ComboBox? (Also natürlich nur wenn man gerade nicht editiert)
Hab auch schon probiert den Value in getTableCellRendererComponent zurückzugeben mit :
return (Component) value;
aber dann kommt immer folgende Fehler Meldung dass er keinen String in Component casten kann.

zu André:
Das ist ja ein universelles Model in dem man dann nach belieben einsetzen kann was man benötigt. Kann man da Icons einsetzen wie sie hier benutzt werden
http://www.java-forum.org/de/topic56466_jtable-icons-db-speichern.html
Man benutzt ja für alle Komponenten den gleichen Renderer, was ist wenn man zb wie ich für die ComboBox oben machen will das sie nur sichtbar ist wenn man die Zelle editiert oder irgendwelche anderen Eigenschaften einer Kompononte ändern will die nicht so allgemein sind?
Mit meiner Methode oben würde ich die Renderer ja spaltenweise setzen und mit deinem Beispiel muss man ja für jede Zeile in der Tabelle die Methode getCombo aufrufen, die dann eine neue ComboBox erstellt. Wie ist das dann von der Performance her?


----------



## André Uhres (29. Sep 2007)

Gast hat gesagt.:
			
		

> ..zu André:
> Das ist ja ein universelles Model in dem man dann nach belieben einsetzen kann was man benötigt.
> Kann man da Icons einsetzen wie sie hier benutzt werden
> http://www.java-forum.org/de/topic56466_jtable-icons-db-speichern.html


Null Problemo: eine JTable kann mehrere Renderer haben 
(wenn man getCellRenderer und getCellEditor wie angegeben implementiert, 
dann sollte automatisch der richtige Renderer/Editor ausgewählt werden).



			
				Gast hat gesagt.:
			
		

> Man benutzt ja für alle Komponenten den gleichen Renderer,
> was ist wenn man zb wie ich für die ComboBox oben machen will
> das sie nur sichtbar ist wenn man die Zelle editiert
> oder irgendwelche anderen Eigenschaften einer Kompononte ändern will die nicht so allgemein sind?


Entweder wie ich es im Beispiel gemacht habe, oder z.B. für JComboBox.class einen eigenen Renderer schreiben:

```
table.setDefaultRenderer(JComboBox.class, new JComboboxRenderer());
```



			
				Gast hat gesagt.:
			
		

> Mit meiner Methode oben würde ich die Renderer ja spaltenweise setzen
> und mit deinem Beispiel muss man ja für jede Zeile in der Tabelle die Methode getCombo aufrufen,
> die dann eine neue ComboBox erstellt. Wie ist das dann von der Performance her?


Null Problemo für kleinere Sachen, wie mein Beispiel mit 1000 Boxen zeigt
(braucht selbstverständlich mehr Platz als deine Methode).


----------



## Beni (29. Sep 2007)

Gast hat gesagt.:
			
		

> Also muss getCellEditorValue folgendes zurückgeben
> return this.getSelectedItem(); ?


Ja



> Was müsste denn in die setValueAt Methode im TableModel reingeschrieben werden?


Kommt halt draufan wie du dein Model geschrieben hast. Aber pseudocodemässig wird es sowas sein:

```
Object[][] data = ... // Die Daten in deinem Model
data[row][column] = newValue; // neuer Wert speichern
```



> Brauch ich denn überhaupt einen eigenen Renderer wenn ich nur will das ein Label in der Zelle steht und nicht die ComboBox? (Also natürlich nur wenn man gerade nicht editiert)


Wenn du unformatierten Text anzeigen willst: dann brauchst du keinen eigenen Renderer.


----------



## André Uhres (29. Sep 2007)

Man kann auch die Defaultsachen nutzen:

```
package table;

/*
 * TableComboboxes2.java
 */
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;

public class TableComboboxes2 {

    public TableComboboxes2() {
        JTable table = new JTable();
        DefaultTableModel model = (DefaultTableModel) table.getModel();
        model.addColumn("A", new Object[]{"item1"});
        model.addColumn("B", new Object[]{"item2"});
        model.addRow(new Object[]{"item3", "item4"});
        String[] values = new String[]{"item1", "item2", "item3"};
        TableColumn col = table.getColumnModel().getColumn(0);
        col.setCellEditor(new MyComboBoxEditor(values));
        table.setRowHeight(20);
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(400, 300);
        f.setLocationRelativeTo(null);
        JPanel tableContainer = new JPanel(new BorderLayout());
        tableContainer.add(table.getTableHeader(), BorderLayout.NORTH);
        tableContainer.add(table);
        f.add(tableContainer);
        f.setVisible(true);
    }

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

    public class MyComboBoxEditor extends DefaultCellEditor {

        public MyComboBoxEditor(String[] items) {
            super(new JComboBox(items));
        }
    }
}
```


----------



## Gast (29. Sep 2007)

Also ich hab die Daten über einen Vector in das TableModel geschrieben. Hab folgendes versucht :


```
private Vector Data;
    
public OmdbTableModel(Vector RowData, Vector ColumnNames) 
    {
        super(RowData, ColumnNames);
        Data = RowData;
        
    }

    public void setValueAt(Object aValue, int row, int column) 
    {
        Vector store = (Vector)(Data.get(row));
        store.set(column, aValue);
        Data.set(row,store);      
    }
```

Das hat aber leider nicht funktioniert.
Müsste ich da ein Object Array für die Daten nehmen, oder geht das auch mit nem Vector?


----------



## André Uhres (29. Sep 2007)

Geht auch mit Vector.
Dies ist überflüssig:

```
Data.set(row,store);
```
und dies fehlt:

```
fireTableCellUpdated(row, column);
```
Falls du von DefaultTableModel ableitest, ist die ganze Methode überflüssig :wink:


----------



## Gast (29. Sep 2007)

Ja wenn ich einfach ein DefaultTableModel nehme mit
DefaultTableModel model = new DefaultTableModel(Vector1, Vector2);
dann hab ich aber genau das gleiche Problem das ich in den Zellen nichts sehen kann.


----------



## Gast (29. Sep 2007)

Achja vielleicht nochwas,
irgendwie scheint er für jede Zelle dieselbe ComboBox zu nehmen.
Das beudeutet wenn ich in Zelle 1 den 3. Wert in der Box auswähle dann in irgendeine andere Zelle klicke ist der 3. Wert schon ausgewählt. (oder wenn ich in der 5. Zelle wert 2 auswähle dann ist in allen anderen Zellen auch Wert 2 ausgewählt usw)


----------



## André Uhres (30. Sep 2007)

>dann hab ich aber genau das gleiche Problem das ich in den Zellen nichts sehen kann.
>irgendwie scheint er für jede Zelle dieselbe ComboBox zu nehmen.

Kann ich nicht bestätigen, bei mir funzt das wie ne Uhr :wink:

```
Vector<String> headerData = new Vector<String>();
        headerData.add("Title 1");
        headerData.add("Title 2");
        Vector<Vector> tableData = new Vector<Vector>();
        for (int i = 0; i < 50; i++) {
            Vector<Object> rowData = new Vector<Object>();
            rowData.add("combo item1");
            rowData.add("simple item");
            tableData.add(rowData);
        }
        model = new DefaultTableModel(tableData, headerData);
        table = new JTable(model);
        String[] comboValues = new String[]{"combo item1", "combo item2", "combo item3", "combo item4"};
        table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(new JComboBox(comboValues)));
```


----------



## Gast (30. Sep 2007)

oh ja haste Recht. Wundbar so funzt das ja schon mal, aber das Problem das der Wert vorausgewählt ist den man in der zuvor editierten Zelle selektiert hat, besteht weiterhin. Naja nicht so tragisch.
Aber dennoch, was stimmt denn an meinem Editor oben nicht das dieser nicht funktioniert, vielleicht brauch ich ihn ja doch nochmal falls ich an der Combobox noch irgendwelche extra Änderungen vornehmen will.


----------



## mylord (9. Okt 2007)

Aber ich habe dann bei diesem Beispiel das Problem, dass in jeder Zeile der Tabelle eine Combobox ist (ich möchte die aber  nur in einer Zeile haben) und dass jede Combobox die gleichen Werte zur Auswahl liefert. Wie kann ich das denn lösen?


----------



## André Uhres (9. Okt 2007)

mylord hat gesagt.:
			
		

> Aber ich habe dann bei diesem Beispiel das Problem, dass in jeder Zeile der Tabelle eine Combobox ist (ich möchte die aber  nur in einer Zeile haben) und dass jede Combobox die gleichen Werte zur Auswahl liefert. Wie kann ich das denn lösen?


Oben im 4. Beitrag ein Link auf TableComboboxes.java 
mit einer alternativen Lösung die für dich passen müsste :wink:


----------

