群里看到有的同学需要在某 JTable 内容的基础上,多出一列 checkbox,用于某种多选,不是第一次看到这种需求了,所以写了这个“通用”的代理实现。
大体写了一下,没有仔细处理原TableModel的事件,所以使用的时候要注意原TableModel不能fire基于cell的更新事件,不能添加删除列。
先扔这里,有时间再琢磨。
/* * Copyright 2014 raistlic@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * Currently not supporting column insertion or deletion, that is, if the wrapped (original) table * model inserted or deleted a column, not sure if the table will correctly pick up the event and * works fine afterwards, behaviour unknown. * * <p/> * Also not supporting cell based update event which column index is greater than the selectable * column. * * TODO: Builder and its methods not Java doc-ed yet. * TODO: properly delegate & translate events for the original table model. * * @author raistlic * @since 2014-08-26 */ public class RowSelectableTableModel extends AbstractTableModel implements TableModel { public static RowSelectableTableModel wrap(TableModel tableModel) { return builderFor(tableModel).build(); } public static Builder builderFor(TableModel tableModel) { if (tableModel == null) { throw new NullPointerException("'tableModel' is null."); } return new Builder(tableModel); } public static class Builder { private TableModel tableModel; private int limit; private int selectableColumnIndex; private String selectableColumnName; private Builder(TableModel tableModel) { this.tableModel = tableModel; this.limit = 0; selectableColumnIndex = 0; selectableColumnName = "Select"; } public Builder withSelectionLimit(int limit) { this.limit = limit; return this; } public Builder withSelectableColumnAt(int column) { if (column < 0) { throw new IndexOutOfBoundsException("Selectable column index out of bounds: " + column); } if (column > tableModel.getColumnCount()) { throw new IndexOutOfBoundsException( "Selectable column index out of bounds: " + column + " / " + tableModel.getColumnCount()); } this.selectableColumnIndex = column; return this; } public Builder withSelectableColumnName(String name) { this.selectableColumnName = (name == null) ? "" : name; return this; } public RowSelectableTableModel build() { RowSelectableTableModel result = new RowSelectableTableModel(this); tableModel.addTableModelListener(result.new OriginalModelAdapter()); return result; } } private final TableModel tableModel; private final int limit; private final int selectableColumnIndex; private final String selectableColumnName; private Set<Integer> selected; private int selectionBasedRowCount; private RowSelectableTableModel(Builder builder) { this.tableModel = builder.tableModel; this.limit = builder.limit; this.selectableColumnIndex = builder.selectableColumnIndex; this.selectableColumnName = builder.selectableColumnName; this.selectionBasedRowCount = tableModel.getRowCount(); this.selected = new HashSet<Integer>(); } public Set<Integer> getSelectedRows() { // defensive copy: return new HashSet<Integer>(selected); } @Override public int getRowCount() { return tableModel.getRowCount(); } @Override public int getColumnCount() { return 1 + tableModel.getColumnCount(); } @Override public String getColumnName(int columnIndex) { if (columnIndex < selectableColumnIndex) { return tableModel.getColumnName(columnIndex); } else if (columnIndex == selectableColumnIndex) { return selectableColumnName; } else { return tableModel.getColumnName(columnIndex - 1); } } @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex < selectableColumnIndex) { return tableModel.getColumnClass(columnIndex); } else if (columnIndex == selectableColumnIndex) { return boolean.class; } else { return tableModel.getColumnClass(columnIndex - 1); } } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { if (columnIndex < selectableColumnIndex) { return tableModel.isCellEditable(rowIndex, columnIndex); } else if (columnIndex == selectableColumnIndex) { return limit <= 0 || selected.size() < limit; } else { return tableModel.isCellEditable(rowIndex, columnIndex - 1); } } @Override public Object getValueAt(int rowIndex, int columnIndex) { if (columnIndex < selectableColumnIndex) { return tableModel.getValueAt(rowIndex, columnIndex); } else if (columnIndex == selectableColumnIndex) { return selected.contains(rowIndex); } else { return tableModel.getValueAt(rowIndex, columnIndex - 1); } } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (columnIndex < selectableColumnIndex) { tableModel.setValueAt(aValue, rowIndex, columnIndex); } else if (columnIndex == selectableColumnIndex) { @SuppressWarnings("unchecked") boolean value = (Boolean) aValue; if (value) { selected.add(rowIndex); } else { selected.remove(rowIndex); } super.fireTableCellUpdated(rowIndex, columnIndex); } else { tableModel.setValueAt(aValue, rowIndex, columnIndex - 1); } } @Override public void addTableModelListener(TableModelListener listener) { super.addTableModelListener(listener); tableModel.addTableModelListener(listener); } @Override public void removeTableModelListener(TableModelListener listener) { super.removeTableModelListener(listener); tableModel.removeTableModelListener(listener); } private class OriginalModelAdapter implements TableModelListener { @Override public void tableChanged(TableModelEvent e) { if (e.getSource() != tableModel) { return; } if (e.getType() != TableModelEvent.DELETE) { return; } int newRowCount = tableModel.getRowCount(); boolean selectionUpdated = false; if (newRowCount < selectionBasedRowCount) { for (Iterator<Integer> iterator = selected.iterator(); iterator.hasNext(); ) { if (iterator.next() >= newRowCount) { iterator.remove(); selectionUpdated = true; } } } selectionBasedRowCount = newRowCount; if (selectionUpdated) { RowSelectableTableModel.super.fireTableDataChanged(); } } } }
RowSelectableTableModel proxy for TableModel
原文地址:http://blog.csdn.net/raistlic/article/details/38843887