6

I think that the JTable component should do a better job of filtering the keys that would start editing. I mean, with the current implementation, if you type DEL, Ctrl+Shift+DEL, F5, F7, for example, in an editable cell, the cell editor will appear. In my opinion, start a cell editor with keys like these is very non-intuitive for the end user.

Also, there's another problem: JTable isn't aware of the other possible key bindings defined in the form. If you have a key binding Ctrl+Shift+C defined for a button on your form, if you type this key combination in your JTable, the table will start editing and them your button key binding action will be called next. I think that there should be an easy way to prevent this instead of disabling all those already defined key bindings in your table key binding mapping.

Is there some third party component that already solved, at least partly, some of these issues, specially the one to start editing with a reasonable key? I wouldn't like to do all the tedious filtering myself.

Any help would be appreciated. Thank you.

Marcos

UPDATE

For the time being I'm using this highly imperfect "solution", that at least makes things less worse for the moment. Improvements, comments and suggestions are appreciated.

    @Override
    public boolean isCellEditable(EventObject e)
    {
        if (e instanceof MouseEvent)
        {
            return ((MouseEvent) e).getClickCount() >=
                _delegate.getMouseClickCountToStartEditing();
        }
        else if (e instanceof KeyEvent)
        {
            KeyEvent event = (KeyEvent) e;

            int key = event.getKeyCode();
            if ((key >= KeyEvent.VK_F1 && key <= KeyEvent.VK_F12) &&
                KeyStroke.getKeyStrokeForEvent(event) != _startEditingKey)
            {
                return false;
            }

            int ctrlAlt = KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK;
            if ((event.getModifiersEx() & ctrlAlt) == ctrlAlt)
            {
                return true;
            }

            if ((event.getModifiersEx() & ctrlAlt) != 0)
            {
                return false;
            }

            return true;
        }
        else
        {
            // Is this else really needed? Are there other events types
            // other than mouse and key events?
            return true;
        }
    }

    // _startEditingKey is obtained with this method
    private KeyStroke getStartEditingKey()
    {
        InputMap bindings = TheTable.this.getInputMap(
            JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        for (KeyStroke key : bindings.allKeys())
        {
            Object binding = bindings.get(key);
            if ("startEditing".equals(binding))
            {
                return KeyStroke.getKeyStroke(
                    key.getKeyCode(), key.getModifiers(), true);
            }
        }
        return null;
    }
Marcos
  • 1,237
  • 1
  • 15
  • 31
  • Please edit your question to include an [sscce](http://sscce.org/) that shows the specific problem you are having. – trashgod Apr 20 '13 at 14:30
  • Sorry. I think that an sscce is needless in this case. The problem is already well described by my text. – Marcos Apr 20 '13 at 14:42

2 Answers2

4

You can implement a custom editor which reports not being editable if the keyEvent has modifiers you want to ignore:

DefaultCellEditor editor = new DefaultCellEditor(new JTextField()) {

    @Override
    public boolean isCellEditable(EventObject e) {
        if (e instanceof KeyEvent) {
            return startWithKeyEvent((KeyEvent) e);
        }
        return super.isCellEditable(e);
    }

    private boolean startWithKeyEvent(KeyEvent e) {
        // check modifiers as needed, this here is just a quick example ;-)
        if ((e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
            return false;
        }    
        // check for a list of function key strokes
        if (excludes.contains(KeyStroke.getKeyStrokeForEvent(e)) {
            return false;
        } 
        return true;
    }

};
JTable table = new JTable(new AncientSwingTeam());
table.setDefaultEditor(Object.class, editor);

Edit: for a more reliable filtering which can handle the ctrl-alt combinations correctly, you might have a look into DefaultEditorKit.DefaultKeyTypedAction: while basically delegating to a hidden method in the SunToolkit and handling keyTyped (vs. keyPressed needed for filtering the events that are probable candidates for a valid printable character after having started the edit) it might still give you an idea of how to do it (source of the suntoolkit are most probably available in openjdk, didn't search there, though)

kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • Fortunately I use custom cell editors for all my table columns. But I think that I don't need to resort to them to solve this issue. I think that I can do better with the overriden _editCellAt_ method (remember that there I can also access the _KeyEvent_ event). But the check to see which key combinations would pass is error prone by a programmer. That's what I'm trying to avoid. See my answer to @trashgod below. I will try that alternative and see if it works. Thank you for the reply. – Marcos Apr 20 '13 at 15:09
  • well, the editor api is _designed_ to decide whether or not an arbitrary event should start the edit: so that's definitely the place to do it (*not* in the table, editCellAt only should query the editor) And no, I don't see much a problem concerning key combinations: you will have to check against modifiers that shouldn't trigger anything plus a set of function keys which are easy to pass into the editor as a list of keyStrokes that can be checked against – kleopatra Apr 20 '13 at 15:19
  • Ok, I agree you're right about the editor api. My code can also be there without any problem. But with the key combinations it is not so easy like this. For example, in my keyboard, if I type Ctrl+Alt+a I will get an `á` character. So the problem is not just to filter some control key combinations. I have to know which one would produce a valid character. This issue is difficult and I don't see any easy way to get rid of it. – Marcos Apr 20 '13 at 15:27
  • Thanks. I'll have a look at it. – Marcos Apr 20 '13 at 15:53
  • I don't understand the problem of overriding `editCellAt` of the table. The API for the method simply states it should return false if for any reason the editing cannot be done. Why can't you do this at a table level? Why are you suggesting you must duplicate this logic for every cell editor used by the table? I would think the place to override depends on the requirement, table level or editor level. – camickr Apr 20 '13 at 16:38
  • @camickr Regarding the duplication, you don't need to duplicate any code. Just one custom cell editor class used in all table cells with constructors for the multiple kind of components, like _DefaultCellEditor_. – Marcos Apr 20 '13 at 17:01
  • @kleopatra: Works on Aqua L&F. I've previously observed that Aqua has no default binding for `startEditing`, e.g. `F2`. I never noticed that `DEL, F5, & F7` work. I'm not sure how that happens, so I'm not sure how to defeat it. – trashgod Apr 20 '13 at 19:39
  • @camickr editCell is responsible for the overall logic (like can we start at all, taking f.i. the editability of the cell and the willingness of a potentially current editor to stop) - the details of which event actually can is delegated to the editor. – kleopatra Apr 20 '13 at 22:29
  • Why can't the view just make the decision itself? Why must it delegate? If the view makes the decision then the decision is the same for all editors that will ever be added to the table. If you let the editor make the decision, then in the future it is possible another column will be added to the table with a different editor and the person may not know to use the custom editor. Now you have inconsistent behaviour between editors. – camickr Apr 20 '13 at 22:45
  • @camickr the view cant know - editors _do_ BTW, that's nothing I decided, just what the original swing team thought appropriate. The underlying problem might be historical: before jdk (whatever? forgot) a keyevent wasn't passed into the editor. Consequently, any effort the editor took to reject events simply didn't work - and (guessing me here) the implementation of default editor never improved to cope .. – kleopatra Apr 20 '13 at 22:55
1

You can bind any desired key to the table's startEditing action, as shown here and here. You can disable undesired keys, as shown here. Some additional nuances are shown here and the article cited here by @camickr.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • The problem, as I said, is that the list of undesired keys to disable is enormous. I'm thinking of creating a invisible fake JTextField filled with 5 characters and dispatch the key event in the _editCellAt_ method (overriden) to it. If the fake field text change, it is a valid, editable key. If it doesn't change, it is not a valid key, so I return _false_ from the _editCellAt_ method. What do you think? – Marcos Apr 20 '13 at 14:39
  • @Marcos whats wrong with F2 implemented in JTable API, otherwise to change that – mKorbel Apr 20 '13 at 14:49
  • 1
    @mKorbel I'm not complaining about the F2 key. I'm just complaining about the other keys. The F2 key will continue to be allowed to start editing. – Marcos Apr 20 '13 at 14:51
  • before anything to check [KeyBindings](http://tips4java.wordpress.com/2008/10/10/key-bindings/) by @camickr, change required Key(s)_ShortCuts – mKorbel Apr 20 '13 at 14:54
  • @mKorbel Had already checked that before. The technical stuff is not the problem to me in this case. The problem is good alternatives to solve my issue. I think that I will give a chance to the fake JTextField alternative to see if it will solve my problem. Theoretically it seems that it will work. – Marcos Apr 20 '13 at 14:58
  • see post by @kleopatra, maybe ...., but wihtout changed for described concurency JTable & JButton, but most of KeyBindings corresponding with accelerators in MsOffice products (could not be an argument why don't do that) – mKorbel Apr 20 '13 at 15:08
  • @mKorbel & Marcos: I've previously observed that Aqua L&F has no default binding for `startEditing`, e.g. `F2`. I never noticed that `DEL, F5, & F7` work. I'm not sure how that happens, so I'm not sure how to defeat it. – trashgod Apr 20 '13 at 19:32