tags:

views:

134

answers:

3

Hi all,

I've added a keylistener to my JTextArea field, but it doesn't behave as I expected.

inputTextArea.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent k) {
  //If the return button is hit, only set to a new line if shift is also down.
  if(k.getKeyChar() == KeyEvent.VK_ENTER) {
   if(k.isShiftDown()) {
    inputTextArea.append(" \n");
   } else {
    //Send The Message...
    boolean cleanTextField = false;
    try {
     sendMessage(inputTextArea.getText());
     cleanTextField = true;
     msgScrollPane.setAutoscrolls(true);

     JScrollBar vbar = msgScrollPane.getVerticalScrollBar();
     if ((vbar.getValue() + vbar.getVisibleAmount()) == vbar.getMaximum()) {
      msgPane.setCaretPosition(msgDoc.getLength());
     }
    } catch (Exception ex) {
     ex.printStackTrace();
     cleanTextField = false;
    } finally {
     if(cleanTextField) {
      inputTextArea.setText("");
     }
    }
   }
  }
 }
});

I want this: - If the return button is hit and shift is down: add a new line. - If the return button is hit and the shift button isn't down: no new line, but submit.

Now it behaves like this: - If I hit the return button and shift is down: no line added. Nothing happens. - If I hit the return button and shift isn't down: submitted, but if I start typing again it begins on new line.

Does someone know how to do what I want?

EDIT:

I tried some other code to detect if the shift button is down:

                    if((k.getModifiersEx() == KeyEvent.SHIFT_DOWN_MASK) || 
                            (k.getModifiers() == KeyEvent.SHIFT_DOWN_MASK)) {

This doesn't work as well

+1  A: 

Try using keyTyped and not keyPressed. I beleive keyPressed gives you an event for the shift and for the enter, whereas keyTyped gives you one combined event with a modifier.

Pace
This doesn't solve my problems. They are excact the same.
dododedodonl
A: 

Instead of doing the actions immediately on receiving the event, sequence them for later by posting them using SwingUtilities.invokeLater(). The code should look like:

if(k.isShiftDown()) {
   SwingUtilities.invokeLater(new Runnable() {
      public void run() {
         inputTextArea.append(" \n");
      }
   });
} else {
   SwingUtilities.invokeLater(new Runnable() {
      public void run() {
          //rest of the else body here
      }
   });

}

In my opinion, the problems seen here are because application-defined actions and internal actions are not being properly sequenced, leading to repaints happening before the text has been modified.

Karthik Shiraly
I tried this one. I keep the same results.Now I see that the JTextArea is in a JScrollPane. Could this have an effect?
dododedodonl
+2  A: 

You may use the InputMap and ActionMap of the JTextArea to map the key strokes to actions:

private static final String TEXT_SUBMIT = "text-submit";
private static final String INSERT_BREAK = "insert-break";
...
private void initialize() {
    InputMap input = inputTextArea.getInputMap();
    KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
    KeyStroke shiftEnter = KeyStroke.getKeyStroke("shift ENTER");
    input.put(shiftEnter, INSERT_BREAK);  // input.get(enter)) = "insert-break"
    input.put(enter, TEXT_SUBMIT);

    ActionMap actions = inputTextArea.getActionMap();
    actions.put(TEXT_SUBMIT, new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            submitText();
        }
    });
}
...
private void submitText() {
    // TODO
}  

The original action for ENTER - "insert-break" - is used for shift ENTER.

Carlos Heuberger
Thanks! This is the solution I needed!!!
dododedodonl