当我使用removeAll(和e.getValueIsAdjusting == false)从列表中删除多个项目时,为什么我的ListSelectionListener会看到多个事件?

时间:2012-09-16 22:15:14

标签: java jtable jlist glazedlists

我正在使用GlazedLists'以下示例中为EventListEventTableModel。我不确定它会有所作为。我有一张桌子,我正在观看选择更改。当我删除多个项目时,ListSelectionListener会看到多个事件,并且当处理程序内部时,表格报告的选定索引与之前的模型状态匹配即使模型发生了删除已经改变了。

当我运行以下示例时,列表中添加了7个项目。如果我选择最后2项,则以下输出最终会出现在控制台上:

Selected row count: 2
Item list size: 7
Selected index: 5
Selected index: 6

这就是我所期待的,但当我删除这两项时,我得到以下输出:

Selected row count: 1
Item list size: 5
Selected index: 5

Selected row count: 0
Item list size: 5

由于我使用列表中的removeAll删除了连续区块中的项目,因此我认为这是一个事件,但ListSelectionListener似乎会收到通知,就像它& #39;两个独立的事件。如果我删除4个项目,则听众会看到4个事件。

桌子和型号不同步,但我不确定原因。如果从列表末尾删除项目,则表格报告的选定索引可能大于基础列表大小。基本上,从JTable.getSelectedRows返回的索引在基础模型上调用removeAll导致的最后一个选择事件之前是不可靠的。

如何在列表选择稳定并且JTable将报告正确的选定索引后,如何获得有关选择更改的通知?

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.gui.AdvancedTableFormat;
import ca.odell.glazedlists.impl.sort.ComparableComparator;
import ca.odell.glazedlists.swing.EventTableModel;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import static javax.swing.WindowConstants.EXIT_ON_CLOSE;

public class MultiDeleteMain {
    // The number of items that should be added to the model.
    @SuppressWarnings("FieldCanBeLocal")
    private final int itemCount = 7;

    private EventList<Item> itemList;
    private JTable itemTable;

    public static void main(String[] args) {
        new MultiDeleteMain();
    }

    public MultiDeleteMain() {
        SwingUtilities.invokeLater(new Runnable() {
            @SuppressWarnings("ConstantConditions")
            @Override
            public void run() {
                // The delete function needs access to the list and table, so
                // they are stored as instance variables.
                itemList = createItemList();
                itemTable = createItemTable(itemList);

                addListSelectionListenerToItemTable(itemTable);

                JPanel mainPanel = new JPanel(new BorderLayout());
                mainPanel.add(createDeleteButton(), BorderLayout.NORTH);
                mainPanel.add(new JScrollPane(itemTable), BorderLayout.CENTER);

                JFrame mainFrame = new JFrame("Multi-deletion in list test.");
                mainFrame.setContentPane(mainPanel);
                mainFrame.pack();
                mainFrame.setSize(300, mainFrame.getHeight());
                mainFrame.setLocationRelativeTo(null);
                mainFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                mainFrame.setVisible(true);
            }
        });
    }

    private EventList<Item> createItemList() {
        EventList<Item> itemList = new BasicEventList<>();
        for (int i = 0; i < itemCount; i++) {
            itemList.add(new Item("Item " + i));
        }
        return itemList;
    }

    @SuppressWarnings("ConstantConditions")
    private JTable createItemTable(EventList<Item> itemList) {
        JTable itemTable = new JTable(new EventTableModel<>(itemList, new EventTableModelFormat()));
        itemTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        return itemTable;
    }

    private void addListSelectionListenerToItemTable(final JTable itemTable) {
        ListSelectionListener listener = new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                if(!e.getValueIsAdjusting()) {
                    System.out.println("Selected row count: " + itemTable.getSelectedRowCount());
                    System.out.println("Item list size: " + itemList.size());
                    for(Integer index : itemTable.getSelectedRows()) {
                        System.out.println("Selected index: " + index);
                    }
                    System.out.println();
                }
            }
        };

        itemTable.getSelectionModel().addListSelectionListener(listener);
    }

    private JButton createDeleteButton() {
        JButton deleteButton = new JButton("Delete");
        deleteButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                deleteSelectedItems();
            }
        });
        return deleteButton;
    }

    @SuppressWarnings("ConstantConditions")
    private void deleteSelectedItems() {
        List<Item> itemsToDelete = new ArrayList<>();
        for (Integer rowIndex : itemTable.getSelectedRows()) {
            int convertedIndex = itemTable.convertRowIndexToModel(rowIndex);
            itemsToDelete.add(itemList.get(convertedIndex));
        }

        itemList.removeAll(itemsToDelete);
        itemTable.revalidate();
        itemTable.repaint();
    }

    // Enum for managing table columns
    private static enum Columns {
        NAME("Name", String.class, new ComparableComparator());

        private final String name;
        private final Class type;
        private final Comparator comparator;

        private Columns(String name, Class type, Comparator comparator) {
            this.name = name;
            this.type = type;
            this.comparator = comparator;
        }
    }

    // Each table holds a list of items.
    private static class Item {
        private final String name;

        private Item(String name) {
            this.name = name;
        }
    }

    // Table format for use with the EventTableModel
    private static class EventTableModelFormat implements AdvancedTableFormat<Item> {
        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public String getColumnName(int i) {
            return Columns.values()[i].name;
        }

        @Override
        public Object getColumnValue(Item item, int i) {
            return item.name;
        }

        @Override
        public Class getColumnClass(int column) {
            return Columns.values()[column].type;
        }

        @Override
        public Comparator getColumnComparator(int column) {
            System.out.println("Asked for comparator.");
            return Columns.values()[column].comparator;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

我们必须知道EventList和EventTableModel的外观。我敢打赌,EventTableModel并不保证deleteAll方法只会传递连续的元素。因此,唯一的选择是逐个删除它们,为每个事件触发一个单独的事件。