Spaltenbreite verändert sich mit dem Setzen des TableModels

Moin,

ich habe wiedermal ein Problem mit der JTable.

Wenn ich den Vector dataVector eines DefaultTableModels ersetze, ändert sich erwartungsgemäß der Inhalt, aber auch - nicht gewünscht - die von mir gesetzten Spaltenbreiten meiner JTable.
Kann man das irgendwie umgehen oder muss ich jedesmal die Spaltenbreiten neu setzen?

Kling ein wenig nach dem:
http://forum.byte-welt.net/threads/11206-GUI-JTable-mit-mehreren-TableModels-removeColumns?p=81934#post81934

bye
TT

Hi TT,

danke für deinen Beitrag.
Aber darum geht es nicht. Ich habe zwar in der Tat mehrere JTables, die aber in verschiedenen Tabs einer JTabbedPane liegen.
Aus einer Datei lade ich mir Daten, die in die JTable des gerade aktiven Tabs geladen werden sollen. Die Datei ändert sich laufend und ich möchte per Mausklick auf einen Button die Daten des aktuellen Stands aus der Datei laden, in ein TableModel umformen und damit die JTable auf den neusten Stand bringen. Da die Daten in einem Vector aus Vectoren liegen, ersetze ich den Original-Vector (dataVector) eines DefaultTableModels.
Und immer wenn ich das mache, ändern sich auch die Spaltenbreiten meiner JTable auf die Default-Werte…
Nur, warum? Und wie kann ich das umgehen?

was sind denn die “default werte”? alle Spalten gleich breit?

Wie hast Du denn die Spaltenbreiten gesetzt? setMaxWitdth()?
Schon setPreferedWidth() versucht?

bye
TT

