如何在fireTableStructureChanged之后在JTable中维护用户指定的表行排序?

时间:2014-07-29 13:26:56

标签: java swing sorting jtable

方法fireTableStructureChanged()从头开始重新绘制整个JTable。众所周知,用户指定的列宽和用户指定的行排序(当用户点击其中一个列的标题时)将​​丢失。

有没有办法存储自定义排序并在调用fireTableStructureChanged()后将其检索回来? 可能是方法convertRowIndexToModelconvertRowIndexToView可以帮助......

或者是否有另一种方法可以重新绘制整个表(在更改行数后)并保持排序?

以下是我添加/删除某些行的实验的简短示例:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;


public class Table extends JFrame {

    private static final long serialVersionUID = 1L;

    private JTable table;

    private String[][] tableData = {{"a", "5"},
                                    {"b", "4"},
                                    {"c", "9"},
                                    {"d", "2"},
                                    {"e", "1"},
                                    {"f", "7"},
                                    {"g", "3"},
                                    {"h", "8"},
                                    {"i", "6"}};

    private String[] columns = {"A", "B"};

    public Table() {
        MyTableModel mtm = new MyTableModel(tableData, columns);
        this.setLayout(new BorderLayout());
        table = new JTable(mtm);
        table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.getTableHeader().setReorderingAllowed(false);
        table.setCellSelectionEnabled(true);
        table.setAutoCreateRowSorter(true);                     

        JScrollPane scrollpane = new JScrollPane(table);
        scrollpane.setPreferredSize(new Dimension(600, 150));
        this.add(scrollpane);
        this.setLocation(300, 100);
        setVisible(true);
        pack();

        //Trying to add and remove some rows:
        mtm.addRow(new Object[]{"new 1", "new 2"});
        mtm.removeRow(2);
        mtm.removeRow(3);
        table.addNotify();
    }

    public class MyTableModel extends AbstractTableModel {

        private static final long serialVersionUID = 1L;

        private String[][] tableData;

        private String[] columns;

        public MyTableModel(String[][] tableData, String[] columns) {
            this.tableData = tableData;
            this.columns = columns;
        }

        public void addRow(Object newRow) {
             fireTableRowsInserted(2, 2);
        }

        public void removeRow(int row) {
            fireTableRowsDeleted(row, row);
        }

        public int getRowCount() {
            return tableData.length;
        }

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

        public String getColumnName(int column) {
            return columns[column];
        }

        public Object getValueAt(int row, int col) {
            return tableData[row][col];
        }

        public void setValueAt(Object value, int row, int col) {
            String oldValue = (String) tableData[row][col];
            if(oldValue.equals((String)value)) {
                return;
            }
            tableData[row][col] = value.toString();
        }

        public boolean isCellEditable(int row, int col) {
            return true;
        }
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                new Table();

            }
        });
    }
}

1 个答案:

答案 0 :(得分:2)

根据AbstractTableModel#fireTableStructureChanged() javadoc:

  

通知所有侦听器表的结构已更改。该   表中的列数,以及新的名称和类型   列可能与先前的状态不同。如果JTable   接收此事件并设置其autoCreumnsColumnsFromModel标志   丢弃它拥有的任何表列并重新分配默认列   按照它们出现在模型中的顺序。这与呼叫相同   setModel(TableModel)上的JTable

因此,如果你调用这个方法然后没有意义保持列宽(因为可能已经改变),也没有行排序或过滤(也可能有数据更改)。

  

还是有另一种方法可以重新绘制整个表(在更改行数后)并保持排序吗?

如果要在插入/删除行上更新表数据,则需要在表模型中提供此类方法,并在此类事件中通知TableModelListener

class MyTableModel extends AbstractTableModel {
    ...
    public void addRow(Object newRow) {
        // add row to underlying data structure here
         fireTableRowsInserted(rowIndex, rowIndex);
    }

    public void remove(Object rowToBeDeleted) {
        // remove row from the underlying data structure here
        fireTableRowsDeleted(rowIndex, rowIndex);
    }
    ...
}

请参阅AbstractTableModel API:

这样,列宽和行排序和过滤将保持不变。