DatePickerCellEditor сбрасывает время начала и окончания редактирования ячейки

У меня есть JXTable с двумя столбцами, содержащими строковые значения, и одним столбцом, содержащим значение даты и времени в следующем формате: yyyy-MM-dd HH:mm:ss.

Поскольку меня волнует только то, что пользователи изменят дату, я решил использовать DatePickerCellEditor из пакета Swingx с пользовательским SimpleDateFormat("yyyy-MM-dd HH:mm:ss").

Пока все хорошо, за исключением того, что проблемы начинают возникать при запуске редактирования. Часть даты и времени сохраняется, однако часть времени сбрасывается на «00:00:00» и, что еще хуже, когда я перехожу к редактированию другой ячейки, значение, которое остается в ячейке, которая была отредактировано - правильная дата, но время в 00:00:00.

Другими словами, этот Before edit становится введите здесь описание изображения

Я пробовал многое, чтобы исправить это, в том числе переопределить getTableCellEditorComponent из DatePickerCellEditor и распечатать дату непосредственно из JXDatePicker. Я обнаружил, что где-то по пути временная часть дня сбрасывалась на «00:00:00». Я не мог узнать, где. Затем я попытался в getTableCellEditorComponent вручную установить дату с помощью JXDatePicker#setDate, но это тоже не сработало.

Один обходной путь, который я нашел, заключался в том, что внутри getTableCellEditorComponent вызывался JXDatePicker#getEditor и вручную устанавливалась дата, однако временная часть значения ячейки по-прежнему сбрасывалась при остановке редактирования.

public class SQLDatePickerCellEditor extends DatePickerCellEditor {

    public SQLDatePickerCellEditor(DateFormat dateFormat) {
        super(dateFormat);
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        JXDatePicker picker = (JXDatePicker) super.getTableCellEditorComponent(table, value, isSelected, row, column);
        picker.getEditor().setText(value.toString());
        System.out.println(picker.getDate()); //this prints the correct date but for some reason at 00:00:00
        return picker;
    }

}

Вот пример кода для работы:

public class DateForm extends javax.swing.JFrame {

    public DateForm() {
        initComponents();
        pack();
        setLocationRelativeTo(null);
        initModel();
    }

    public void initModel() {
        Class<?>[] types = new Class<?>[]{String.class, String.class, Date.class};
        Object[][] data = new Object[][]{
            {"John", "Smith", new Date(System.currentTimeMillis())}
        };
        DefaultTableModel model = new DefaultTableModel(data, new String[]{"Name", "Surname", "Date"}) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                return types[columnIndex];
            }
        };

        table.setModel(model);
        table.getColumn(2).setCellEditor(new DatePickerCellEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")));
        StringValue sv = new FormatStringValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        TableCellRenderer r = new DefaultTableRenderer(sv);
        table.getColumn(2).setCellRenderer(r);
    }

    @SuppressWarnings("unchecked")                      
    private void initComponents() {

        scrPane = new javax.swing.JScrollPane();
        table = new org.jdesktop.swingx.JXTable();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setPreferredSize(new java.awt.Dimension(500, 500));
        scrPane.setViewportView(table);

        getContentPane().add(scrPane, java.awt.BorderLayout.CENTER);
    }                     

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                DateForm df = new DateForm();
                df.setVisible(true);
            }
        });
    }

    private javax.swing.JScrollPane scrPane;
    private org.jdesktop.swingx.JXTable table;               

}

Это поведение предназначено? Я знаю, что JXDatePicker предназначен только для дат, но я, естественно, предположил, что он сохранит время, пока пользователь не изменит дату.


person Morgan    schedule 10.01.2018    source источник
comment
Мне интересно, проблема в том, что значение даты равно String, но редактор может ожидать значение Date   -  person MadProgrammer    schedule 11.01.2018
comment
Нет, к сожалению, это не так. Я просто изменил тип массива данных на Object и присвоил ему Date в качестве третьего значения, но поведение осталось точно таким же. В любом случае, для полноты картины я только что обновил пример кода, чтобы отразить это изменение.   -  person Morgan    schedule 11.01.2018


Ответы (1)


О боже, кажется, я сделал это. После МНОГО копания проблема заключается в компоненте JXMonthView, который находится внутри JXDatePicker. Короче говоря, он использует неправильную модель выбора. Чтобы он работал правильно, нам нужно создать новый экземпляр SingleDaySelectionModel и передать его в JXMonthView.

Документация по методу JXDatePicker#setDate, который дал мне ответ на мою проблему:

Sets the date property.

Does nothing if the ui vetos the new date - as might happen if the code tries to set a date which is unselectable in the monthView's context. The actual value of the new Date is controlled by the JXMonthView's DateSelectionModel. The default implementation normalizes the date to the start of the day in the model's calendar's coordinates, that is all time fields are zeroed. To keep the time fields, configure the monthView with a SingleDaySelectionModel.

Инициализация по умолчанию в JXDatePicker.java — как видите, нужная нам строка закомментирована:

private void initMonthView() {
    _monthView = new JXMonthView();
    //        _monthView.setSelectionModel(new SingleDaySelectionModel());
    _monthView.setTraversable(true);
    _monthView.addPropertyChangeListener(getMonthViewListener());
}

Поскольку наследование от JXDatePicker было невозможно, я создал собственный CellEditor следующим образом:

public class SQLDatePickerCellEditor extends DatePickerCellEditor {

    public SQLDatePickerCellEditor() {
        super(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        datePicker.getMonthView().setSelectionModel(new SingleDaySelectionModel());
    }

}

Это экономит время по мере необходимости.

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

person Morgan    schedule 11.01.2018