私はGlazedListsを使用EventList
しEventTableModel
ています。以下の例では。それが違いを生むかどうかはわかりません。選択の変更を監視しているテーブルがあります。複数のアイテムを削除するListSelectionListener
と、複数のイベントが表示され、ハンドラー内では、モデルが既に変更されていても、テーブルによって報告された選択されたインデックスが、削除が発生する前のモデルの状態と一致します。
以下の例を実行すると、7つのアイテムがリストに追加されます。最後の2つの項目を選択すると、次の出力がコンソールに表示されます。
Selected row count: 2
Item list size: 7
Selected index: 5
Selected index: 6
それは私が期待していることですが、これら2つのアイテムを削除すると、次の出力が得られます。
Selected row count: 1
Item list size: 5
Selected index: 5
Selected row count: 0
Item list size: 5
removeAll
リストを使用して連続ブロック内のアイテムを削除しているので、これは1つのイベントだと思いますが、 ListSelectionListener
2つの別々のイベントであるかのように通知されているようです。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;
}
}
}