更新后,setAutoCreateRowSorter不会正确排序表列 [英] setAutoCreateRowSorter doesn't sort table column correctly after update
问题描述
在开发小型任务管理器时,我注意到列未正确排序。为了解决我的程序问题,我创建了一个最小版本但它仍然无法正确排序唯一列。
import java .awt.BorderLayout;
import java.util.List;
import java.util.Random;
import javax.swing。*;
import javax.swing.table.AbstractTableModel;
公共类TableSortTest扩展了JFrame
{
私有最终JTable表;
私有最终ATableModel模型;
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.execute();
}
私人类对
{
int index;
int value;
}
私有类Worker扩展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);
配对p = new Pair();
p.index = indice;
p.value = Math.abs(r.nextInt());
publish(p);
}
尝试
{
Thread.sleep(1000);
}
catch(InterruptedException ie)
{
ie.printStackTrace();
}
}
返回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)));
}
私有类ATableModel扩展AbstractTableModel
{
private final Integer [] data;
public ATableModel()
{
data = new Integer [100];
随机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)
{
returnColumn;
}
}
public static final void main(String [] args)
{
SwingUtilities.invokeLater(() - >
{
try
{
new TableSortTest();
}
catch(例外e)
{
e.printStackTrace();
}
});
}
}
我试过 ScheduledExecutorService
+ Runnable
和一个计时器
+ TimerTask
只是为了测试它是否是一个线程问题,但行为是一样的。我还阅读了有关该主题的Java Tutorial页面。鉴于我的表只使用标准类型,我认为一个简单的 table.setAutoCreateRowSorter(true);
应该可以完成这项工作,不应该吗?
每次修改/添加/删除后,是否应该对表进行排序?
使用
import java.awt。 BorderLayout的;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing。*;
import javax.swing.table.AbstractTableModel;
/ ** @see https://stackoverflow.com/a/36522182/230513 * /
公共类TableSortTest扩展JFrame {
私有最终JTable表;
私有最终ATableModel模型;
public TableSortTest(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
model = new ATableModel();
table = new JTable(model){
@Override
public Dimension getPreferredScrollableViewportSize(){
return new Dimension(200,500);
}
};
table.setFillsViewportHeight(true);
table.setAutoCreateRowSorter(true);
add(new JScrollPane(table),BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setVisible(true);
工人工人=新工人();
worker.execute();
}
私人类对{
int index;
int value;
}
私有类Worker扩展SwingWorker< Void,Pair> {
private static final int N = 100;
private final Random r = new Random();
@Override
protected Void doInBackground(){
while(!isCancelled()){
for(int i = 0; i< N; i ++) {
int index = r.nextInt(N);
配对p = new Pair();
p.index = index;
p.value = Math.abs(r.nextInt());
publish(p);
}
try {
Thread.sleep(1000);
} catch(InterruptedException ie){
ie.printStackTrace();
}
}
返回null;
}
@Override
public void process(List< Pair> items){
for(Pair p:items){
model.setValueAt( p.value,p.index,0);
}
}
}
私有类ATableModel扩展AbstractTableModel {
private static final int N = 100;
私人最终名单<整数> data = new ArrayList<>(N);
public ATableModel(){
final Random r = new Random();
for(int i = 0; i< N; i ++){
data.add(Math.abs(r.nextInt()));
}
}
@Override
public int getColumnCount(){
return 1;
}
@Override
public int getRowCount(){
return data.size();
}
@Override
public Object getValueAt(int rowIndex,int columnIndex){
return data.get(rowIndex);
}
@Override
public void setValueAt(Object value,int rowIndex,int columnIndex){
data.set(rowIndex,(Integer)value);
fireTableDataChanged();
}
@Override
public class getColumnClass(int columnIndex){
return Integer.class;
}
@Override
public String getColumnName(int col){
returnColumn;
}
}
public static final void main(String [] args){
SwingUtilities.invokeLater(() - > {
new TableSortTest ();
});
}
}
认识到这只是一个例子,下面的变化通过发布 List< Integer>
来优化更新,将 en bloc 传递给 TableModel
via process()
。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing。*;
import javax.swing.table.AbstractTableModel;
/ **
* @请参阅https://stackoverflow.com/a/36522182/230513
* /
公共类TableSortTest扩展JFrame {
私有最终JTable表;
私有最终ATableModel模型;
public TableSortTest(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
model = new ATableModel();
table = new JTable(model){
@Override
public Dimension getPreferredScrollableViewportSize(){
return new Dimension(200,500);
}
};
table.setFillsViewportHeight(true);
table.setAutoCreateRowSorter(true);
add(new JScrollPane(table),BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setVisible(true);
工人工人=新工人();
worker.execute();
}
私有类Worker扩展SwingWorker< List< Integer>,List< Integer>> {
private static final int N = 100;
private final Random r = new Random();
私人最终名单<整数> data = new ArrayList<>(N);
@Override
protected List< Integer> doInBackground()抛出异常{
while(!isCancelled()){
data.clear();
for(int i = 0; i< N; i ++){
data.add(Math.abs(r.nextInt()));
}
发布(数据);
try {
Thread.sleep(1000);
} catch(InterruptedException ie){
ie.printStackTrace(System.err);
}
}
返回数据;
}
@Override
protected void process(List< List< Integer>> chunks){
for(List< Integer> chunk:chunks){
model.update(chunk);
}
}
}
私有类ATableModel扩展AbstractTableModel {
private List< Integer> data = new ArrayList<>();
public void update(List< Integer> data){
this.data = data;
fireTableDataChanged();
}
@Override
public int getColumnCount(){
return 1;
}
@Override
public int getRowCount(){
return data.size();
}
@Override
public Object getValueAt(int rowIndex,int columnIndex){
return data.get(rowIndex);
}
@Override
public class getColumnClass(int columnIndex){
return Integer.class;
}
@Override
public String getColumnName(int col){
returnColumn;
}
}
public static final void main(String [] args){
SwingUtilities.invokeLater(() - > {
new TableSortTest ();
});
}
}
While developing a small task manager, I have noticed that columns aren't sorted correctly. To discard problems with my program, I have created a minimal version but it still fails to order the unique column right.
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 ();
}
});
}
}
I have tried with a ScheduledExecutorService
+ Runnable
and a Timer
+ TimerTask
just to test if it was a threading problem, but the behavior is the same. I have also read the Java Tutorial page about the subject. Given that my table only uses standard types I think that a simple table.setAutoCreateRowSorter (true);
should do the job, shouldn't it?
Shouldn't the table be sorted after every modification/addition/removal even is fired?
Using setSortsOnUpdates()
, suggested here by @trcs, is the best general solution, but you may be able to optimize updates by the choice of TableModelEvent
available to subclasses of AbstractTableModel
.
The critical issue is the implementation of setValueAt()
. If you meant fireTableRowsUpdated()
, instead of fireTableRowUpdated()
, note that the parameters represent a range of rows, not a row & column. In this case, because "all cell values in the table's rows may have changed," the revised example below invokes fireTableDataChanged()
. I've also changed the model to manage a List<Integer>
and normalized the size, N
.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
/** @see https://stackoverflow.com/a/36522182/230513 */
public class TableSortTest extends JFrame {
private final JTable table;
private final ATableModel model;
public TableSortTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
model = new ATableModel();
table = new JTable(model){
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, 500);
}
};
table.setFillsViewportHeight(true);
table.setAutoCreateRowSorter(true);
add(new JScrollPane(table), BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setVisible(true);
Worker worker = new Worker();
worker.execute();
}
private class Pair {
int index;
int value;
}
private class Worker extends SwingWorker<Void, Pair> {
private static final int N = 100;
private final Random r = new Random();
@Override
protected Void doInBackground() {
while (!isCancelled()) {
for (int i = 0; i < N; i++) {
int index = r.nextInt(N);
Pair p = new Pair();
p.index = index;
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);
}
}
}
private class ATableModel extends AbstractTableModel {
private static final int N = 100;
private final List<Integer> data = new ArrayList<>(N);
public ATableModel() {
final Random r = new Random();
for (int i = 0; i < N; i++) {
data.add(Math.abs(r.nextInt()));
}
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data.get(rowIndex);
}
@Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
data.set(rowIndex, (Integer) value);
fireTableDataChanged();
}
@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(() -> {
new TableSortTest();
});
}
}
Recognizing that this is just an example, the variation below optimizes updates by publishing a List<Integer>
, which is passed en bloc to the TableModel
via process()
.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
/**
* @ see https://stackoverflow.com/a/36522182/230513
*/
public class TableSortTest extends JFrame {
private final JTable table;
private final ATableModel model;
public TableSortTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
model = new ATableModel();
table = new JTable(model) {
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, 500);
}
};
table.setFillsViewportHeight(true);
table.setAutoCreateRowSorter(true);
add(new JScrollPane(table), BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setVisible(true);
Worker worker = new Worker();
worker.execute();
}
private class Worker extends SwingWorker<List<Integer>, List<Integer>> {
private static final int N = 100;
private final Random r = new Random();
private final List<Integer> data = new ArrayList<>(N);
@Override
protected List<Integer> doInBackground() throws Exception {
while (!isCancelled()) {
data.clear();
for (int i = 0; i < N; i++) {
data.add(Math.abs(r.nextInt()));
}
publish(data);
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace(System.err);
}
}
return data;
}
@Override
protected void process(List<List<Integer>> chunks) {
for (List<Integer> chunk : chunks) {
model.update(chunk);
}
}
}
private class ATableModel extends AbstractTableModel {
private List<Integer> data = new ArrayList<>();
public void update(List<Integer> data) {
this.data = data;
fireTableDataChanged();
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data.get(rowIndex);
}
@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(() -> {
new TableSortTest();
});
}
}
这篇关于更新后,setAutoCreateRowSorter不会正确排序表列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!