Как я могу отсортировать java JTable с пустой строкой и заставить пустую строку всегда быть последней? - PullRequest
1 голос
/ 23 февраля 2010

Я использую JTable с пустой строкой внизу таблицы, чтобы дать возможность добавлять новую строку в таблицу.

После вставки или записи данных в пустую строку я автоматически добавляю новую пустую строку под ней. (Предполагается, что он действует как визуальные таблицы Microsoft)

Я использую сортировщик строк Java по умолчанию,

Проблема в том, что мне нужно, чтобы пустая строка всегда была последней! но после сортировки таблицы она становится первой строкой.

Метод * сравнить (int model1, int model2)"класса DefaultRowSorter получает 2 номера строки и возвращает -1, если значение первой строки равно нулю и 1, если значение второй строки равно нулю. и в случае DESCENDING его умножить на -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) и вызывает множество проблем.

Я мог бы переопределить его, и если пустая строка (обычно последняя строка) не умножается на -1 в режиме DESCENDING, и это будет последняя строка после любой сортировки. Но проблема в том, что метод " сравни " и его вызывающий " Row " внутренний класс являются закрытыми внутри DefaultRowSorter .

Есть ли способ избежать сортировки пустой строки и сделать ее всегда последней строкой?

Ответы [ 5 ]

5 голосов
/ 23 февраля 2010

Я попробовал, и думаю, что нашел решение.

Вместо создания этой пустой строки в 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);
        }
    }
}
2 голосов
/ 23 февраля 2010

DefaultRowSorter определенно имеет недостатки.

Единственный вариант - создать свой собственный RowSorter на основе DefaultRowsorter и исправить проблему.

1 голос
/ 17 ноября 2014

Я нашел другое решение только по подклассам TableRowSorter .

Из документации DefaultRowSorter , которую мы знаем:

Компаратор никогда не передается ноль

При создании подкласса DefaultRowSorter.ModelWrapper мы можем вернуть специальный Null-объект и создать пользовательский компаратор , обрабатывающий это значение.

Здесь следует мой код. Возможно, он не так эффективен, как пользовательская реализация 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);
0 голосов
/ 07 апреля 2013

Я знаю, что это старая ветка, но я застрял здесь, пытаясь найти способ. Пожалуйста, дайте мне знать, если есть новый способ, не упомянутый ранее. На самом деле это мой первый пост на SO, но, поскольку я потратил много времени на поиск решения, я решил поделиться им.

Я решил эту проблему упорядочения, вместо того, чтобы использовать 'null' в качестве моей 'новой записи', я создал конкретный объект (в моем случае из самого класса Object, но это может быть что-то более значимое, например 'NewEntryDoNotCompareWithMePleaseLetMeBeTheLastEntryIBegLouDoNotSortMe' empty) класс).

При сравнении я сначала проверяю, является ли объект, который сравнивается, объектом. Конечно, не instanceof, но (obj.getClass () == Object.class). - Если это так, проверьте порядок сортировки и верните 1 или -1.

Не стесняйтесь комментировать любые проблемы, которые вы обнаружите с этим, я могу попытаться создать небольшую рабочую версию, если кому-то понадобится код.

Ура, Daniel

0 голосов
/ 23 февраля 2010

Установите другой компаратор, используя метод setComparator DefaultRowSorter.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...