[英]How can i sort java JTable with an empty Row and force the Empty row always be last?
我正在使用JTable,表底部有一个空行,以便能够向表中添加新行。
在空行中插入或写入数据后,我将在其下方自动添加一个新的空行。 (它的行为类似于Microsoft可视表)
我正在使用Java默认行排序器,
问题是我一直需要空行成为最后一行! 但对表格进行排序后,它成为第一行。
DefaultRowSorter类的“ compare(int model1,int model2) ”方法获取2行号,如果第一行的值为null,则返回-1,如果第二行的值为null,则返回1。 如果将其降级,则将其乘以-1即可得到倒序。
//Treat nulls as < then non-null
if (v1 == null) {
if (v2 == null) {
result = 0;
} else {
result = -1;
}
} else if (v2 == null) {
result = 1;
} else {
result = sortComparators[counter].compare(v1, v2);
}
if (sortOrder == SortOrder.DESCENDING) {
result *= -1;
}
空行被排序为最小值,如果降序,它将是第一行(由于倍数为-1),因此会引起很多问题。
我可以覆盖它,以防空行(通常是最后一行)在DESCENDING模式下不乘-1,并且它将是任何排序后的最后一行。 但是问题在于,“ compare ”方法及其调用方“ Row ”内部类在DefaultRowSorter内部是私有的。
有没有一种方法可以避免对空行进行排序并使它始终是最后一行?
我尝试了一下,我想找到了解决方案。
我没有在TableModel
中创建该空行,而是在JTable
对其进行了伪造,并且仅在用户实际输入一些数据时才创建它。
RowSorter
仅对TableModel
行进行排序,因此我们的行不受影响,并保留为最后一行。
public class NewLineTable extends JTable {
@Override
public int getRowCount() {
// fake an additional row
return super.getRowCount() + 1;
}
@Override
public Object getValueAt(int row, int column) {
if(row < super.getRowCount()) {
return super.getValueAt(row, column);
}
return ""; // value to display in new line
}
@Override
public int convertRowIndexToModel(int viewRowIndex) {
if(viewRowIndex < super.getRowCount()) {
return super.convertRowIndexToModel(viewRowIndex);
}
return super.getRowCount(); // can't convert our faked row
}
@Override
public void setValueAt(Object aValue, int row, int column) {
if(row < super.getRowCount()) {
super.setValueAt(aValue, row, column);
}
else {
Object[] rowData = new Object[getColumnCount()];
Arrays.fill(rowData, "");
rowData[convertColumnIndexToModel(column)] = aValue;
// That's where we insert the new row.
// Change this to work with your model.
((DefaultTableModel)getModel()).addRow(rowData);
}
}
}
DefaultRowSorter肯定有缺陷。
唯一的选择是基于DefaultRowsorter创建自己的RowSorter并更正问题。
我通过仅子类化TableRowSorter找到了另一个解决方案。
从DefaultRowSorter文档中,我们知道:
比较器永不传递null
当对DefaultRowSorter.ModelWrapper进行子类化时,我们可以返回一个特殊的Null-Object并创建一个处理该值的自定义比较器 。
这是我的代码。 可能它不像自定义RowSorter实现那样高效,并且它可能仍然包含一些错误,我没有测试所有东西,但是对于我的要求,它可以工作。
class EmptyTableRowSorter<M extends AbstracTableModel> extends TableRowSorter<M> {
private static final EmptyValue emptyValue = new EmptyValue();
public EmptyTableRowSorter(M model) {
super(model);
}
@Override
public void modelStructureChanged() {
// deletes comparators, so we must set again
super.modelStructureChanged();
M model = getModelWrapper().getModel();
for (int i = 0; i < model.getColumnCount(); i++) {
Comparator<?> comparator = this.getComparator(i);
if (comparator != null) {
Comparator wrapper = new EmptyValueComparator(comparator, this, i);
this.setComparator(i, wrapper);
}
}
}
@Override
public void setModel(M model) {
// also calls setModelWrapper method
super.setModel(model);
ModelWrapper<M, Integer> modelWrapper = getModelWrapper();
EmptyTableModelWrapper emptyTableModelWrapper = new EmptyTableModelWrapper(modelWrapper);
// calls modelStructureChanged method
setModelWrapper(emptyTableModelWrapper);
}
/**
* The DefaulRowSorter implementation does not pass null values from the table
* to the comparator.
* This implementation is a wrapper around the default ModelWrapper,
* returning a non null object for our empty row that our comparator can handle.
*/
private class EmptyTableModelWrapper extends DefaultRowSorter.ModelWrapper {
private final DefaultRowSorter.ModelWrapper modelWrapperImplementation;
public EmptyTableModelWrapper(ModelWrapper modelWrapperImplementation) {
this.modelWrapperImplementation = modelWrapperImplementation;
}
@Override
public Object getModel() {
return modelWrapperImplementation.getModel();
}
@Override
public int getColumnCount() {
return modelWrapperImplementation.getColumnCount();
}
@Override
public int getRowCount() {
return modelWrapperImplementation.getRowCount();
}
@Override
public Object getValueAt(int row, int column) {
M model = EmptyTableRowSorter.this.getModel();
// my model has the empty row always at the end,
// change this depending on your needs
int lastRow = model.getRowCount() - 1;
if (row == lastRow) {
return emptyValue;
}
return modelWrapperImplementation.getValueAt(row, column);
}
//@Override
//public String getStringValueAt(int row, int column) {
// // also override this if there is no comparator definied for a column
//}
@Override
public Object getIdentifier(int row) {
return modelWrapperImplementation.getIdentifier(row);
}
}
/**
* This is a wrapper around another comparator.
* We handle our empty value and if none, we invoke the base comparator.
*/
private class EmptyValueComparator implements Comparator {
private final Comparator defaultComparator;
private final TableRowSorter tableRowSorter;
private final int columnIndex;
public EmptyValueComparator(Comparator defaultComparator, TableRowSorter tableRowSorter, int columnIndex) {
this.defaultComparator = defaultComparator;
this.tableRowSorter = tableRowSorter;
this.columnIndex = columnIndex;
}
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof EmptyValue && o2 instanceof EmptyValue) {
return 0;
}
if (o1 instanceof EmptyValue) {
return adjustSortOrder(1);
}
if (o2 instanceof EmptyValue) {
return adjustSortOrder(-1);
}
return defaultComparator.compare(o1, o2);
}
/**
* Changes the result so that the empty row is always at the end,
* regardless of the sort order.
*/
private int adjustSortOrder(int result) {
List sortKeys = tableRowSorter.getSortKeys();
for (Object sortKeyObject : sortKeys) {
SortKey sortKey = (SortKey) sortKeyObject;
if (sortKey.getColumn() == columnIndex) {
SortOrder sortOrder = sortKey.getSortOrder();
if (sortOrder == SortOrder.DESCENDING) {
result *= -1;
}
return result;
}
}
return result;
}
}
private static class EmptyValue {}
}
现在,您可以在表格中启用排序。
JTable table = ...;
TableRowSorter tableRowSorter = new EmptyTableRowSorter(table.getModel());
table.setRowSorter(tableRowSorter);
我知道这是一个旧线程,但是我被困在这里试图寻找一种方法。 请让我知道是否有以前未提及的新方法。 实际上,这是我的第一篇关于SO的文章,但是由于我花了很多时间为我决定分享一个解决方案。
我解决了排序问题,而不是使用``空''作为我的``新条目'',而是创建了一个特定的对象(以我的Object类本身为例,但这可能更有意义,例如``NewEntryDoNotCompareWithMePleaseLetMeBeTheLastEntryIBegYouDoNotSortMe''空类)。
比较时,我首先检查要比较的“对象”是否为对象。 当然不是'instanceof',而是(obj.getClass()== Object.class)。 -如果是这种情况,请检查排序顺序并返回1或-1。
随便评论一下您发现的任何问题,如果有人需要代码,我可以尝试创建一个小型工作版本。
干杯,丹尼尔
使用DefaultRowSorter的setComparator方法设置其他比较器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.