Genau. Ich setze die Werte beim Instanziieren meiner JTable, in dem ich mir das TableColumnModel von der JTable geben lasse und die einzelnen Spalten manipuliere.
Sieht dann so aus:


        int width = 0;
        int minWidth = 0;
        for (int i = 0, c = columnModel.getColumnCount(); i < c; i++) {
            TableColumn column = columnModel.getColumn(i);

            switch (i) {
                case 0:
                case 1:
                    width = 110;
                    minWidth = 80;
                    break;
                case 2:
                    width = 110;
                    minWidth = 90;
                    break;
                case 3:
                case 4:
                case 5:
                case 6:
                    width = 60;
                    minWidth = 60;
                    break;
                case 7:
                    width = 80;
                    minWidth = 80;
                    break;
                case 8:
                    width = 120;
                    minWidth = 120;
                    break;
                case 9:
                    width = 80;
                    minWidth = 80;
                    break;
                case 10:
                    width = 400;
                    minWidth = 200;
                    break;
            }
            column.setPreferredWidth(width);
            column.setMinWidth(minWidth);
        }```

Keine Ahnung, ob man das so machen kann. Aber es funktioniert bei mir.

Hast Du mal versucht Dir das Column-Model zu merken und nach dem TableModel auch neu zu setzen?

bye
TT

Nein, noch nicht. Aber das wäre mein nächster Schritt gewesen.
Nur wollte ich zuvor noch fragen, ob ich was verkehrt gemacht habe, und/oder ob sich das beschriebene Verhalten erklären und umgehen lässt.

Ja, die JTable,… die mit Abstand komplizierteste Klasse in Swing… Für sowas wäre ein KSKB immer gut. Bis dahin (nicht zuletzt wegen der Uhrzeit) nur ein kurzer Hinweis, vielleicht mal mit http://docs.oracle.com/javase/7/docs/api/javax/swing/JTable.html#setAutoCreateColumnsFromModel(boolean) rumzuspielen. Ansonsten aber noch ein Codesnippet, das ich irgendwann mal gebastelt hatte, und was manchmal ganz praktisch sein kann:

    /**
     * Adjust the preferred widths of the columns of the given table
     * depending on the contents of the cells and headers.
     * 
     * @param table The table to adjust
     * @param maxWidth The maximum width a column may have
     */
    public static void adjustColumnWidths(JTable table, int maxWidth)
    {
        final int safety = 20;
        for (int c = 0; c < table.getColumnCount(); c++)
        {
            TableColumn column = table.getColumnModel().getColumn(c);

            TableCellRenderer headerRenderer = column.getHeaderRenderer();
            if (headerRenderer == null) {
                headerRenderer = table.getTableHeader().getDefaultRenderer();
            }
            Component headerComponent = 
                headerRenderer.getTableCellRendererComponent(
                    table, column.getHeaderValue(), false, false, 0, 0);
            int width = headerComponent.getPreferredSize().width;

            for (int r = 0; r < table.getRowCount(); r++) 
            {
                TableCellRenderer cellRenderer = table.getCellRenderer(r, c);
                Component cellComponent = 
                    cellRenderer.getTableCellRendererComponent(
                        table, table.getValueAt(r, c), 
                        false, false, r, c);
                Dimension d = cellComponent.getPreferredSize();
                //System.out.println("Preferred is "+d.width+" for "+cellComponent);
                width = Math.max(width, d.width);
            }
            column.setPreferredWidth(Math.min(maxWidth, width + safety));
        }
    }    

Ich dachte mir, dass irgendwann mal die Frage nach einem KSKB kommt und habe noch schnell eins zusammengekitzelt.

Eine GUI:


import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

/**
 *
 * @author l-ectron-x
 */
class MainPanel extends JPanel {

    private MyTableModel tModel;
    private TableColumnModel cModel;

    MainPanel() {
        super(new BorderLayout());
        add(createCenterPanel(), BorderLayout.CENTER);
        add(createButtonPanel(), BorderLayout.SOUTH);
    }

    private JPanel createCenterPanel() {
        JPanel panel = new JPanel(new GridLayout());

        tModel = new MyTableModel();
        tModel.setDataVector(createModel1());

        JTable table = new JTable(tModel);
        TableColumnModel cModel = table.getColumnModel();
        int width = 0;
        int minWidth = 0;
        for (int i = 0, c = cModel.getColumnCount(); i < c; i++) {
            TableColumn column = cModel.getColumn(i);

            switch (i) {
                case 0:
                case 1:
                    width = 100;
                    minWidth = 80;
                    break;
                case 2:
                case 3:
                case 4:
                    width = 60;
                    minWidth = 60;
                    break;
                case 5:
                case 6:
                    width = 100;
                    minWidth = 80;
                    break;
                case 7:
                    width = 300;
                    minWidth = 150;
                    break;
            }
            column.setPreferredWidth(width);
            column.setMinWidth(minWidth);
        }

        panel.add(new JScrollPane(table));

        return panel;
    }

    private JPanel createButtonPanel() {
        JPanel panel = new JPanel();

        JButton tModel1 = new JButton("Model 1");
        tModel1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                tModel.setDataVector(createModel1());
            }
        });

        JButton tModel2 = new JButton("Model 2");
        tModel2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                tModel.setDataVector(createModel2());
            }
        });

        panel.add(tModel1);
        panel.add(tModel2);
        return panel;
    }

    private Vector createModel1() {
        Vector rows = new Vector();
        for (int i = 0, j = tModel.getColumnCount(); i < j; i++) {
            Vector column = new Vector();
            for (int x = 0; x < 10; x++) {
                column.add(Math.multiplyExact(x+1, i+1));
            }
            rows.add(column);
        }
        return rows;
    }
    
    private Vector createModel2() {
        Vector rows = new Vector();
        for (int i = 0, j = tModel.getColumnCount(); i < j; i++) {
            Vector column = new Vector();
            for (int x = 0; x < 10; x++) {
                column.add(Math.pow(x+1, i+1));
            }
            rows.add(column);
        }
        return rows;
    }    

    class MyTableModel extends DefaultTableModel {

        private String[] columnNames = new String[]{
            "Spalte 1", "Spalte 2", "Spalte 3", "Spalte 4",
            "Spalte 5", "Spalte 6", "Spalte 7", "Spalte 8"
        };

        MyTableModel() {

        }

        @Override
        public String getColumnName(int column) {
            return columnNames[column];
        }

        @Override
        public int getColumnCount() {
            return columnNames.length;
        }

        public void setDataVector(Vector data) {
            super.setDataVector(data, null); //auch wenn ein ColumnModel gesetzt wird, werden Spaltenbreiten zurückgesetzt
        }
    }
}```

Zum Starten:
```package tabletest.columnwidth;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

/**
 *
 * @author l-ectron-x
 */
public class Main {
    
    private static void createAndShowGUI() {
        JFrame f = new JFrame("JTable-Test");
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        f.add(new MainPanel());
        f.setSize(900, 300);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}```

Deinen Beitrag lese ich noch gleich durch...

Ja, mit einem
table.setAutoCreateColumnsFromModel(false);
direkt nach dem Erstellen der JTable scheint - soweit ich das verstanden habe - das Ziel ja schon erreicht zu sein.

Irre! Es funktioniert tatsächlich! Danke @Marco13 . …wiedermal…