Editable Header

Hallo zusammen,

Ich möchte in meiner JTable die Column-Header als ComboBox haben. Da habe ich auch ein ganz tolles Beispiel gefunden:

http://www.java2s.com/Code/Java/Swing-Components/EditableHeaderTableExample2.htm

Jetzt funktioniert das alles ganz toll wenn ich eine Tabelle fester Größe habe. Meine JTable soll aber, sobald ich in der ComboBox im Header etwas auswähle eine neue Spalte erstellen, die selbst wieder eine ComboBox im Header hat. Ich dachte ich könnte es so realisieren:

public class CriteriaTable extends JTable implements ActionListener{
	
	private static final long serialVersionUID = 1L;
	
	CriteriaTableModel critModel;
	
	public CriteriaTable(){
		
		//Das TableModel setzen
		critModel = new CriteriaTableModel();
		setModel(critModel);
			
		putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
	    
		
		TableColumnModel colModel = this.getColumnModel();
		setTableHeader(new EditableHeader(colModel));
		
		
		ComboCrit combo = new ComboCrit();
		combo.addActionListener(this);
	    
	    EditableHeaderTableColumn col = (EditableHeaderTableColumn) getColumnModel().getColumn(0);
	    col.setHeaderValue(combo.getItemAt(0));
	    col.setHeaderRenderer(combo);
	    col.setHeaderEditor(new DefaultCellEditor(combo));
	    
	    
	    

	}

.
.
.

@Override
	public void actionPerformed(ActionEvent ae) {
		System.out.println("Wieso?");
		
		//ComboCrit = ComboRenderer
		ComboCrit combo = new ComboCrit();		
		critModel.addCrit(combo);
		
		TableColumnModel colModel = this.getColumnModel();
		setTableHeader(new EditableHeader(colModel));
	    
	    EditableHeaderTableColumn col = (EditableHeaderTableColumn) getColumnModel().getColumn(getColumnCount()-1);
	    col.setHeaderValue(combo.getItemAt(0));
	    
	    /*
	     * Wenn ich den Renderer hier setze dann erzeugt mir das
	     * Programm unendlich viele Spalten.
	     * Wenn ich ihn weglasse dann werden die Boxen nicht/falsch angezeigt
	     */
	    col.setHeaderRenderer(combo);
	    col.setHeaderEditor(new DefaultCellEditor(combo));
	    
	    combo.addActionListener(this);
		System.out.println(getColumnCount()-1);
	}
}

Leider funktioniert das so nicht. Aus irgendeinem Grund wird der ActionListener beim ersten Initialisieren getriggert. Zuerst hatte ich einen ItemChangeListener drin, aber da der zweimal triggert wenn ich ein Item auswähle habe ich mich doch wieder für den ActionListener entschieden. Warum der aber gleich losgeht kann ich mir nicht denken.

Vielleicht hat ja jemand schonmal Erfahrung mit diesem EditableHeader gemacht und kann mir helfen :slight_smile:

Bei Auswahl eines Items in der ComboBox eines ColumnHeaders eine neue Spalte zu erzeugen erscheint mir bzgl. Bedienbarkeit nicht ganz logisch. Als Anwender hätte ich das Bedienelement zum Einfügen einer neuen Spalte eher außerhalb der Tabelle erwartet.

Unabhängig davon, warum erzeugst Du dann jedesmal ein neues TableColumnModel anstatt das existierende einfach nur um eine Spalte zu erweitern.

Das hab ich mir natürlich auch überlegt. Du meinst diese zwei Zeilen, oder?

TableColumnModel colModel = this.getColumnModel();
		setTableHeader(new EditableHeader(colModel));

Dann bekomme ich aber beim erzeugen der nächsten Box

Exception in thread "Thread-4" java.lang.ClassCastException: javax.swing.table.TableColumn cannot be cast to main.ressource.EditableHeaderTableColumn

Sorry, hatte mich verschaut. Es wird ja kein neues ColumnModel erzeugt, aber ich sehe auch nirgends wo das bestehende um eine neue Spalte erweitert wird.
Was mir noch unklar ist warum erstellst Du immer eine neue ComboCrit und was steckt hinter critModel?

Grundsätzlich ist es keine gute Idee einen Listener direkt an die ComboBox zu hängen und einen DefaultEditor zu verwenden, da der Listener bereits ausgelöst werden würde wenn die ComboBox als Editor angezeigt wird (der Editor setzt die ComboBox vor jeder anzeige neu).
Besser wäre es einen eigenen TableCellEditor zu schreiben, der diese ComboBox verwendet und darin auf das Beenden des CellEditors zu reagieren.

Erstmal Danke für die Hilfe,

Das mit dem TableCellEditor war ein super Tip. Allerdings bringt selbiger mir nicht viel, da der CellEditor nur Zellen in der Tabelle, nicht aber die Header editiert. Also hätte ich einen eigenen JTableHeader schreiben müssen und diesen in ein eigenes ColumnModel einbetten.

Das wäre aber zum einen viel Arbeit gewesen und zum anderen habe ich mich mit deinem ersten Vorschlag auseinandergesetzt. Es ist tatsächlich besser wenn ich das alles von einem Knopf außerhalb der Tabelle steuere (sonst habe ich wenn ich keine weiteren Spalten mehr will trotzdem eine zu viel :open_mouth: ). Warum kommen einem immer die tollen Ideen wenn man bereits viel Zeit und Kraft in eine andere gesteckt hat? :smiley:

Freut mich, dass Du Dir meinen Vorschlag zu Herzen genommen hast.

Grundsätzlich korrekt, dass ein CellEditor als Editor für Tabellenzellen genutzt wird. Aber Deine bzw. die von Dir genutzte Implementierung macht ja genau das. Es wird ein eigener JTableHeader implementiert, mit dem ColumnModel verknüpft und ein CellEditor und auch CellRenderer als Editor/Renderer für den Spaltentitel verwendet.