5

I have a JTextArea. I have a function that selects some amount of text when some combination is called. It's done properly. The thing is, I want to move caret to the selection beginning when some text is selected and VK_LEFT is pressed. KeyListener is implemented properly, I tested it in other way. The thing is, that when I write following code:

@Override public void keyPressed( KeyEvent e) {
        if(e.getKeyChar()==KeyEvent.VK_LEFT)
            if(mainarea.getSelectedText()!=null)
                mainarea.setCaretPosition(mainarea.getSelectionStart());
    }

and add an instance of this listener to mainarea, select some text (using my function) and press left arrow key, the caret position is set to the end of selection... And I wont it to be in the beginning... What's the matter? :S

nicks
  • 2,161
  • 8
  • 49
  • 101
  • 1
    don't use KeyListeners, it's a no-no-never ;-) instead, use keybindings .. – kleopatra May 10 '11 at 14:18
  • IIRC, you can set the caret to the beginning when you set the selection. For that you have to set selection from the end position to the start position. Thus, when user presses the left key, the caret will be at the start of slection. Isn't it what you want to achieve? – jfpoilpret May 10 '11 at 14:41

1 Answers1

8

Here's a code snippet

    Action moveToSelectionStart = new AbstractAction("moveCaret") {

        @Override
        public void actionPerformed(ActionEvent e) {
            int selectionStart = textComponent.getSelectionStart();
            int selectionEnd = textComponent.getSelectionEnd();
            if (selectionStart != selectionEnd) {
                textComponent.setCaretPosition(selectionEnd);
                textComponent.moveCaretPosition(selectionStart);
            }
        }

        public boolean isEnabled() {
            return textComponent.getSelectedText() != null;
        }
    };
    Object actionMapKey = "caret-to-start";
    textComponent.getInputMap().put(KeyStroke.getKeyStroke("LEFT"), actionMapKey);
    textComponent.getActionMap().put(actionMapKey, moveToSelectionStart);

Note: it's not recommended to re-define typically installed keybindings like f.i. any of the arrow keys, users might get really annoyed ;-) Better look for some that's not already bound.

kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • 2
    +1, for Key Bindings. Hopefully one of these days people will forget about KeyListeners. Although I would extend TextAction to be consistent with the Actions defined in the editor kits. Then you can use getFocusedComponent() to get the text component to act on. – camickr May 10 '11 at 14:53
  • I guess I need to clarify myself again :) In general, I would extend AbstractAction when using Key Bindings on Swing components. However, when adding actions to text components, I would extend TextAction. – camickr May 10 '11 at 15:18
  • @camickr - that's how I understood you :-) Here the requirement is a bit pathological, anyway. – kleopatra May 10 '11 at 15:25
  • @camickr and kleopatra- Why do you do it this way instead of using the Keymap for the text component and the "addActionForKeyStroke" method? Pros and cons to each approach? – harmanjd Dec 19 '12 at 14:52
  • 1
    @harmanjd that's the old api (deprecated? don't remember), for textComponents only. The newer style keyBindings are for all JSomething and more flexible. Note that internally, everything registered to a keyMap is wrapped to fit into the input/actionMap – kleopatra Dec 19 '12 at 15:28
  • Ahh - thanks. It isn't marked deprecated and I've seen code with both on different sites. So - just wanted to know which was better. Thanks for the clarification. – harmanjd Dec 20 '12 at 04:48