简体   繁体   English

JTable选择间隔问题与排序表有关

[英]JTable selection interval issues with sorted table

I have a JTable that is sorted and filtered using a RowSorter and updates in a real time manner. 我有一个JTable,它使用RowSorter进行排序和过滤,并以实时方式进行更新。 I have an issue when users are trying to create a selection interval with either the mouse (click + drag over rows) or via the keyboard (SHIFT + arrow down multiple times). 当用户尝试使用鼠标(单击+拖动行)或通过键盘(多次SHIFT +向下箭头)创建选择间隔时,我遇到了一个问题。

The selection interval start and end get corrupted as soon as a table-model update event occurs. 一旦表模型更新事件发生,选择间隔的开始和结束就会被破坏。 I have discovered that if a table is sorted and there is more than one selected row the selection model fires multiple list selection events that clear then recreate the selection on every table model update. 我发现,如果对一个表进行排序并且选择的行超过一个,则选择模型将触发多个列表选择事件,这些事件将清除并在每次表模型更新时重新创建选择。

If multiple rows are selected one at a time - all is well. 如果一次选择多行-一切都很好。 What the user selected remain selected. 用户选择的内容保持选中状态。 If however the user tries to create a selection-interval by clicking and dragging the mouse down over multiple rows - the rows get selected correctly until a table model update event fires. 但是,如果用户尝试通过在多行上单击并向下拖动鼠标来创建选择间隔,则将正确选择行,直到触发表模型更新事件为止。 The selection then starts building from the currently selected row. 然后,选择从当前选择的行开始构建。

I've attached a small demo application. 我已经附加了一个小型演示应用程序。 Try selecting multiple rows using the mouse - every second the selection will get corrupted.... 尝试使用鼠标选择多行-选择的每一秒都会损坏。

This seems to be a bug (or unwanted behavior) in the Java classes. 这似乎是Java类中的错误(或不良行为)。 I'm hoping someone can provide a creative solution/work-around. 我希望有人可以提供创造性的解决方案/解决方法。

    public class TableTest extends JFrame {
    private static final long serialVersionUID = 1L;

    public TableTest() {
        super("Table Selection Problem");
        setBounds(50, 50, 800, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        // Create a table model
        final DefaultTableModel tableModel = new DefaultTableModel(40,10);

        // Create table row sorter sorted on column 1
        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel);
        sorter.setSortsOnUpdates(true);
        sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(1,SortOrder.DESCENDING)));

        // Create a table and bind the sorter
        JTable table = new JTable(tableModel);
        table.setRowSorter(sorter);

        // Bind a list selection listener, this doesn't do anything besides showing the selection change(s) on every table model update
        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                System.out.println(e); 
            }
        });


        // place the table in the frame
        getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);

        // Simulate some application events that trigger a table update...
        new Thread() {
            public void run() {
                try {
                    final Random r = new Random();
                    for(int x = 0; x < 1000; x++) {
                        // update a table cell (not even an add or delete)
                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                tableModel.setValueAt(r.nextInt(1000), r.nextInt(40), r.nextInt(10));
                            }
                        });
                        // wait 1 second before next table update
                        Thread.sleep(1000);
                    }
                } catch(Throwable t) {
                    t.printStackTrace();
                }
            }
        }.start();      
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                (new TableTest()).setVisible(true);                     
            }
        });     
    }
}

When I ran your code using JDK7 on Windows 7 I found that the setSortsOnUpdates(...) was causing problems with the data in the table. 在Windows 7上使用JDK7运行代码时,我发现setSortsOnUpdates(...)导致表中的数据出现问题。 That is I let the code run for a while and I noticed that no values in column 1 where being displayed. 那就是我让代码运行了一段时间,并且我注意到第1列中没有显示任何值。 So then I increased the width of the frame and suddenly the values appeared in sorted order. 因此,我增加了框架的宽度,然后突然值按排序顺序出现。 So for some reason the table was not being repainted even though the data changed. 因此,由于某些原因,即使数据已更改,该表也没有被重绘。 When I commented the setSortsOnUpdates(...) the changes to the TableModel appeared right away. 当我评论setSortsOnUpdates(...) ,TableModel的更改立即出现。 I have no idea what the problem is. 我不知道是什么问题。

So then I changed the approach to manually invoke a sort when the data is changed. 因此,然后我更改了在数据更改时手动调用排序的方法。 However, I only did the sort when the ListSelectionListener was not adjusting. 但是,我仅在ListSelectionListener未调整时才进行排序。 Here is the code: 这是代码:

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.Arrays;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;

    public class TableTest5 extends JFrame {
    private static final long serialVersionUID = 1L;

    private boolean isAdjusting = false;
    private boolean isModelChanged = false;
    TableRowSorter<TableModel> sorter;
    final Random r = new Random();

    public TableTest5() {
        super("Table Selection Problem");
        setBounds(50, 50, 800, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        // Create a table model
        final DefaultTableModel tableModel = new DefaultTableModel(30,3);

        // Create table row sorter sorted on column 1
//        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel);
        sorter = new TableRowSorter<TableModel>(tableModel);
        sorter.setSortsOnUpdates(true);
        sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(1,SortOrder.DESCENDING)));

        // Create a table and bind the sorter
        JTable table = new JTable(tableModel);
        table.setRowSorter(sorter);

        // Bind a list selection listener, this doesn't do anything besides showing the selection change(s) on every table model update
        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                isAdjusting = e.getValueIsAdjusting();

                if (!isAdjusting && isModelChanged)
                {
                    isModelChanged = false;
                    sorter.sort();
                }
            }
        });


        // place the table in the frame
        getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);

        // Simulate some application events that trigger a table update...
        new Thread() {
            public void run() {
                try {
                    //final Random r = new Random();
                    for(int x = 0; x < 1000; x++) {
                        // update a table cell (not even an add or delete)
                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {

                                int value = r.nextInt(1000);
                                int row = r.nextInt(30);
                                int column = r.nextInt(5);
                                System.out.println(value + " : " + row + " : " + column);
                                tableModel.setValueAt(value, row, column);

                                if (!isAdjusting)
                                    sorter.sort();
                                else
                                    isModelChanged = true;
                            }
                        });
                        // wait 1 second before next table update
                        Thread.sleep(1000);
                    }
                } catch(Throwable t) {
                    t.printStackTrace();
                }
            }
        }.start();

    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                (new TableTest5()).setVisible(true);
            }
        });
    }
}

You might want to consider using a TableModelListener to listen for TableModel changes to manually invoke the sort. 您可能要考虑使用TableModelListener来侦听TableModel的更改,以手动调用排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM