单击JTable Header时排序错误的列

时间:2016-01-16 17:30:32

标签: java swing sorting jtable jtableheader

我有RowSorterListener的以下代码。这样做的目的是对列进行排序而不影响任何其他列。

import javax.swing.event.RowSorterListener;
import javax.swing.event.RowSorterEvent;
import javax.swing.JTable;
import javax.swing.RowSorter.SortKey;
import java.util.List;
import java.util.Arrays;

public class UnrelateData implements RowSorterListener {
    JTable table;
    int columnSorted = -1;
    Object[][] dataStore;

    public UnrelateData(JTable table) {
        this.table = table;
    }

    @Override
    public void sorterChanged(RowSorterEvent e)
    {
        if(e.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
            List<SortKey> keys = e.getSource().getSortKeys();
            for (SortKey key : keys) {
                if (key.getColumn() == -1) {
                    columnSorted = -1;
                    break;
                } else {
                    columnSorted = key.getColumn();
                    break;
                }
            }
            dataStore = getData();
        }

        if(e.getType() == RowSorterEvent.Type.SORTED) {
            List<SortKey> keys = e.getSource().getSortKeys();
            for (SortKey key : keys) {
                if (key.getColumn() == -1) {
                    columnSorted = -1;
                    break;
                } else {
                    columnSorted = key.getColumn();
                    break;
                }
            }

            for(int i = 0; i < table.getColumnCount(); i++) {
                if(i != columnSorted && columnSorted != -1) {
                    for (int j = 0; j < table.getRowCount(); j++) {
                        table.setValueAt(dataStore[i][j], j, i);
                    }
                }
            }
        }
    }

    private Object[][] getData() {
        int columnCount = table.getColumnCount();
        int rowCount = table.getRowCount();
        Object[][] tempData = new Object[columnCount][rowCount];

        for(int i = 0; i < columnCount; i++) {
            for(int j = 0; j < rowCount; j++) {
                tempData[i][j] = table.getValueAt(j, i);
            }
        }

        return tempData;
    };
}

这很有效。但是,有一个重大故障。如果移动了一列,并且我尝试对列进行排序,则它不会对列进行正确排序。相反,它会错误地对列移动的原始位置中的列进行排序。

Column 2 and 3 switched

它应该看起来像(“第1列”和“第2列”保持未分类)

Column 2 and 3 switch properly

有人能够解释为什么会发生这种情况以及如何解决这个问题吗?

注意:我不想使用JTableHeader.reorderingAllowed(false)

修改

我在我的代码中添加了以下for循环并尝试了不同的变体,但它似乎无法正常工作

尝试1

if(e.getType() == RowSorterEvent.Type.SORTED) {
    int[] actualColumn = new int[table.getColumnCount()];
    for(int i = 0; i<table.getColumnCount(); i++){
        actualColumn[i] = table.convertColumnIndexToModel(i);
    }

    int[] actualRow = new int[table.getRowCount()];
    for(int i = 0; i<table.getRowCount(); i++){
        actualRow[i] = table.convertRowIndexToModel(i);
    }

    List<SortKey> keys = e.getSource().getSortKeys();
    for (SortKey key : keys) {
        if (key.getColumn() == -1) {
            columnSorted = -1;
            break;
        } else {
            columnSorted = key.getColumn();
            break;
        }
    }

    for(int i = 0; i < table.getColumnCount(); i++) {
        if(i != columnSorted && columnSorted != -1) {
            for (int j = 0; j < table.getRowCount(); j++) {
                table.setValueAt(dataStore[i][j], actualRow[j], actualColumn[i]);
            }
        }
    }
}

尝试2

private Object[][] getData() {
    int columnCount = table.getColumnCount();
    int rowCount = table.getRowCount();

    int[] actualColumn = new int[columnCount];
    for(int i = 0; i<table.getColumnCount(); i++){
        actualColumn[i] = table.convertColumnIndexToModel(i);
    }

    int[] actualRow = new int[rowCount];
    for(int i = 0; i<table.getRowCount(); i++){
        actualRow[i] = table.convertRowIndexToModel(i);
    }

    Object[][] tempData = new Object[columnCount][rowCount];

    for(int i = 0; i < columnCount; i++) {
        for(int j = 0; j < rowCount; j++) {
            tempData[i][j] = table.getValueAt(actualRow[j], actualColumn[i]);
        }
    }

    return tempData;
};

尝试3是尝试一个和两个放在一起

2 个答案:

答案 0 :(得分:3)

  • RowSorterListener中的代码是指定正确返回索引(来自RowSorterListener s事件)

  • 默认情况下,您永远不需要知道JTable视图中的排序,所有这些事件都是models events

  • 在您要跟踪TableColumnModelListener的情况下添加columnMoved,以编程方式排序的所有事件都在JTable视图中正确显示

  • 第一。没有列重新排序的attemtp,

enter image description here

Column NO. - 0 is sorted
Column NO. - 1 is sorted
Column NO. - 2 is sorted
Column NO. - 3 is sorted
Column NO. - 4 is sorted

... and so on
BUILD SUCCESSFUL (total time: 21 seconds)

  • 第二。尝试使用列重新排序(通过鼠标拖动)

enter image description here

