有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

swing如何使用空行对java JTable进行排序,并强制空行始终位于最后?

我使用JTable,在表的底部有一个空行,以便能够向表中添加新行

在空行中插入或写入数据后,我将自动在其下方添加一个新的空行。(假设它的行为类似于Microsoft visual tables)

我使用的是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;
            }

空行被排序为最小值,如果降序,它将是第一行(因为mult by-1),并且会导致很多问题

我可以跳过它,如果是空行(通常是最后一行),在降序模式下不乘以-1,它将是任何排序后的最后一行。 但问题是“比较”方法及其调用方“”内部类在默认行排序器中是私有的

有没有办法避免将空行排序并使其始终位于最后一行


共 (5) 个答案

  1. # 1 楼答案

    我知道这是一条旧线,但我被困在这里想办法。请让我知道,如果有一个新的方式之前没有提到。实际上这是我第一篇关于SO的帖子,但因为我花了很多时间寻找解决方案,所以我决定与大家分享

    我解决了排序问题,我没有使用“null”作为“新条目”,而是创建了一个特定的对象(在我的例子中,是从对象类本身创建的,但它可能是更具意义的东西,比如“newentrydonotcomparewithepleaseletmebelastenrybeghoudonotsortme”空类)

    比较时,我首先检查要比较的“对象”是否是对象。当然不是“instanceof”,而是(obj.getClass()==Object)。班级)如果是这种情况,请检查排序顺序并返回1或-1

    如果您发现任何问题,请随时发表评论。如果有人需要代码,我可以尝试创建一个小的工作版本

    干杯, 丹尼尔

  2. # 2 楼答案

    我尝试了一下,我想我找到了解决办法

    我没有在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);
            }
        }
    }
    
  3. # 3 楼答案

    我找到了另一个解决方案,只对子类化了TableRowSorter

    DefaultRowSorter文档中我们知道:

    The Comparator is never passed null

    子类化DefaultRowSorter时。ModelWrapper,我们可以返回一个特殊的空对象,并创建一个处理该值的自定义比较器

    下面是我的代码。可能它没有自定义行排序器实现那么高效,而且可能仍然包含一些bug,我没有测试所有东西,但根据我的需求,它可以工作

    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);
    
  4. # 4 楼答案

    DefaultRowSorter肯定有缺陷

    唯一的选择是基于DefaultRowsorter创建自己的RowSorter并纠正问题

  5. # 5 楼答案

    使用DefaultRowSorter的setComparator方法设置不同的比较器