当前位置: 首页 > 知识库问答 >
问题:

如何处理与RowHeader在JTable中的RowSorter同步?

万俟浩
2023-03-14

以下情况:我有一个带有RowHeader的J(X)表(作为guidline,我使用了Rob Camicks的一个很好的例子)。一切如期进行。

根据要求,我从服务器接收的数据已经包含一个表号,我必须在轮转器中显示,数据应该是可过滤的。所以我扩展了这个例子,并添加了一个过滤器。当我过滤视图时,我看到行号中有空白(例如:1, 3, 6,..),这是所需的效果。

为了能够根据我自己的tablerow对表格进行筛选和排序,我添加了一个TableRowSorter。我开始感到困惑。该示例对mainTable和rowHeaderTable使用相同的TableModel和SelectionModel:

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

这很好,因为我不必同步它们。但是关于TableRowSorter,我突然不确定,我是否也可以甚至必须使用相同的TableRowSorter-Instance,或者我是否必须为每个表创建一个TableRowSorter。首先,我添加了相同的两个表,因为这似乎是实际的,但后来我得到了IndexOutOfBand-Exceptions在许多情况下。经过一些挖掘,我发现这是因为TableRowSorter在每个TableModel事件中更新了两次,因为每个表(RowHeader和Main Table)都会通知TableRowSorter关于表的变化。

现在我不确定哪条路是正确的。我想到了以下解决方案:我应该添加第二个TableRowSorter(每个表一个)并同步这些,还是应该将TableModel包装在RowHeaderTable中,让它不触发任何事件?或者,也许我应该创建我自己的类型的RowHeaderTable,它根本不会通知排序器有关更改?

共有1个答案

毕浩渺
2023-03-14

下面是包装行分拣器的一个快速实现(注意:未经过正式测试!不过使用示例工作正常)。

  • 收到型号更改通知时不执行任何操作
  • 委派所有状态查询
  • 侦听包装的行分类器并传播其事件

客户有责任使其与主表中使用的行分拣机保持同步

使用示例(根据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);
}

说唱歌手:

/**
 * 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
    }

}
 类似资料:
  • 问题内容: 我正在使用Python 2.6和用于多线程的多处理模块。现在,我希望有一个同步的字典(我真正需要的唯一原子操作是值上的+ =运算符)。 我应该用multiprocessing.sharedctypes.synchronized()调用包装字典吗?还是另一种方式? 问题答案: 介绍 似乎有很多主席建议,没有可行的例子。这里列出的答案都没有建议使用多处理,这令人失望和不安。作为python

  • 对于登录页面自动化,用户需要输入用户id、安全答案和密码。不同的环境有不同的用户。例如,qa和dev环境的用户具有不同的用户id、安全答案和密码。那么在自动化测试中如何妥善处理用户信息呢?我们可以将所有的属性存储在属性文件中,还有其他更好的解决方案吗?

  • 在Spring集成中是否可以保持通道同步(发送消息后获得确认)但同时处理更多消息(并行处理)而无需使用线程创建自己的代码(即ExecutorService执行和提交工作人员)并等待它们?我想通过FTP上传文件,但同时上传更多文件,而无需在代码中创建自己的线程。我需要知道所有文件何时上传(这就是我希望它是同步的原因)。是否可以通过Spring集成配置,如果可以,如何?

  • 问题内容: 如何处理Java中的同时按键? 我正在尝试编写游戏,并且需要一次处理多个按键。 当我按住一个键(假设向前移动),然后按住另一个键(例如,向左转)时,将检测到新键,但不再检测到旧键。 问题答案: 一种方法是跟踪自己当前按下了哪些键。 当您收到keyPressed事件时,将新键添加到列表中;当您收到keyReleased事件时,请从列表中删除密钥。 然后,在游戏循环中,您可以根据按键列表中

  • 我用的是Laravel和Stripe。我的应用程序中有5个不同的订阅计划。每个计划都有自己的一组选项,如 基本计划-最大活动-20-最大电子邮件-100 专业计划-最大活动-40-最大电子邮件-200 等 如何在数据库中表示这些选项? 我使用Laravel的收银台,它很好地处理订阅表,在那里它存储订阅名称,条纹计划id等。 但我希望稍后当用户准备创建一个活动时,检查他是否可以这样做,也就是说,他没

  • 我正在开发一个仅支持iPhone的iOS 8应用程序。我想只支持iPhone 4S的纵向模式设备。 我有一个图形设计,它采用全屏内容。我使用自动布局来处理视图,并使其适用于所有屏幕。但是,我使用一个小资产来管理从iPhone4S工作的设计。当我在iPhone6S/6看到它时,内容非常小,大量额外的空间被浪费了。 当设备分辨率变大时,我想增加字体大小、图像大小。这个应用程序中有很多屏幕。 例如,我在

  • 我正在尝试实现同步调用: 我得到以下例外情况: (节点:22140)UnhandledPromiseRejectionWarning:错误:协议错误(Target.CreateTarget):目标已关闭。在Promise(C:\imageServer\node_modules\puppeteer\lib\connection.js:74:56)在new Promise()在connection.s

  • 问题内容: 我想要一个文本区域,可以处理按 Tab 键的情况。 在默认情况下,如果您按 Tab 键,则焦点将离开文本区域。但是,当用户想要在文本区域中输入 Tab 键时会怎样呢? 我可以捕捉到此事件并将焦点返回到文本区域并将标签添加到 当前 光标位置吗? 问题答案: