像其他Swing模型(即DefaultComboBoxModel,DefaultListModel)一样,我们可以使用泛型来创建灵活且可重用的表模型,还提供与用户定义的POJO一起使用的API。
该表模型将具有以下特殊功能:
- 它从
AbstractTableModel
利用表模型事件处理的优势扩展而来。 - 与
CustomerTableModel
上面显示的不同,此表模型必须是抽象的,因为它不能重写getValueAt()
方法:仅仅因为我们不知道该表模型将处理的类或数据类型,重写上述方法的任务留给了子类。 - 它继承了的空
setValueAt()
实现AbstractTableModel
。这是有道理的,因为isCellEditable()
它也从该类继承并始终返回false
。 - 的默认实现
getColumnClass()
也被继承,并且始终返回Object.class
。
这些功能使此表模型真正易于实现,具体取决于我们的要求:
- 如果我们需要显示一个只读表,那么我们必须重写2种方法top:
getValueAt()
和getColumnClass()
(这是推荐的,但不是强制性的)。 - 如果我们的表需要可编辑,那么我们必须重写top的4种方法:上面提到的两个加号
isCellEditable()
和setValueAt()
。
让我们看一下表模型的代码:
import java.util.ArrayList;import java.util.Collections;import java.util.List;import javax.swing.table.AbstractTableModel;public abstract class DataObjectTableModel<T> extends AbstractTableModel { private final List<String> columnNames; private final List<T> data; public DataObjectTableModel() { this.data = new ArrayList<>(); this.columnNames = new ArrayList<>(); } public DataObjectTableModel(List<String> columnIdentifiers) { this(); if (columnIdentifiers != null) { this.columnNames.addAll(columnIdentifiers); } } @Override public int getRowCount() { return this.data.size(); } @Override public int getColumnCount() { return this.columnNames.size(); } @Override public String getColumnName(int columnIndex) { return this.columnNames.get(columnIndex); } public void setColumnNames(List<String> columnNames) { if (columnNames != null) { this.columnNames.clear(); this.columnNames.addAll(columnNames); fireTableStructureChanged(); } } public List<String> getColumnNames() { return Collections.unmodifiableList(this.columnNames); } public void addDataObject(T dataObject) { int rowIndex = this.data.size(); this.data.add(dataObject); fireTableRowsInserted(rowIndex, rowIndex); } public void addDataObjects(List<T> dataObjects) { if (!dataObjects.isEmpty()) { int firstRow = data.size(); this.data.addAll(dataObjects); int lastRow = data.size() - 1; fireTableRowsInserted(firstRow, lastRow); } } public void insertDataObject(T dataObject, int rowIndex) { this.data.add(rowIndex, dataObject); fireTableRowsInserted(rowIndex, rowIndex); } public void deleteDataObject(int rowIndex) { if (this.data.remove(this.data.get(rowIndex))) { fireTableRowsDeleted(rowIndex, rowIndex); } } public void notifyDataObjectUpdated(T domainObject) { T[] elements = (T[])data.toArray(); for (int i = 0; i < elements.length; i++) { if(elements[i] == domainObject) { fireTableRowsUpdated(i, i); } } } public T getDataObject(int rowIndex) { return this.data.get(rowIndex); } public List<T> getDataObjects(int firstRow, int lastRow) { List<T> subList = this.data.subList(firstRow, lastRow); return Collections.unmodifiableList(subList); } public List<T> getDataObjects() { return Collections.unmodifiableList(this.data); } public void clearTableModelData() { if (!this.data.isEmpty()) { int lastRow = data.size() - 1; this.data.clear(); fireTableRowsDeleted(0, lastRow); } }}
因此,采用此表模型和
Customer类,一个完整的实现将如下所示:
String[] header = new String[] {"Entry date", "Name", "Address", "Phone number"};DataObjectTableModel<Customer> model = new DataObjectTableModel<>(Arrays.asList(header)) { @Override public Class<?> getColumnClass(int columnIndex) { switch (columnIndex) { case 0: return Date.class; case 1: return String.class; case 2: return String.class; case 3: return String.class; default: throw new ArrayIndexOutOfBoundsException(columnIndex); } } @Override public Object getValueAt(int rowIndex, int columnIndex) { Customer customer = getDataObject(rowIndex); switch (columnIndex) { case 0: return customer.getEntryDate(); case 1: return customer.getName(); case 2: return customer.getAddress(); case 3: return customer.getPhoneNumber(); default: throw new ArrayIndexOutOfBoundsException(columnIndex); } } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return true; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (columnIndex < 0 || columnIndex >= getColumnCount()) { throw new ArrayIndexOutOfBoundsException(columnIndex); } else { Customer customer = getDataObject(rowIndex); switch (columnIndex) { case 0: customer.setEntryDate((Date)aValue); break; case 1: customer.setName((String)aValue); break; case 2: customer.setAddress((String)aValue); break; case 3: customer.setPhoneNumber((String)aValue); break; } fireTableCellUpdated(rowIndex, columnIndex); } }};
如我们所见,在几行代码(LOC <50)中,我们有一个完整的实现。
它适用于JPA实体吗?
只要实体具有公共获取者和设置者,它就起作用。与JPA实现不同,此表模型不适用于反射,因此我们必须使用类的公共接口来实现
getValueAt()和
setValueAt()方法来访问对象属性。它可以与JDBC一起使用吗?
不,不是。我们将不得不将结果集包装到域类中,并使用如上所述的类提供的接口。
它适用于Java默认类吗?是的,它确实。再次使用class提供的界面。例如,让
java.io.File我们上课,我们可以实现以下表模型实现:
String[] header = new String[] { "Name", "Full path", "Last modified", "Read", "Write", "Execute", "Hidden", "Directory"};DataObjectTableModel<File> model = new DataObjectTableModel<File>(Arrays.asList(header)) { @Override public Class<?> getColumnClass(int columnIndex) { switch (columnIndex) { case 0: return String.class; case 1: return String.class; case 2: return Date.class; case 3: return Boolean.class; case 4: return Boolean.class; case 5: return Boolean.class; case 6: return Boolean.class; case 7: return Boolean.class; default: throw new ArrayIndexOutOfBoundsException(columnIndex); } } @Override public Object getValueAt(int rowIndex, int columnIndex) { File file = getDataObject(rowIndex); switch (columnIndex) { case 0: return file.getName(); case 1: return file.getAbsolutePath(); case 2: return new Date(file.lastModified()); case 3: return file.canRead(); case 4: return file.canWrite(); case 5: return file.canExecute(); case 6: return file.isHidden(); case 7: return file.isDirectory(); default: throw new ArrayIndexOutOfBoundsException(columnIndex); } }};
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)