将已排序的JTable的modelRowIndex转换为viewRowIndex [英] Convert modelRowIndex to viewRowIndex for sorted JTable

查看:63
本文介绍了将已排序的JTable的modelRowIndex转换为viewRowIndex的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个可排序的JTable;添加一行后,我想知道其视图-索引.我尝试使用这样的表模型侦听器:

I have a sortable JTable; when a row is added I want to know its view-index. I tried using a table model listener like this:

@Override
public void tableChanged(TableModelEvent event)
{
    if (event.getType() == TableModelEvent.INSERT)
    {
        int modelRowIndex = event.getFirstRow();
        int viewRowIndex = table.convertRowIndexToView(modelRowIndex);
        System.out.println("viewRowIndex: " + viewRowIndex);
    }
}

如果表未排序,则此方法有效.不幸的是,如果对表进行排序,转换方法将导致由DefaultRowSorter.java:503引起的ArrayIndexOutOfBoundsException.

This works if the table is not sorted. Unfortunately, if the table is sorted the conversion-method results in an ArrayIndexOutOfBoundsException caused by DefaultRowSorter.java:503.

我猜这是因为表模型在通知行排序器之前先通知我的侦听器.有任何想法吗?谢谢!

I guess this happens because the table model notifies my listener before it notifies the row sorter. Any ideas? Thanks!

这是SSCCE:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;

public class RowIndexSSCCE extends JFrame
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new RowIndexSSCCE().setVisible(true);
            }
        });
    }

    private final JTable table;

    public RowIndexSSCCE()
    {
        JButton button = new JButton("Add");
        button.addActionListener(new ButtonListener());

        table = new JTable(new Model());
        table.setAutoCreateRowSorter(true);
        table.getModel().addTableModelListener(new ModelListener());

        JScrollPane scrollPane = new JScrollPane(table);
        JPanel panel = new JPanel();
        panel.add(button);
        panel.add(scrollPane);
        add(panel);
        pack();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private class ButtonListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent event)
        {
            ((Model) table.getModel()).addRow("asdf" + table.getRowCount());
        }
    }

    private class ModelListener implements TableModelListener
    {
        @Override
        public void tableChanged(TableModelEvent event)
        {
            if (event.getType() == TableModelEvent.INSERT)
            {
                int modelRowIndex = event.getFirstRow();
                int viewRowIndex = table.convertRowIndexToView(modelRowIndex);
                System.out.println("viewRowIndex: " + viewRowIndex);
            }
        }
    }

    private class Model extends AbstractTableModel
    {
        private final List<String> data = new ArrayList<String>();

        public void addRow(String string)
        {
            int oldSize = data.size();
            data.add(string);
            fireTableRowsInserted(oldSize, oldSize);
        }

        @Override
        public int getRowCount()
        {
            return data.size();
        }

        @Override
        public int getColumnCount()
        {
            return 1;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex)
        {
            return data.get(rowIndex);
        }
    }
}

我自己弄清楚了...使用SwingUtilities.invokeLater可以确保在更新行排序器之后完成行索引转换:

I just figured it out myself... using SwingUtilities.invokeLater ensures that the row index conversion is done after the row sorter has been updated:

@Override
public void tableChanged(final TableModelEvent event)
{
    if (event.getType() == TableModelEvent.INSERT)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                int modelRowIndex = event.getFirstRow();
                int viewRowIndex = table.convertRowIndexToView(modelRowIndex);
                System.out.println("viewRowIndex: " + viewRowIndex);
            }
        });
    }
}

推荐答案

是的,以错误的顺序通知了表模型侦听器.我想到的最简单的解决方案是自己实现侦听器.对于我来说,我从来没有通过扩展AbstractTableModel来实现表模型.我发现自己实现该功能更加透明.

You are right, the table model listeners are informed in the wrong order. The easiest solution that comes to my mind is to implement the listeners yourself. As for me, I never implement table models by extending the AbstractTableModel. I find it more transparent to implement the functionality myself.

private class Model extends AbstractTableModel {
    private final List<TableModelListener> listeners = new ArrayList<TableModelListener>();

    @Override
    public void addTableModelListener(TableModelListener l) {
        listeners.add(l);
    }

    @Override
    public void fireTableRowsInserted(int firstRow, int lastRow) {
        for (TableModelListener l : listeners) {
            l.tableChanged(new TableModelEvent(Model.this, firstRow,
                    lastRow, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
        }
    }
    ...
}

这篇关于将已排序的JTable的modelRowIndex转换为viewRowIndex的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