JTable - Spaltennamen im Model ändern ohne ColumnModel zu verändern

Licorice

Allrounder
Hallo Community,

ich möchte gerne den Spaltennamen einer JTable ändern ohne dabei das TableColumnModel der JTable zu manipulieren / komplett neu zu schreiben.


Was ich möchte:
Einzelne Spalten sollen in der Tabelle zur Laufzeit ausgeblendet oder umbenannt werden können.

Das Umbenennen realisiere ich, in dem ich auf das TableColumnModel zugreife und dort die betreffende Spalte entferne, damit nicht die Daten im TableModel gelöscht werden, sondern nur die Spalte ausgeblendet wird.
Das funktioniert auch.

Das Umbenennen der Spalten möchte ich hingegen im TableModel realisieren. (Da auf dieses Model später zugegriffen wird)
Ich habe ein eigenes Model, welches von AbstractTableModel ableitet und eine renameColumn-Methode implementiert. In dieser Methode wird ein fireTableStructureChanged() ausgelöst, das anscheinend dafür sorgt, dass auch das ColumnModel neu geschrieben wird.

Problem:
Wenn nun nach dem Umbenennen das ColumnModel neu geschrieben wird, sind alle vorher ausgeblendeten Spalten wieder sichtbar. Auch die über die GUI vorgenommene Sortierung ist natürlich weg.

Wie verhindere ich das?

Mein bisheriger Ansatz:
Ich lasse das fireTableStructureChanged() im TableModel weg und ändere den Spaltennamen zusätzlich im ColumnModel. Dann bleiben die ausgeblendeten Spalten weiterhin ausgeblendet, das Model wurde verändert und der geänderte Spaltenname ist in der GUI auch sichtbar. Allerdings finde ich diese Lösung nicht so elegant.

--
Ich hoffe mein Anliegen war verständlich. Code Beispiele gibt es gerne auf Anfrage.
 
Zuletzt bearbeitet:
Hier nochmal ein direkt ausführbares Beispiel.
Wie es aussieht komme ich nicht darum herum ein eigenes ColumnModel zu implementieren!?

Code:
//package example;
import javax.swing.table.DefaultTableModel;

/** @author http://www.tutorials.de/members/licorice.html */
public class TableColumnRenameDemo extends javax.swing.JFrame {

    /** Konstruktor */
    public TableColumnRenameDemo() {
        initComponents();
        
        // Fenster zentrieren
        setLocationRelativeTo(null);
        
        // Eine Spalte vorab verschieben
        jTable.getColumnModel().moveColumn(1, 2);
        
        // Eine andere Spalte voran *ausblenden*
        javax.swing.table.TableColumn column = jTable.getColumnModel().getColumn(3);
        jTable.getColumnModel().removeColumn(column);
    }

    /** Generated Code */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jButton_rename = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable = new javax.swing.JTable();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton_rename.setText("Spalte 2 umbennen");
        jButton_rename.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton_renameActionPerformed(evt);
            }
        });

        jTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {"a", "b", "c", "d"},
                {"aa", "bb", "cc", "dd"},
                {"aaa", "bbb", "ccc", "ddd"}
            },
            new String [] {
                "Spalte 1", "Spalte 2", "Spalte 3", "Spalte 4"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jScrollPane1.setViewportView(jTable);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jButton_rename)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 452, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jButton_rename)
                .addGap(18, 18, 18)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 315, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>

    private void jButton_renameActionPerformed(java.awt.event.ActionEvent evt) {
        /**
         * 
         * ---------------------------------------------------------------------
         * Hier soll Spalte 2 umbenannt werden.
         * Zur Demonstration hier mit einem statischen Feld.
         * (Mein Model besitzt dazu eine einfachere rename-Methode.)
         * 
         * Nachdem die Spalte umbenannt wurde, wird das ColumnModel geändert und
         * somit bereits ausgeblendete Spalten wieder eingeblendet, vom User
         * verschobene Spalten wieder in der ursprünglichen Reihenfolge
         * angezeigt. Das will ich verhindern! 
         * 
         * Wie!?
         * 
         * Komme ich nicht drum herum ein eigenes ColumnModel zu implementieren?
         * ---------------------------------------------------------------------
         * 
         */
        String[] newColumns = new String[]{ "Spalte 1", "Spalte 2 (umbenannt)",
                                            "Spalte 3", "Spalte 4" };
        DefaultTableModel dtm = (DefaultTableModel)jTable.getModel();
        dtm.setColumnIdentifiers(newColumns);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new TableColumnRenameDemo().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private javax.swing.JButton jButton_rename;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable;
    // End of variables declaration
}
 
Falls mal jemand über diesen Thread stolpert...

Ich habe jetzt herausgefunden, dass die JTable eine Eigenschaft AutoCreateColumnsFromModel besitzt. Ist diese auf true gesetzt, wird bei einem tableChange-Event das ColumnModel neu erstellt. Somit gehen dadurch darin alle Eigenschaften verloren.

Jetzt müsste man also nur diese Eigenschaft auf false setzen und eine eigene Methode implementieren, die das ColumnModel aktualisiert.
 

Neue Beiträge

Zurück