Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java dataModelUpdate后自动排序JTable_Java_Swing_Jtable_Tablerowsorter - Fatal编程技术网

Java dataModelUpdate后自动排序JTable

Java dataModelUpdate后自动排序JTable,java,swing,jtable,tablerowsorter,Java,Swing,Jtable,Tablerowsorter,数据模型更改后保持排序 预期行为: 我单击其中一个ColumnHeader进行排序,它应该随着数据模型的更改而保持对该列的排序。也就是说,一旦选择了要排序的列,就不必在每次更新基础数据模型后手动单击它,就可以按顺序查看它 当前行为: 似乎在数据模型更改后重置排序。也就是说,好像我没有点击任何专栏。数据模型的更新使其再次混乱 我尝试的内容: 我编写了一个小程序,每2000毫秒通过for循环模拟底层数据模型的变化。 由于原始数据在不同的更新中变化很大,因此我选择使用DefaultTableModel

数据模型更改后保持排序

预期行为: 我单击其中一个ColumnHeader进行排序,它应该随着数据模型的更改而保持对该列的排序。也就是说,一旦选择了要排序的列,就不必在每次更新基础数据模型后手动单击它,就可以按顺序查看它

当前行为: 似乎在数据模型更改后重置排序。也就是说,好像我没有点击任何专栏。数据模型的更新使其再次混乱

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

如果基础模型结构发生更改(调用modelStructureChanged方法),则以下内容将重置为其默认值:按列列出的比较器、当前排序顺序以及每个列是否可排序。默认的排序顺序是自然的(与模型相同),默认情况下列是可排序的

这可以在API文档中找到:

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

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

迄今为止我的代码:

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