[英]Wrong column being sorted when JTable Header clicked
I have the following code for a RowSorterListener
. 我有以下代码用于
RowSorterListener
。 The purpose of this is to sort a column without affecting any other columns. 这样做的目的是对一列进行排序而不影响任何其他列。
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;
};
}
This works well. 这很好。 However, there is one major glitch.
但是,存在一个主要故障。 If a column is moved and I try to sort a column it doesn't correctly sort the column.
如果移动了列,但我尝试对列进行排序,则无法正确对列进行排序。 Instead, it incorrectly sorts the column in the original place of the column moved.
而是,它在移动的列的原始位置中对列进行了错误的排序。
Whereas it should look like (Where "Column 1" and "Column 2" remain unsorted) 看起来应该是这样(“第1列”和“第2列”仍未排序)
Would someone be able to explain why this occurs and how to fix it? 有人能够解释为什么会发生这种情况以及如何解决吗?
Note: I do not want to use JTableHeader.reorderingAllowed(false)
注意:我不想使用
JTableHeader.reorderingAllowed(false)
Edit 编辑
I added the following for loops into my code and tried different variations but it didn't seem to work 我在代码中添加了以下for循环,并尝试了不同的变体,但似乎不起作用
Attempt 1 尝试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]);
}
}
}
}
Attempt 2 尝试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;
};
Attempt 3 was both attempt one and two put together 尝试3是尝试1和2的总和
code in RowSorterListener
is designatet to returns the index correctly (from RowSorterListener
s event) 指定
RowSorterListener
代码以正确返回索引(来自RowSorterListener
的事件)
by default you never need to know ordering from JTable
s view, all those events are models events
, 默认情况下,您不需要从
JTable
的视图知道顺序,所有这些事件都是models events
,
add TableColumnModelListener
in the case that you want to trace columnMoved
, all events from sorting programatically are painted in JTable
s view correctly 如果要跟踪
columnMoved
,请添加TableColumnModelListener
,以编程方式排序的所有事件都将正确地绘制在JTable
的视图中
1st. 1号 attemtp without column reordering,
attemtp无需重新排序列,
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)
. 。
. 。
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)
3rd. 第三名 attempt the same correct output if Swing Timer isn't initialized and all event are made by users hand
如果未初始化Swing Timer且所有事件均由用户手动进行,则尝试相同的正确输出
for example 例如
. 。
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();
});
}
}
From your problem description (haven't looked at the code) you probably are not converting indexes reported from view indexes to model index or vice versa. 从问题描述(没有查看代码),您可能没有将视图索引报告的索引转换为模型索引,反之亦然。
Cf JTable general description, to quote the relevant part: cf JTable的一般描述,引用相关部分:
Similarly when using the sorting and filtering functionality provided by
RowSorter
the underlyingTableModel
does not need to know how to do sorting, ratherRowSorter
will handle it.同样,使用
RowSorter
提供的排序和筛选功能时,底层的TableModel
不需要知道如何进行排序,而是由RowSorter
进行处理。 Coordinate conversions will be necessary when using the row based methods ofJTable
with the underlyingTableModel
.当将
JTable
基于行的方法与基础TableModel
一起使用时,必须进行坐标转换。 All ofJTables
row based methods are in terms of theRowSorter
, which is not necessarily the same as that of the underlyingTableModel
.所有基于
JTables
行的方法都是基于RowSorter
,不一定与基础TableModel
的相同。 For example, the selection is always in terms ofJTable
so that when usingRowSorter
you will need to convert usingconvertRowIndexToView
orconvertRowIndexToModel
.例如,选择始终是根据
JTable
因此在使用RowSorter
时,需要使用convertRowIndexToView
或convertRowIndexToModel
进行转换。 [...][...]
You need to be aware that listeners on your table will report in view indexes, not model indexes. 您需要注意,表上的侦听器将在视图索引而非模型索引中报告。 If you use a view index to get values from the model, you will experience the problem you are describing.
如果使用视图索引从模型中获取值,您将遇到描述的问题。
To handle these conversions, following methods exist in JTable: 为了处理这些转换,JTable中存在以下方法:
A small example to explain model vs view in a JTable
in relation to your problem. 一个小示例,用于说明与您的问题有关的
JTable
中的模型vs视图。 The model of a table contains the data. 表的模型包含数据。 The view is what is shown on the screen.
该视图就是屏幕上显示的内容。 The view maps its columns to columns in the model.
该视图将其列映射到模型中的列。 When the column is dragged to a different position in the view (ie what you see on screen), your model is not changed (ie the data in the data container is not changed).
当将列拖动到视图中的其他位置(即,在屏幕上看到的内容)时,模型不会更改(即,数据容器中的数据不会更改)。 What happens is that the mapping from view to model changes.
发生的是从视图到模型的映射发生了变化。
For example you have three columns A, B and C in your data model and you drag the second column on screen to the first position so that the order becomes B, A, C on screen. 例如,数据模型中有三列A,B和C,然后将屏幕上的第二列拖到第一个位置,以便顺序在屏幕上变为B,A,C。 What the view does is change its mapping to show column B in the first position, A in the second position and C in the third position.
该视图所做的是更改其映射以在第一位置显示列B,在第二位置显示A,在第三位置显示C。 So the mapping was
view:1->model:A, view:2->model:B, view:3->model:C
and after the dragging becomes view:1->model:B, view:2->model:A, view:3->model: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
。
Now back to what I said before. 现在回到我之前说的。 When any listener on a
JTable
reports indexes (row, column) it does so with view indexes. 当
JTable
上的任何侦听器报告索引(行,列)时,它都会使用视图索引进行报告。 Now if you want to look up what the value is at those indexes in the model, you first need to translate those view indexes to model indexes using the methods I highlighted before. 现在,如果要查找模型中这些索引的值,则首先需要使用我之前强调的方法将这些视图索引转换为模型索引。
So you always need to be aware what indexes you are receiving and what you intend to do with them. 因此,您始终需要知道要接收哪些索引以及打算如何使用它们。 If you receive indexes from the table (ie the view) and you want to use those to look up values in the model, you first need to translate the indexes using the
convertXXXToModel
methods. 如果您从表(即视图)接收到索引,并且想使用那些索引来查找模型中的值,则首先需要使用
convertXXXToModel
方法转换索引。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.