JTable, Spalten struktur ändern.

d0x

Grünschnabel
Hallo,
warum übernimmt meine JTable nachdem ich im Tablemodel die Captions (getCoumnlCount() gibt eine andere anzahl zurück) die neue struktur nicht?

Nach dem ändern rufe ich zudem jtable.revalidate() .repaint() auf.

Ich habe auch es auch schon mit jtable.fireProperty( "TableStructureChanged"); versucht.

Hat jemand eine Idee?

Ich habe das Problem in einen kurzen ausführbaren beispielcode gepackt:
Code:
import java.awt.ScrollPane;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelListener;


public class Starter extends JFrame{

   public static void main (String[] args)
   {
      new Starter();
   }
   
   private TableModel model = new TableModel();
   private JTable table = new JTable(model);
   
   public Starter() {
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setContentPane(new JScrollPane(table));
      pack();
      setVisible(true);
      
      // Jetzt kommt die änderung der Tabellenstruktur
      model.setBuchstaben(true);
      table.revalidate();
      table.repaint();   
      
   }
   
}

class TableModel implements javax.swing.table.TableModel
{
   private String[] buchstaben = { "A", "B", "C", "D" };
   private String[] zahlen = { "1", "2" };
   private String[] captions = zahlen;
   
   public void addTableModelListener(TableModelListener l) {}

   public Class<?> getColumnClass(int columnIndex) { return String.class; }

   public int getColumnCount() { return captions.length; }

   public String getColumnName(int columnIndex) { return captions[columnIndex]; }

   public int getRowCount() { return 5;   }

   public Object getValueAt(int rowIndex, int columnIndex) { return "Text"; }

   public boolean isCellEditable(int rowIndex, int columnIndex) { return false; }

   public void removeTableModelListener(TableModelListener l) {}

   public void setValueAt(Object aValue, int rowIndex, int columnIndex) {}
   
   /**
    * Ändert ggf. die Captions. (Dadurch wird auch getcolumnCount() beeinflusst.
    * @param isBuchstaben
    */
   public void setBuchstaben(boolean isBuchstaben)
   {
      captions = isBuchstaben ? buchstaben : zahlen;
   }
   
}
 
Ich würde dir empfehlen dein TableModel von Abstract oder DefaultTableModel erben zu lassen. Dann kannst du entweder die dort angeboteten Methoden zum Column-Header setzen verwenden oder machst danach ein fireTableStructureChanged.

Und poste nächstes Mal bitte ins richtige Forum. Habs mal verschoben :)
 
Ich nehme an dass TabelModel ein von Dir erstellte Klasse ist.
Es wäre nicht schlecht wesentlich Teile des Codes Deines Models zu sehen, um Dein problem besser erkennen zu können. Z.Z. kann ich da nur spekulieren.
Takidoso
 
@Takidoso: Einmal scrollen. Der code ist gepostet ;)

Oops, sorry... ja manchmal hilft es, wenn man den Scrollbalken bedienen kann, jedoch ist die dringende Voraussetzung dafür, dass man ihn auch sieht :D

Also für mich ist der Fall klar.
Die Mehtode die du aufrufst, sagt dem JTable nicht, dass was neues im Tablemodel passiert ist. Nun ist es so, dass Du zwar mit dem revalidate und dem repaint ähnliches vollführst... aber demnach gibt es da noch einen weiteren Grund warum es so nicht geht ...
Wenn ich mich recht entsinne ist hierfür das TableColumnModel zu beglücken.

schau Dir mal diesen Extract aus JTable an:
Java:
    /**
     *  Appends <code>aColumn</code> to the end of the array of columns held by
     *  this <code>JTable</code>'s column model.
     *  If the column name of <code>aColumn</code> is <code>null</code>,
     *  sets the column name of <code>aColumn</code> to the name
     *  returned by <code>getModel().getColumnName()</code>.
     *  <p>
     *  To add a column to this <code>JTable</code> to display the
     *  <code>modelColumn</code>'th column of data in the model with a
     *  given <code>width</code>, <code>cellRenderer</code>,
     *  and <code>cellEditor</code> you can use:
     *  <pre>
     *
     *      addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
     *
     *  </pre>
     *  [Any of the <code>TableColumn</code> constructors can be used
     *  instead of this one.]
     *  The model column number is stored inside the <code>TableColumn</code>
     *  and is used during rendering and editing to locate the appropriates
     *  data values in the model. The model column number does not change
     *  when columns are reordered in the view.
     *
     *  @param  aColumn         the <code>TableColumn</code> to be added
     *  @see    #removeColumn
     */
    public void addColumn(TableColumn aColumn) {
        if (aColumn.getHeaderValue() == null) {
	    int modelColumn = aColumn.getModelIndex();
	    String columnName = getModel().getColumnName(modelColumn);
            aColumn.setHeaderValue(columnName);
        }
        getColumnModel().addColumn(aColumn);
    }
