Получить выбранные строки в JTable, используя AbstractTableModel
У меня есть JTable
с помощью AbstractTableModel
где у меня есть JCheckBox
в первом столбце для выбора строк. Теперь мне нужно получить выбранные строки из таблицы, которые проверяются. Прямо сейчас я последовательно перехожу от первого ряда к последнему и получаю все строки, которые выделены, как показано ниже,
List<Integer> selectedRows = new ArrayList<Integer>();
for(int i = 0; i < table.getRowCount(); i++) {
if((Boolean) table.getValuAt(i, 0)) {
selectedRows.add(i);
}
}
Проблема здесь в том, что мне нужно пройти по всем строкам, когда мне нужно, чтобы получить выбранные строки. Сейчас у меня от 10 до 20 рядов. Но в будущем я получу около 5000 строк. Мой вопрос: если есть 5000 строк и если пользователь выбирает только 5000-ю (последнюю запись) строку, то мне нужно пройти все 5000 строк, чтобы получить выбранную строку. Что, я думаю, не очень хороший подход.
Одним из подходов, который я хочу реализовать, является добавление слушателя к JCheckBox
столбец, такой, что когда-либо происходит изменение (SELECTED/DESELECTED)
тогда мне нужно обновить мой массив выбранных строк в классе слушателя. В этом классе слушателя, когда пользователь выбирает JCheckBox
Мне нужно позвонить table.getSelectedRow(..)
и мне нужно хранить, если что JCheckBox
выбран.
Есть ли лучшие подходы?
2 ответа
В приведенном ниже примере TableModel
обновляет Set<Integer> checked
в реализации setValueAt()
, Модель смежного JList
прослушивает модель таблицы и отображает выбранные в данный момент номера строк. В примере предполагается, что количество выбранных строк мало по сравнению с количеством строк. Обратите внимание на использование TreeSet
, чей итератор сохраняет естественный порядок элементов.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
/** @see http://stackru.com/a/13919878/230513 */
public class CheckTable {
private static final CheckModel model = new CheckModel(5000);
private static final JTable table = new JTable(model) {
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(150, 300);
}
};
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("CheckTable");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1, 0));
f.add(new JScrollPane(table));
f.add(new DisplayPanel(model));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class DisplayPanel extends JPanel {
private DefaultListModel dlm = new DefaultListModel();
private JList list = new JList(dlm);
public DisplayPanel(final CheckModel model) {
super(new GridLayout());
this.setBorder(BorderFactory.createTitledBorder("Checked"));
this.add(new JScrollPane(list));
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
dlm.removeAllElements();
for (Integer integer : model.checked) {
dlm.addElement(integer);
}
}
});
}
}
private static class CheckModel extends AbstractTableModel {
private final int rows;
private List<Boolean> rowList;
private Set<Integer> checked = new TreeSet<Integer>();
public CheckModel(int rows) {
this.rows = rows;
rowList = new ArrayList<Boolean>(rows);
for (int i = 0; i < rows; i++) {
rowList.add(Boolean.FALSE);
}
}
@Override
public int getRowCount() {
return rows;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public String getColumnName(int col) {
return "Column " + col;
}
@Override
public Object getValueAt(int row, int col) {
if (col == 0) {
return row;
} else {
return rowList.get(row);
}
}
@Override
public void setValueAt(Object aValue, int row, int col) {
boolean b = (Boolean) aValue;
rowList.set(row, b);
if (b) {
checked.add(row);
} else {
checked.remove(row);
}
fireTableRowsUpdated(row, row);
}
@Override
public Class<?> getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
@Override
public boolean isCellEditable(int row, int col) {
return col == 1;
}
}
}
Я согласен с Клеопатрой. Когда вы создаете подкласс класса AbstractTableModel, вы переопределяете setValue(значение объекта, int rowIndex, int colIndex). В переопределенном методе вы просто проверяете, является ли столбец столбцом с вашим флажком, и, если это так, соответствующим образом обновляете внутреннюю структуру данных. Вы также можете добавить метод getCheckedRows(), который возвращает List