在开发一个小型任务管理器时,我注意到列的排序不正确。为了消除程序中的问题,我创建了一个最小版本,但它仍然无法正确排序唯一列。
import java.awt.BorderLayout;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
public class TableSortTest extends JFrame
{
private final JTable table;
private final ATableModel model;
public TableSortTest ()
{
setDefaultCloseOperation (EXIT_ON_CLOSE);
setSize (1366, 768);
setLocationRelativeTo (null);
model = new ATableModel ();
table = new JTable ();
table.setFillsViewportHeight (true);
table.setAutoCreateRowSorter (true);
table.setModel (model);
add (new JScrollPane (table), BorderLayout.CENTER);
setVisible (true);
Worker worker = new Worker ();
worker.execute ();
}
private class Pair
{
int index;
int value;
}
private class Worker extends SwingWorker <Void, Pair>
{
@Override
protected Void doInBackground ()
{
while (!isCancelled ())
{
Random r = new Random ();
for (int i = 0; i < 100; i++)
{
int indice = getIndexInRange (0, 99);
Pair p = new Pair ();
p.index = indice;
p.value = Math.abs (r.nextInt ());
publish (p);
}
try
{
Thread.sleep (1000);
}
catch (InterruptedException ie)
{
ie.printStackTrace ();
}
}
return null;
}
@Override
public void process (List <Pair> items)
{
for (Pair p : items)
{
model.setValueAt (p.value, p.index, 0);
}
}
}
public static int getIndexInRange (int min, int max)
{
return (min + (int) (Math.random () * ((max - min) + 1)));
}
private class ATableModel extends AbstractTableModel
{
private final Integer [] data;
public ATableModel ()
{
data = new Integer [100];
Random r = new Random ();
for (int i = 0; i < 100; i++)
{
data [i] = Math.abs (r.nextInt ());
}
}
@Override
public int getColumnCount ()
{
return 1;
}
@Override
public int getRowCount ()
{
return data.length;
}
@Override
public Object getValueAt (int rowIndex, int columnIndex)
{
return data [rowIndex];
}
@Override
public void setValueAt (Object value, int rowIndex, int columnIndex)
{
data [rowIndex] = (Integer) value;
fireTableRowUpdated (rowIndex, columnIndex);
}
@Override
public Class getColumnClass (int columnIndex)
{
return Integer.class;
}
@Override
public String getColumnName (int col)
{
return "Column";
}
}
public static final void main (String [] args)
{
SwingUtilities.invokeLater (() ->
{
try
{
new TableSortTest ();
}
catch (Exception e)
{
e.printStackTrace ();
}
});
}
}
我尝试过使用 ScheduledExecutorService
+ Runnable
和 Timer
+ TimerTask
只是为了测试它是否是线程问题,但行为是相同的。我还阅读了有关该主题的 Java 教程页面。鉴于我的表仅使用标准类型,我认为一个简单的 table.setAutoCreateRowSorter (true);
应该可以完成这项工作,不是吗?
在每次修改/添加/删除甚至被触发后,表不应该被排序吗?
最佳答案
感谢您的快速回答trashgod。你是对的,我的意思是 fireTableRowsUpdated ()
但我在写代码时犯了一个错误,抱歉。关键是 fireTableRowsUpdated (rowIndex, rowIndex)
和 fireTableCellUpdated (rowIndex, columnIndex)
都无法正确对列进行排序。在实际程序中,大多数表行确实会从一次迭代到下一次迭代发生变化,因此调用 fireTableDataChanged ()
非常有意义。但我不想使用它,因为如果我选择一行或多行向进程发送信号,或者每次更新时选择都会丢失。我已经探索了这种方式,发现了两种保留选择的形式,但这有点烦人,其中一种用键盘破坏了选择。接下来我将展示对原始代码的必要添加。
第一个表单在修改模型之前保存选择并在每次更新后恢复它:
...
private class Worker extends SwingWorker <Void, Pair>
{
private int [] selectedRows;
@Override
protected Void doInBackground ()
{
while (!isCancelled ())
{
// Save the selection before modifying the model
int x = table.getSelectedRowCount ();
if (x > 0)
{
selectedRows = new int [x];
int [] tableSelection = table.getSelectedRows ();
for (int i = 0; i < x; i++)
{
selectedRows [i] = table.convertRowIndexToModel (tableSelection [i]);
}
}
Random r = new Random ();
for (int i = 0; i < table.getRowCount (); i++)
{
int indice = getIndexInRange (0, table.getRowCount () - 1);
Pair p = new Pair ();
p.index = indice;
p.value = Math.abs (r.nextInt ());
publish (p);
}
// If I put the code to restore the selection here, it doesn't work...
try
{
Thread.sleep (1000);
}
catch (InterruptedException ie)
{
ie.printStackTrace ();
}
}
return null;
}
@Override
public void process (List <Pair> items)
{
for (Pair p : items)
{
model.setValueAt (p.value, p.index, 1);
}
// Restore the selection on every update
if (selectedRows != null && selectedRows.length > 0)
{
for (int i = 0; i < selectedRows.length; i++)
{
table.addRowSelectionInterval (table.convertRowIndexToView (selectedRows [i]), table.convertRowIndexToView (selectedRows [i]));
}
}
}
}
...
第二种形式使用一个ListSelectionListener
、一个KeyListener
和一个标志。使用键盘进行选择不起作用。老实说,我不知道我是如何得到这个解决方案的。这可能是偶然的:
public class TableSortTestSolucionConSelectionListener extends JFrame implements KeyListener
{
...
private boolean ctrlOrShiftDown = false;
private int [] selectedRows;
@Override
public void keyPressed (KeyEvent e)
{
ctrlOrShiftDown = e.isControlDown () || e.isShiftDown ();
}
@Override
public void keyReleased (KeyEvent e)
{
ctrlOrShiftDown = e.isControlDown () || e.isShiftDown ();
}
@Override
public void keyTyped (KeyEvent e)
{
ctrlOrShiftDown = e.isControlDown () || e.isShiftDown ();
}
public TableSortTestSolucionConSelectionListener ()
{
...
ListSelectionListener lsl = new ListSelectionListener ()
{
@Override
public void valueChanged (ListSelectionEvent e)
{
if (!e.getValueIsAdjusting ())
{
if (!ctrlOrShiftDown)
{
int x = table.getSelectedRowCount ();
if (x > 0)
{
selectedRows = new int [x];
int [] tableSelection = table.getSelectedRows ();
for (int i = 0; i < x; i++)
{
selectedRows [i] = table.convertRowIndexToModel (tableSelection [i]);
}
}
}
// Disable the listener to avoid infinite recursion
table.getSelectionModel ().removeListSelectionListener (this);
if (selectedRows != null && selectedRows.length > 0)
{
for (int i = 0; i < selectedRows.length; i++)
{
table.addRowSelectionInterval (table.convertRowIndexToView (selectedRows [i]), table.convertRowIndexToView (selectedRows [i]));
}
}
table.getSelectionModel ().addListSelectionListener (this);
}
}
};
table.getSelectionModel ().addListSelectionListener (lsl);
...
}
幸运的是,今天我找到了一种简单的方法来正确排序列并保留当前选择。您只需将以下内容添加到代码中:
TableRowSorter trs = (TableRowSorter) table.getRowSorter ();
trs.setSortsOnUpdates (true);
有了这个,fireTableCellUpdated ()
和 fireTableRowsUpdated ()
都可以按我的预期工作。据我了解,setAutoCreateRowSorter()
仅用于在单击表头时对行进行排序。
问候。
关于java - 更新后 setAutoCreateRowSorter 无法正确对表列进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36520501/