Es sieht so aus, als ob man für Dein Vorhaben die headerValue der Column des TableColumnModels setzen muss. Der Name der Spalte im TableModel hingegen wird nur in der "Initialisierungsphase" des JTables verwendet, und auch nur dannwenn die headerValue nicht in der Column gesetzt ist.

viel Glück und Spaß

Takidoso
 
Zuletzt bearbeitet:
*brr* Nee das ist viel zu viel Aufstand. Wie gesagt, es reicht das Default Model zu verwenden und dann nen fireTableStructureChange zu verwenden. Der regelt dass mit der View dann schon selber.

Java:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class Starter extends JFrame {

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

	private TableModel model = new TableModel();
	private JTable table = new JTable(model);

	public Starter() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setContentPane(new JScrollPane(table));
		pack();
		setVisible(true);

		// Jetzt kommt die änderung der Tabellenstruktur
		model.setBuchstaben(true);
	}

}

class TableModel extends DefaultTableModel {
	private String[] buchstaben = { "A", "B", "C", "D" };
	private String[] zahlen = { "1", "2" };
	private String[] captions = zahlen;

	public Class<?> getColumnClass(int columnIndex) {
		return String.class;
	}

	public int getColumnCount() {
		if(captions != null){
			return captions.length;
		}
		return super.getColumnCount();
	}

	public String getColumnName(int columnIndex) {
		if(captions != null){
			return captions[columnIndex];
		}
		return super.getColumnName(columnIndex);
	}

	public int getRowCount() {
		return 5;
	}

	public Object getValueAt(int rowIndex, int columnIndex) {
		return "Text";
	}

	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return false;
	}

	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
	}

	/**
	 * Ändert ggf. die Captions. (Dadurch wird auch getcolumnCount()
	 * beeinflusst.
	 *
	 * @param isBuchstaben
	 */
	public void setBuchstaben(boolean isBuchstaben) {
		captions = isBuchstaben ? buchstaben : zahlen;
		fireTableStructureChanged();
	}

}
 
richtig, das ist der einfachste weg, da durch fireTableStructureChanged() das TableColumnModel auf den aktuellen Stand gehalten wird.

KLeiner Einblick in die JTableSource zeigt auch warum bzw auf welche Weise:
Java:
   /**
     * Creates default columns for the table from
     * the data model using the <code>getColumnCount</code> method
     * defined in the <code>TableModel</code> interface.
     * <p>
     * Clears any existing columns before creating the
     * new columns based on information from the model.
     *
     * @see     #getAutoCreateColumnsFromModel
     */
    public void createDefaultColumnsFromModel() {
        TableModel m = getModel();
        if (m != null) {
            // Remove any current columns
            TableColumnModel cm = getColumnModel();
            while (cm.getColumnCount() > 0) {
                cm.removeColumn(cm.getColumn(0));
	    }

            // Create new columns from the data model info
            for (int i = 0; i < m.getColumnCount(); i++) {
                TableColumn newColumn = new TableColumn(i);
                addColumn(newColumn);
            }
        }
    }

... // folgende Routine wird IMHO durch DefaultTableModel.fireTableStructureChanged(); angestoßen

   public void tableChanged(TableModelEvent e) {
        if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
            // The whole thing changed
            clearSelectionAndLeadAnchor();

            rowModel = null;

            if (getAutoCreateColumnsFromModel()) {
		// This will effect invalidation of the JTable and JTableHeader.
                createDefaultColumnsFromModel();
		return;
	    }

	    resizeAndRepaint();
            return;
        }
 
Zuletzt bearbeitet:
Zurück