gpt4 book ai didi

java - dataModelUpdate 后自动排序 JTable

转载 作者:行者123 更新时间:2023-12-02 02:50:43 24 4
gpt4 key购买 nike

数据模型更改后继续排序。

预期行为:我单击其中一个列标题进行排序,并且随着数据模型的更改,它应该继续对该列进行排序。也就是说,一旦您选择了要排序的列,您就不必在每次更新基础数据模型后手动单击它来按顺序查看它。

当前行为:似乎在数据模型更改后重置排序。也就是说,就好像我没有单击任何列一样。数据模型的更新,又变得困惑了。

我尝试过的:我编写了一个小程序,通过 for 循环每 2000 毫秒模拟底层数据模型的变化。由于原始数据在更新过程中发生了很大变化,因此我选择使用 DefaultTableModel.setDataVector() 来更改数据,而不是逐行更改数据,如果大量行发生更改,这看起来会很庞大。我使用了对我来说有意义的方法,即 TableRowSorter.setSortsOnUpdates(),以便...在更新 x) 后进行排序。我留下了注释掉的代码,以表明我尝试了不同的方法,其中一些在 stackexchange 上找到,但无论如何都无法使其工作。我尝试读取 api,发现这可能是一个问题产生者:

If the underlying model structure changes (the modelStructureChanged method is invoked) the following are reset to their default values: Comparators by column, current sort order, and whether each column is sortable. The default sort order is natural (the same as the model), and columns are sortable by default.

这是在 API 文档中找到的:TableRowSorter

我想有人可能会说我希望它重置为默认排序顺序,而是保留最后选择的排序顺序。肯定有一种简单的方法可以阻止它这样做吗?

顺便说一句,我是一个菜鸟,请在回答时记住这一点,我希望我在尝试解释预期行为时有意义。

到目前为止我的代码:

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);
}
}
}

最佳答案

让我们暂时跳过线程违规问题。

DefaultTableModel 上调用 setDataVector 会触发 TableStructureChanged,这会强制 JTable 除其他外,丢弃/重置 rowSorter,而是直接更新模型中的值,例如

for (int x = 0; x < 3; x++) {
for (int y = 0; y < table.getColumnCount(); y++) {
model.setValueAt(dice.nextInt(10), x, y);
}
}

我使用 Swing Timer 对此进行了测试,以确保更新在 EDT 中正确进行

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);
}
}
}

I chose to change the data with DefaultTableModel.setDataVector(), instead of row by row which seems bulky if lots of rows change

好吧,这看起来很合理。我似乎能够解决此问题的唯一解决方案是替换 RowSorter,但使用旧 RowSorter 中的 sortKeys

仅使用 RowSorter 的相同实例对我来说不起作用

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);
}
}
}

请注意,这种更新也会删除列/行选择

I chose to change the data with DefaultTableModel.setDataVector(), instead of row by row which seems bulky if lots of rows change

另一种选择是不使用 DefaultTableModel,而是使用 AbstractTableModel 实现您自己的模型,您可以在其中对底层模型数据进行“批量”更新,然后触发tableDataChanged 事件。您必须小心确保在完成批量更新之前不会修改 JTable 可能请求的数据

关于java - dataModelUpdate 后自动排序 JTable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43883012/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com