我正在使用 GlazedLists'EventList
并EventTableModel
在下面的示例中。我不确定它是否有所作为。我有一张桌子,我正在观察选择的变化。当我删除多个项目时,会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
似乎收到通知,就好像它是两个单独的事件一样。如果我删除 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;
}
}
}