Column NO. - 0 is sorted
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
Column NO. - 1 is sorted
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnSelectionChanged from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
Column NO. - 2 is sorted
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
columnMoved from ColumnModelListener
Column NO. - 3 is sorted
Column NO. - 4 is sorted
Column NO. - 0 is sorted
Column NO. - 1 is sorted
Column NO. - 2 is sorted
BUILD SUCCESSFUL (total time: 10 seconds)
  • 第三。如果Swing Timer未初始化且所有事件均由用户手工制作,则尝试相同的正确输出

  • 例如

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import javax.swing.*;
import javax.swing.RowSorter.SortKey;
import javax.swing.event.*;
import javax.swing.table.*;

public class SortTest1 {

    private JFrame frame = new JFrame(getClass().getSimpleName());

    private DefaultTableModel model = new DefaultTableModel(10, 5) {
        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };
    private JTable table = new JTable(model);
    private TableRowSorter<?> sorter;
    private static final Random rnd = new Random();
    private Timer timer;
    private int columnNo = 0;


    public SortTest1() {
        for (int row = model.getRowCount(); --row >= 0;) {
            int i = 20 + row % 20;
            model.setValueAt(row + " " + i, row, 0);
            model.setValueAt(i + row, row, 1);
            model.setValueAt(rnd.nextBoolean(), row, 2);
            model.setValueAt(rnd.nextDouble(), row, 3);
            model.setValueAt(row + " " + i * 1, row, 4);
        }
        table.setAutoCreateRowSorter(true);
        sorter = (TableRowSorter<?>) table.getRowSorter();
        sorter.setSortsOnUpdates(true);
        sorter.addRowSorterListener(new RowSorterListener() {

            @Override
            public void sorterChanged(RowSorterEvent rse) {
                if (rse.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
                    List<SortKey> keys = rse.getSource().getSortKeys();
                    for (SortKey key : keys) {
                        System.out.println("Column NO. - " + key.getColumn() + " is sorted");
                        if (key.getColumn() == 0) {
                            break;
                        } else {
                            break;
                        }
                    }
                }
            }
        });
        frame.add(new JScrollPane(table));
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
            // just handle columnMarginChanged to re-paint headings
            @Override
            public void columnMarginChanged(ChangeEvent e) {
                System.out.println("columnMarginChanged from ColumnModelListener");
            }

            @Override
            public void columnAdded(TableColumnModelEvent e) {
                System.out.println("columnAdded from ColumnModelListener");
            }

            @Override
            public void columnRemoved(TableColumnModelEvent e) {
                System.out.println("columnRemovedfrom ColumnModelListener");
            }

            @Override
            public void columnMoved(TableColumnModelEvent e) {
                System.out.println("columnMoved from ColumnModelListener");
            }

            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {
                System.out.println("columnSelectionChanged from ColumnModelListener");
            }
        });
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        timer = new javax.swing.Timer(1000, updateCol());
        timer.setRepeats(true);
        timer.start();
    }

    private Action updateCol() {
        return new AbstractAction("Sort JTable") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                if (columnNo > 4) {
                    columnNo = 0;
                    sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(columnNo, SortOrder.ASCENDING)));              
                } else {
                    sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(columnNo, SortOrder.ASCENDING)));
                    columnNo++;
                }
            }
        };
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            new SortTest1();
        });
    }
}

答案 1 :(得分:2)

从您的问题描述(未查看代码)您可能不会将从视图索引报告的索引转换为模型索引,反之亦然。

Cf JTable一般说明,引用相关部分:

  

同样,当使用RowSorter提供的排序和过滤功能时,基础TableModel不需要知道如何进行排序,而RowSorter将会处理它。使用JTable的基于行的方法与基础TableModel时,需要协调转换。所有JTables基于行的方法均以RowSorter表示,不一定与基础TableModel的方法相同。例如,选择始终以JTable表示,因此在使用RowSorter时,您需要使用convertRowIndexToViewconvertRowIndexToModel进行转换。 [...]

您需要注意,表上的侦听器将在视图索引中报告,而不是模型索引。如果您使用视图索引从模型中获取值,您将遇到您正在描述的问题。

要处理这些转换,JTable中存在以下方法:

解释JTable中与您的问题相关的模型与视图的小例子。表的模型包含数据。视图是屏幕上显示的内容。视图将其列映射到模型中的列。当列被拖动到视图中的不同位置时(即您在屏幕上看到的内容),您的模型不会更改(即数据容器中的数据不会更改)。会发生什么是从视图到模型的映射更改。

例如,您的数据模型中有三列A,B和C,您将屏幕上的第二列拖到第一个位置,以便屏幕上的顺序变为B,A,C。视图的作用是更改其映射以在第一个位置显示列B,在第二个位置显示A,在第三个位置显示C.因此,映射为view:1->model:A, view:2->model:B, view:3->model:C,拖动后变为view:1->model:B, view:2->model:A, view:3->model:C

现在回到我之前所说的话。当JTable上的任何侦听器报告索引(行,列)时,它会使用视图索引进行报告。现在,如果要查看模型中这些索引的值,首先需要使用我之前突出显示的方法将这些视图索引转换为模型索引。

因此,您始终需要了解您正在接收哪些索引以及您打算如何处理这些索引。如果从表中接收索引(即视图)并且您希望使用这些索引在模型中查找值,则首先需要使用convertXXXToModel方法转换索引。