How can i sort java JTable with an empty Row and force the Empty row always be last?

后端 未结 5 885
心在旅途
心在旅途 2020-12-18 16:49

I am using JTable with an empty row at the bottom of the table in order to give the ability of adding new line to the table.

After insert or writing data in the empt

5条回答
  •  清歌不尽
    2020-12-18 17:07

    I found another solution by subclassing only TableRowSorter.

    From the DefaultRowSorter documentation we know :

    The Comparator is never passed null

    When subclassing DefaultRowSorter.ModelWrapper, we can return a special Null-Object and create a custom comparator handling that value.

    Here follows my code. Probably it is not as efficient as a custom RowSorter implementation and it may still contain some bugs, I did not test everything, but for my requirements it works.

    class EmptyTableRowSorter extends TableRowSorter {
    
        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 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 {}
    
    }
    

    Now you can enable sorting in your table.

    JTable table = ...;
    TableRowSorter tableRowSorter = new EmptyTableRowSorter(table.getModel());
    table.setRowSorter(tableRowSorter);
    

提交回复
热议问题