【问题标题】:How to handle RowSorter-Synchronization in JTables with RowHeader?如何使用 RowHeader 处理 JTables 中的 RowSorter-Synchronization?
【发布时间】:2013-08-02 08:23:28
【问题描述】:

以下情况:我有一个带有 RowHeader 的 J(X)Table(作为指导,我使用了 Rob Camicks 的一个很棒的Examples)。一切都按预期工作。

根据要求,我从服务器收到的数据已经包含一个表格行号,我必须在行标题中显示它,并且数据应该是可过滤的。所以我扩展了这个例子,并添加了一个过滤器。当我过滤视图时,我看到行号中有间隙(例如: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 更改?

【问题讨论】:

  • 您是否尝试过为每个表使用单独的行排序器?我知道,你必须保持同步,但这可能会让你克服最初的障碍
  • @ymene please see my view of RowHeader(two JTables, two XxxModels, one listener for two notifiers),只有RowFilter,there you can to try apply your own view of RowSorterif without success 然后发帖,我觉得一定要根据你的SSCCE,还是等到(@camickr),顺便说一句无论如何(这个)可能是非常好的问题+1
  • 你能展示一个 SSCCE 吹的地方吗?我记得有过类似的讨论(但不是它的结果,找不到它)——还有一个非常简单的例子——使用共享的 RowSorter——似乎表现不错。
  • 不是解决方案,但找到了一个决定(测试失败,如您所见抛出 IOOBExceptions):无法共享 RowSorters。我的第一次尝试(虽然从未尝试过)是一个包装器 RowSorter,它对模型更改没有太多作用,而是委托给“真实”(又名:主表中的那个)
  • @kleopatra please where is the issue with RowSorters can't be shared or IndexOutOfBound-Exceptions on Primary JTable(contains based data) or secondary (aka: the one in the main table)意思是放在那里对两个 JTable 都有效的同步 ID(将从两个 JTable 视图中删除 culumn)

标签: java swing jtable tablerowsorter rowheader


【解决方案1】:

这是一个包装 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
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    相关资源
    最近更新 更多