遵循的情况:我有一个带有RowHeader的J(X)Table(作为指导,我使用了Rob Camicks的其中一位Examples)。所有工作都按预期进行。

根据要求,我从服务器接收的数据已经包含tablerownumber,我必须在行标题中显示该数据,并且该数据应该是可过滤的。因此,我扩展了该示例,并添加了一个过滤器。当我过滤视图时,我在行号中看到了空白(例如:1、3、6 ..),这是理想的效果。

为了能够按自己的表格行对表格进行过滤和排序,我添加了 TableRowSorter 。在这里,我开始感到困惑。该示例对mainTable和rowHeaderTable使用相同的TableModel和SelectionModel:

setModel( main.getModel() );
setSelectionModel( main.getSelectionModel() );

很好,因为我不必同步它们。但是对于TableRowSorter,我突然不确定,是否我也可以甚至必须使用相同的TableRowSorter -Instance,或者是否必须为每个表创建一个TableRowSorter。首先,我将相同的内容添加到两个表中,因为这似乎很实用,但是随后在很多情况下,我得到了IndexOutOfBound-Exceptions。经过一番挖掘后,我发现这是因为TableRowSorter在每个TableModelEvent上都被更新了两次,因为每个表(RowHeader和MainTable)都自行向TableRowSorter通知了有关表更改的信息。

现在我不确定哪种正确的方法是。我想到以下解决方案:我应该添加第二个TableRowSorter(每个表一个)并对其进行同步,还是应该将TableModel包装在RowHeaderTable中,并且不触发任何事件?或者,也许我应该创建自己的RowHeaderTable,它根本不通知Sorters有关更改的信息?

最佳答案

这是包装RowSorter的一种快速(请注意:未经正式测试!使用示例很好用)。

  • 在收到模型更改通知时不执行任何操作
  • 委托所有状态查询
  • 监听包装的rowSorter并传播其事件

  • 客户有责任使其与主表中使用的rowSorter保持同步

    使用示例(就SwingX测试基础结构和SwingX sortController / table而言):
    public void interactiveRowSorterWrapperSharedXTable() {
        final DefaultTableModel tableModel = new DefaultTableModel(list.getElementCount(), 2) {
    
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                return Integer.class;
            }
    
        };
        for (int i = 0; i < tableModel.getRowCount(); i++) {
            tableModel.setValueAt(i, i, 0);
            tableModel.setValueAt(tableModel.getRowCount() - i, i, 1);
        }
        final JXTable master = new JXTable(tableModel);
        final TableSortController<TableModel> rowSorter = (TableSortController<TableModel>) master.getRowSorter();
        master.removeColumn(master.getColumn(0));
        final JXTable rowHeader = new JXTable(master.getModel());
        rowHeader.setAutoCreateRowSorter(false);
        rowHeader.removeColumn(rowHeader.getColumn(1));
        rowHeader.setRowSorter(new RowSorterWrapper<TableModel>(rowSorter));
        rowHeader.setSelectionModel(master.getSelectionModel());
        // need to disable selection update on one of the table's
        // otherwise the selection is not kept in model coordinates
        rowHeader.setUpdateSelectionOnSort(false);
        JScrollPane scrollPane = new JScrollPane(master);
        scrollPane.setRowHeaderView(rowHeader);
        JXFrame frame = showInFrame(scrollPane, "xtables (wrapped sortController): shared model/selection");
        Action fireAllChanged = new AbstractAction("fireDataChanged") {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                tableModel.fireTableDataChanged();
            }
    
        };
        addAction(frame, fireAllChanged);
        Action removeFirst = new AbstractAction("remove firstM") {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                tableModel.removeRow(0);
    
            }
        };
        addAction(frame, removeFirst);
        Action removeLast = new AbstractAction("remove lastM") {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                tableModel.removeRow(tableModel.getRowCount() - 1);
    
            }
        };
        addAction(frame, removeLast);
        Action filter = new AbstractAction("toggle filter") {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                RowFilter filter = rowSorter.getRowFilter();
                if (filter == null) {
                    rowSorter.setRowFilter(RowFilter.regexFilter("^1", 1));
                } else {
                    rowSorter.setRowFilter(null);
                }
    
            }
        };
        addAction(frame, filter);
        addStatusMessage(frame, "row header example with RowSorterWrapper");
        show(frame);
    }
    

    RowSorterWrapper:
    /**
     * Wrapping RowSorter for usage (f.i.) in a rowHeader.
     *
     * Delegates all state queries,
     * does nothing on receiving notification of model changes,
     * propagates rowSorterEvents from delegates.
     *
     * Beware: untested!
     *
     * @author Jeanette Winzenburg, Berlin
     */
    public class RowSorterWrapper<M> extends RowSorter<M> {
    
        private RowSorter<M> delegate;
        private RowSorterListener rowSorterListener;
    
        public RowSorterWrapper(RowSorter<M> delegate) {
            this.delegate = delegate;
            delegate.addRowSorterListener(getRowSorterListener());
        }
    
        /**
         * Creates and returns a RowSorterListener which re-fires received
         * events.
         *
         * @return
         */
        protected RowSorterListener getRowSorterListener() {
            if (rowSorterListener == null) {
                RowSorterListener listener = new RowSorterListener() {
    
                    @Override
                    public void sorterChanged(RowSorterEvent e) {
                        if (RowSorterEvent.Type.SORT_ORDER_CHANGED == e.getType()) {
                            fireSortOrderChanged();
                        } else if (RowSorterEvent.Type.SORTED == e.getType()) {
                            fireRowSorterChanged(null);                }
                    }
                };
                rowSorterListener = listener;
            }
            return rowSorterListener;
        }
    
    
        @Override
        public M getModel() {
            return delegate.getModel();
        }
    
        @Override
        public void toggleSortOrder(int column) {
            delegate.toggleSortOrder(column);
        }
    
        @Override
        public int convertRowIndexToModel(int index) {
            return delegate.convertRowIndexToModel(index);
        }
    
        @Override
        public int convertRowIndexToView(int index) {
            return delegate.convertRowIndexToView(index);
        }
    
        @Override
        public void setSortKeys(List keys) {
            delegate.setSortKeys(keys);
        }
    
        @Override
        public List getSortKeys() {
            return delegate.getSortKeys();
        }
    
        @Override
        public int getViewRowCount() {
            return delegate.getViewRowCount();
        }
    
        @Override
        public int getModelRowCount() {
            return delegate.getModelRowCount();
        }
    
        @Override
        public void modelStructureChanged() {
            // do nothing, all work done by delegate
        }
    
        @Override
        public void allRowsChanged() {
            // do nothing, all work done by delegate
        }
    
        @Override
        public void rowsInserted(int firstRow, int endRow) {
            // do nothing, all work done by delegate
        }
    
        @Override
        public void rowsDeleted(int firstRow, int endRow) {
            // do nothing, all work done by delegate
        }
    
        @Override
        public void rowsUpdated(int firstRow, int endRow) {
            // do nothing, all work done by delegate
        }
    
        @Override
        public void rowsUpdated(int firstRow, int endRow, int column) {
            // do nothing, all work done by delegate
        }
    
    }
    

    07-28 00:29