2

In my Java panel I have a JTable in which two of the columns use the JDateChooser object, from the package com.toedter.calendar, via a custom cell editor. Unlike cells that use text boxes or other simple components, which you can type into without having to click the cell beforehand, this functionality is not present on date-chooser cells. As far as my current understanding goes, this is because my custom editor's returns the JDateChooser object as the component (via the getTableCellEditorComponent method). Since JDateChooser's parent class is JPanel (according to the API), that's what it's trying to edit, and of course, you can't type text into a JPanel. Is there some way to detect when the user tabs over to a date-chooser cell and tries to type a date into it?

P.S. I did manage a sort of workaround by requesting focus on the date chooser's text field, but the catch is that the first key you type doesn't appear in the cell; it just starts editing the cell. If possible, I would like it to behave so that you can tab over to the cell, type "1" once, for example, and have "1" appear in it, as with a regular text field cell.

dic19
  • 17,821
  • 6
  • 40
  • 69
Kevin M.
  • 21
  • 3
  • 1
    I think you need your own editor for cell read how do it in [tutorial](http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#editrender) – alex2410 Nov 20 '13 at 07:07
  • I don't have this library so I can't test it but I have an idea: try returning `dateChooser.getSpinner()` in the `getTableCellEditorComponent()` implementation. As I can understand from the (poor) API documentation this should return the `JSpinner` which is used to edit the Date. – dic19 Nov 20 '13 at 13:44
  • I wasn't able to call the getSpinner() method in my code. Apparently it was removed in a later version and the API was never changed. But I see your point, and I had in fact tried to call the editor component (in our case, an extention of JTextFieldDateEditor). However, while this did let me type in numbers without me needing to focus on the text component directly, the calendar button did not show up (it was not returned by the method), and we can't have that. – Kevin M. Nov 20 '13 at 16:41

2 Answers2

2

Apparently it was removed in a later version and the API was never changed.

You're right, I've noticed the API is outdated since it's from 1.2.1 version and latest version of JCalendar is 1.4 I guess they don't have time to update the online version of the API, but the javadoc distributed with the library is updated. The thing is getSpinner() is not available anymore so my previuos suggestion is unreachable.

Anyway I've decided to try a DateCellEditor using JDateChooser on my own and I've had not much troubles to make it work except I've experienced the same behavior as you do when you start to type in the cell. It seems like the focus is transferred to the JDateChooser top level component (as you say it's probably a JPanel). So I made use of the AncestorListener API to transfer the focus to the date editor. This approach is well explained in this post by @camickr.

This is what I've made:

public class DateCellEditor extends AbstractCellEditor implements TableCellEditor {

    JDateChooser editor;

    public DateCellEditor() {
        editor = new JDateChooser();
        editor.setLocale(Locale.ENGLISH);
        editor.setDateFormatString("MM/dd/yyyy");
        editor.setFocusable(false); // Key #1

        JComponent editorComponent = (JComponent)editor.getDateEditor();
        editorComponent.addAncestorListener(new AncestorListener() { // Key #2

            @Override
            public void ancestorAdded(AncestorEvent event) {
                ((JComponent)editor.getDateEditor()).requestFocusInWindow();
            }

            @Override
            public void ancestorRemoved(AncestorEvent event) {}

            @Override
            public void ancestorMoved(AncestorEvent event) {}

        });
    }

    ....
}

There are two key factors here:

  1. Making the editor not focusable. This way you'll be avoiding the focus be automatically transferred to the top level container that is part of it.
  2. Using the AncestorListener API.

Here is the complete cell editor implementation:

import com.toedter.calendar.JDateChooser;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import java.util.Locale;
import javax.swing.AbstractCellEditor;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.table.TableCellEditor;

public class DateCellEditor extends AbstractCellEditor implements TableCellEditor {

    JDateChooser editor;
    int clickCountToStart = 2;

    public DateCellEditor() {
        editor = new JDateChooser();
        editor.setLocale(Locale.ENGLISH);
        editor.setDateFormatString("MM/dd/yyyy");
        editor.setFocusable(false);

        JComponent editorComponent = (JComponent)editor.getDateEditor();
        editorComponent.addAncestorListener(new AncestorListener() {

            @Override
            public void ancestorAdded(AncestorEvent event) {
                ((JComponent)editor.getDateEditor()).requestFocusInWindow();
            }

            @Override
            public void ancestorRemoved(AncestorEvent event) {}

            @Override
            public void ancestorMoved(AncestorEvent event) {}

        });
    }

    @Override
    public Object getCellEditorValue() {
        return editor.getDate();
    }    

    @Override
    public boolean isCellEditable(EventObject anEvent) {
        if (anEvent instanceof MouseEvent) {
            return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
        }
        return true;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        return true;
    }

    @Override
    public boolean stopCellEditing() {
        fireEditingStopped();
        return true;
    }

    @Override
    public void cancelCellEditing() {
        fireEditingCanceled();
    }




    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        if(value instanceof java.util.Date){
            editor.setDate((java.util.Date)value);
            table.setRowHeight((int)editor.getPreferredSize().getHeight());
            //This last one is optional. It fits the row height to the JDateChooser preferred height.
        }
        return editor;
    }
}
Community
  • 1
  • 1
dic19
  • 17,821
  • 6
  • 40
  • 69
  • That solution does help me edit the cell with the keyboard only. However, like my original fix, it still won't register the first digit entered, i.e. a date entered as "05012014" will display as "50/12/014_". To get around this, I'm thinking I might have to overwrite the JDateChooser itself and add a listener there. Thoughts? – Kevin M. May 19 '14 at 15:42
0
datepicker.getEditor().setEditable(true);
chiragchavda.ks
  • 532
  • 7
  • 25