我正在使用JTable,在表格的底部有一个空行,以便能够在表格中添加新行。
在空行中插入或写入数据后,我自动添加一个新的空行。 (它假设像Microsoft视觉表一样)
我正在使用java默认行排序器
问题是我需要空行一直是最后一行!但在对表格进行排序后,它将成为第一行。
DefaultRowSorter 类的 compare(int model1,int model2)“方法获得2个行号,如果第一行的值为1,则返回-1如果第二行的值为null,则返回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;
}
空行被排序为最小值,并且DESCENDING将是第一行(因为mult乘以-1)并导致很多问题。
我可以覆盖它,并且在DESCENDING模式下,空行(通常是最后一行)不会多次-1,它将是任何排序后的最后一行。 但问题是“比较”方法及其调用者“行”内部类在 DefaultRowSorter 中是私有的。
有没有办法避免排空空行并使其始终排在最后一行?
答案 0 :(得分:5)
我尝试了一下,我想我找到了解决方案。
我没有在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);
}
}
}
答案 1 :(得分:2)
DefaultRowSorter肯定存在缺陷。
唯一的选择是根据DefaultRowsorter创建自己的RowSorter并更正问题。
答案 2 :(得分:1)
我通过仅仅 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);
答案 3 :(得分:0)
我知道这是一个旧线程,但我被困在这里试图找到一种方法。如果有一种以前没有提到的新方法,请告诉我。实际上这是我关于SO的第一篇文章,但由于我花了很多时间为此寻找解决方案,我决定分享。
我解决了这个排序问题,而不是使用'null'作为我的'新条目',我创建了一个特定的对象(在我的情况下来自Object类本身,但它可能更像是'NewEntryDoNotCompareWithMePleaseLetMeBeTheLastEntryIBegYouDoNotSortMe'空的东西类)。
比较时,我首先检查要比较的'对象'是否是对象。当然不是'instanceof',而是(obj.getClass()== Object.class)。 - 如果是这种情况,请检查排序顺序并返回1或-1。
随意评论您发现的任何问题,如果有人需要代码,我可以尝试创建一个小工作版本。
干杯, 丹尼尔
答案 4 :(得分:-2)
使用DefaultRowSorter的setComparator方法设置不同的比较器。