DatePicker Cell Editor重置单元格编辑开始和停止的时间

DatePickerCellEditor resets the time when cell editing starts and stops

我有一个 JXTable,其中两列包含字符串值,一列包含遵循以下格式的日期时间值:yyyy-MM-dd HH:mm:ss.

因为我只关心用户更改日期,所以我想我会使用带有自定义 SimpleDateFormat("yyyy-MM-dd HH:mm:ss").

的 Swingx 包中的 DatePickerCellEditor

到目前为止一切顺利,除了开始编辑时开始出现问题。日期时间的日期部分被保留,但是,它的时间部分被重置为“00:00:00”,更糟糕的是,当我移动到编辑另一个单元格时,保留在正在编辑的单元格中的值edited 是正确的日期,但是时间在 00:00:00.

也就是说,这个 becomes this

我尝试了很多方法来解决这个问题,包括从 DatePickerCellEditor 覆盖 getTableCellEditorComponent 并直接从 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 仅适用于日期,但我自然认为只要用户不更改日期,它就会保留时间。

天哪,我想我做到了。经过大量挖掘,问题出在 JXDatePicker 内部的 JXMonthView 组件。简而言之,它使用了错误的选择模型。为了使其正常工作,我们需要实例化一个新的 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,因此无法编辑源文件。如果使用可编辑的源文件,最好的解决方案自然是简单地取消该行的注释。