【问题标题】:How Can I Maintain User-Specified Table Row Sorting in a JTable after fireTableStructureChanged?fireTableStructureChanged 后如何在 JTable 中维护用户指定的表行排序?
【发布时间】:2014-07-29 13:26:55
【问题描述】:

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();

            }
        });
    }
}

【问题讨论】:

标签: java swing sorting jtable


【解决方案1】:

根据AbstractTableModel#fireTableStructureChanged()javadoc:

通知所有侦听器表的结构已更改。这 表中的列数,以及新的名称和类型 列可能与之前的状态不同。如果JTable 接收此事件并设置其 autoCreateColumnsFromModel 标志 丢弃它拥有的所有表列并重新分配默认列 按照它们在模型中出现的顺序。这与调用相同 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:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    • 2016-12-19
    • 1970-01-01
    • 2017-11-06
    • 2023-01-18
    • 1970-01-01
    • 2022-01-25
    相关资源
    最近更新 更多