Java dataModelUpdate后自动排序JTable
数据模型更改后保持排序 预期行为: 我单击其中一个ColumnHeader进行排序,它应该随着数据模型的更改而保持对该列的排序。也就是说,一旦选择了要排序的列,就不必在每次更新基础数据模型后手动单击它,就可以按顺序查看它 当前行为: 似乎在数据模型更改后重置排序。也就是说,好像我没有点击任何专栏。数据模型的更新使其再次混乱 我尝试的内容: 我编写了一个小程序,每2000毫秒通过for循环模拟底层数据模型的变化。 由于原始数据在不同的更新中变化很大,因此我选择使用DefaultTableModel.setDataVector()来更改数据,而不是使用一行一行地更改数据,因为如果有很多行发生更改,这看起来会很庞大。 我使用了对我有意义的工具,即TableRowSorter.setSontUpdates(),来。。。更新后排序(x)。 我遗漏了注释代码,以表明我尝试了不同的方法,其中一些方法可以在stackexchange上找到,但无论如何都无法实现。 我尝试阅读api,发现这是一个可能的问题制造者: 如果基础模型结构发生更改(调用modelStructureChanged方法),则以下内容将重置为其默认值:按列列出的比较器、当前排序顺序以及每个列是否可排序。默认的排序顺序是自然的(与模型相同),默认情况下列是可排序的 这可以在API文档中找到: 我想有人可能会说,我不希望它重置为默认排序顺序,而是保留最后选择的排序顺序。肯定有什么简单的方法可以阻止它这样做 顺便说一句,我是一个noob,请在回答时记住这一点,我希望我在试图解释预期的行为时有意义 迄今为止我的代码:Java dataModelUpdate后自动排序JTable,java,swing,jtable,tablerowsorter,Java,Swing,Jtable,Tablerowsorter,数据模型更改后保持排序 预期行为: 我单击其中一个ColumnHeader进行排序,它应该随着数据模型的更改而保持对该列的排序。也就是说,一旦选择了要排序的列,就不必在每次更新基础数据模型后手动单击它,就可以按顺序查看它 当前行为: 似乎在数据模型更改后重置排序。也就是说,好像我没有点击任何专栏。数据模型的更新使其再次混乱 我尝试的内容: 我编写了一个小程序,每2000毫秒通过for循环模拟底层数据模型的变化。 由于原始数据在不同的更新中变化很大,因此我选择使用DefaultTableModel
package TestTable;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Random;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import ui.Runner;
public class starter {
public static void main(String[] args) {
starter start = new starter();
Vector<String> columNames = new Vector<>();
columNames.add("index");
columNames.add("years");
columNames.add("weight");
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
Vector<Object> dataInData = new Vector<>();
Random dice = new Random();
JTable table = new JTable(data, columNames);
//table.setAutoCreateRowSorter(true);
MyFrame frame = new MyFrame(table);
DefaultTableModel model = (DefaultTableModel)table.getModel();
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<>(model);
//MyRowSorter<DefaultTableModel> sorter = new MyRowSorter<>();
table.setRowSorter(sorter);
//DefaultRowSorter sorter = (DefaultRowSorter)table.getRowSorter();
//TableModelEvent ev = new TableModelEvent(model);
sorter.setSortsOnUpdates(true);//<---------------<<<<<
data.add(new Vector<Object>());
data.add(new Vector<Object>());
data.add(new Vector<Object>());
for(int x = 0; x < 3; x++) {
dataInData = data.get(x);
for(int y = 0; y < 5; y++) {
dataInData.add(dice.nextInt(10));
}
}
for(int z = 0; z < 10; z++) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int x = 0; x < 3; x++) {
dataInData = data.get(x);
for(int y = 0; y < dataInData.size(); y++) {
dataInData.set(y, dice.nextInt(10));
}
}
model.setDataVector(data, columNames);//<-------------------<<
//model.fireTableDataChanged();
//sorter.setSortsOnUpdates(true);
//sorter.rowsUpdated(0, data.size() -1);
model.fireTableRowsUpdated(0, model.getRowCount() -1 );
//model.fireTableDataChanged();
//model.fireTableChanged(ev);
//model.fireTableStructureChanged();
//sorter.rowsUpdated(0, data.size() );
//sorter.sort();
}
}
public static class MyFrame extends JFrame{
JTable table;
Dimension dim = new Dimension(300, 500);
JScrollPane pane;
Vector<String> columNames = new Vector<>();
Vector<Vector<Object>> dataVector;
Runner thread;
int[] i = {0, 1, -1};
public MyFrame(JTable table) {
pane = new JScrollPane(table);
table.setFillsViewportHeight(true);
setSize(300, 500);
setPreferredSize(dim);
setMinimumSize(dim);
setTitle("Failing autoupdate of JTable");
setBackground(Color.BLACK);
add(pane);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
}
包测试表;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.util.Random;
导入java.util.Vector;
导入javax.swing.JFrame;
导入javax.swing.JScrollPane;
导入javax.swing.JTable;
导入javax.swing.table.DefaultTableModel;
导入javax.swing.table.TableRowSorter;
导入ui.Runner;
公开课初学者{
公共静态void main(字符串[]args){
起动机起动=新起动机();
向量列名称=新向量();
添加(“索引”);
专栏名称。添加(“年”);
列名称。添加(“重量”);
向量数据=新向量();
Vector dataInData=新向量();
随机骰子=新随机();
JTable table=新的JTable(数据、列名称);
//表.setAutoCreateRowSorter(真);
MyFrame=新的MyFrame(表格);
DefaultTableModel=(DefaultTableModel)table.getModel();
TableRowSorter分拣机=新的TableRowSorter(型号);
//MyRowSorter-sorter=新的MyRowSorter();
表.SetRow分拣机(分拣机);
//DefaultRowSorter-sorter=(DefaultRowSorter)table.getRowSorter();
//TableModelEvent ev=新的TableModelEvent(模型);
sorter.setSortsOnUpdates(true);//设置新的首选索引时,是否要保留排序?
您只有三个ColumnHeader(有限),为什么不设置ColumnHeader的优先级呢?
单击一个标题时,将其优先级更改为“第一”,将其他标题的优先级降低一。
然后再次计算总排序以显示它们。设置新的首选索引时是否保留排序?
您只有三个ColumnHeader(有限),为什么不设置ColumnHeader的优先级呢?
单击一个标题时,将其优先级更改为“第一”,将其他标题的优先级降低一。
并再次计算总排序以显示它们
我选择使用DefaultTableModel.setDataVector()来更改数据,而不是一行一行地更改数据,如果有很多行发生更改,这看起来会很庞大
如果所有数据都在更改,这似乎是合理的,因为您将只生成一个事件来重新绘制整个表,而不是为每行生成一个事件
但是,如果您只更改几个随机行上的数据,那么我将只更新单个行,这样您就不会有排序问题
对于第一种方法,请尝试以下方法:
JTable table = new JTable(data, columNames);
table.setAutoCreateColumnsFromModel(false);
这应该可以防止在调用setDataVector(…)
时重新创建TableColumnModel
,从而生成TableStructureChanged
事件,从而导致丢失行分类器。(或者您仍然会丢失RowSorter,我从未尝试过,但我知道使用这种方法您不会丢失自定义渲染器/编辑器)
当数据发生变化时,TableModel负责调用适当的事件
我选择使用DefaultTableModel.setDataVector()来更改数据,而不是一行一行地更改数据,如果有很多行发生更改,这看起来会很庞大
如果所有数据都在更改,这似乎是合理的,因为您将只生成一个事件来重新绘制整个表,而不是为每行生成一个事件
但是,如果您只更改几个随机行上的数据,那么我将只更新单个行,这样您就不会有排序问题
对于第一种方法,请尝试以下方法:
JTable table = new JTable(data, columNames);
table.setAutoCreateColumnsFromModel(false);
这应该可以防止在调用setDataVector(…)
时重新创建TableColumnModel
,从而生成TableStructureChanged
事件,从而导致丢失行分类器。(或者您仍然会丢失RowSorter,我从未尝试过,但我知道使用这种方法您不会丢失自定义渲染器/编辑器)
这是永远不需要的。当数据发生更改时,TableModel负责调用适当的事件。让我们暂时跳过线程冲突问题
在DefaultTableModel
上调用setDataVector
会触发TableStructureChanged
,从而强制执行
for (int x = 0; x < 3; x++) {
for (int y = 0; y < table.getColumnCount(); y++) {
model.setValueAt(dice.nextInt(10), x, y);
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}
public Main() {
Vector<String> columNames = new Vector<>();
columNames.add("index");
columNames.add("years");
columNames.add("weight");
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
Random dice = new Random();
JTable table = new JTable(data, columNames);
MyFrame frame = new MyFrame(table);
DefaultTableModel model = (DefaultTableModel) table.getModel();
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<>(model);
table.setRowSorter(sorter);
sorter.setSortsOnUpdates(true);//<---------------<<<<<
for (int x = 0; x < 3; x++) {
model.addRow(new Vector());
for (int y = 0; y < table.getColumnCount(); y++) {
model.setValueAt(dice.nextInt(10), x, y);
}
}
Timer timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (int x = 0; x < 3; x++) {
for (int y = 0; y < table.getColumnCount(); y++) {
model.setValueAt(dice.nextInt(10), x, y);
}
}
}
});
timer.start();
}
public static class MyFrame extends JFrame {
JTable table;
Dimension dim = new Dimension(300, 500);
JScrollPane pane;
Vector<String> columNames = new Vector<>();
Vector<Vector<Object>> dataVector;
int[] i = {0, 1, -1};
public MyFrame(JTable table) {
pane = new JScrollPane(table);
table.setFillsViewportHeight(true);
setSize(300, 500);
setPreferredSize(dim);
setMinimumSize(dim);
setTitle("Failing autoupdate of JTable");
setBackground(Color.BLACK);
add(pane);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}
Random dice = new Random();
public Main() {
Vector<String> columNames = new Vector<>();
columNames.add("index");
columNames.add("years");
columNames.add("weight");
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
JTable table = new JTable();
makeModel(table, columNames);
MyFrame frame = new MyFrame(table);
Timer timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
makeModel(table, columNames);
}
});
timer.start();
}
protected void makeModel(JTable table, Vector columnNames) {
DefaultTableModel model = new DefaultTableModel(columnNames, 0);
for (int x = 0; x < 3; x++) {
Vector row = new Vector();
for (int y = 0; y < model.getColumnCount(); y++) {
row.add(dice.nextInt(10));
}
model.addRow(row);
}
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<>(model);
RowSorter<? extends TableModel> oldSorter = table.getRowSorter();
if (oldSorter != null) {
sorter.setSortKeys(oldSorter.getSortKeys());
}
table.setModel(model);
table.setRowSorter(sorter);
}
public static class MyFrame extends JFrame {
JTable table;
Dimension dim = new Dimension(300, 500);
JScrollPane pane;
Vector<String> columNames = new Vector<>();
Vector<Vector<Object>> dataVector;
int[] i = {0, 1, -1};
public MyFrame(JTable table) {
pane = new JScrollPane(table);
table.setFillsViewportHeight(true);
setSize(300, 500);
setPreferredSize(dim);
setMinimumSize(dim);
setTitle("Failing autoupdate of JTable");
setBackground(Color.BLACK);
add(pane);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
}
RowSorter<? extends TableModel> lastRowSorter;
List<? extends RowSorter.SortKey> lastSortKeys;
@Override
public void tableChanged(TableModelEvent e) {
lastRowSorter = getRowSorter();
lastSortKeys = (lastRowSorter == null) ? null : lastRowSorter.getSortKeys();
super.tableChanged(e);
}
@Override
public void createDefaultColumnsFromModel() {
super.createDefaultColumnsFromModel();
if( lastSortKeys != null ) {
setRowSorter(lastRowSorter);
lastRowSorter.setSortKeys(lastSortKeys);
}
}