3

I have a JTextArea which is uneditable under a certain setting. However, under this setting the user can still use the space and backspace keys. To accommodate the space, I have the following code,

if (e.getKeyChar() == KeyEvent.VK_SPACE) {
    editor.insert(" ", editor.getCaretPosition());
}

I'm having an issue with backspace though. I've tried this,

if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE) {
    editor.insert("\b", editor.getCaretPosition());
}

That seems to add a tiny space when backspace is pressed. It's not as much as a space, and it's almost unnoticeable when pressed once. It's definitely not a backspace though. Worse case I'll have to copy all the characters up to the caret position - 1 and append them to all the characters after the caret position, but I don't like that solution.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
gsgx
  • 12,020
  • 25
  • 98
  • 149
  • Just looked at an interface I wrote a while ago, and I (as you say) used **if(!s.equals("")) s = s.substring(0, s.length() - 1);** (my interface did not require a carat) Also: I don't know if JTextArea handles it for you, but you might want to watch out for Alt, Tab, Escape, Control etc (anything not caught by **KeyEvent.isActionKey()** will also cause a teeny space to be inserted (a non-printable character). – lynks Apr 22 '12 at 00:48

1 Answers1

3

Use Key Bindings to allow the space and backspace keys to have associated actions, and then remove a character from the JTextArea's Document if backspace has been pressed.

For example,

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

@SuppressWarnings("serial")
public class TextAreaFun extends JPanel {
   public static final String SPACE = "space";
   public static final String BACK_SPACE = "back space";
   private JTextArea textArea = new JTextArea(15, 50);

   public TextAreaFun() {
      // create our key bindings
      // only allow key presses to initiate an action if the JTextArea has focus
      int condition = JComponent.WHEN_FOCUSED;
      InputMap taInputMap = textArea.getInputMap(condition);
      ActionMap taActionMap = textArea.getActionMap();

      taInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), SPACE);
      taInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
            BACK_SPACE);
      taActionMap.put(SPACE, new KeyAction(textArea, SPACE));
      taActionMap.put(BACK_SPACE, new KeyAction(textArea, BACK_SPACE));

      // checkbox that stops all editing except for that specified in the 
      // key bindings above
      JCheckBox chkBox = new JCheckBox(new AbstractAction("Prevent Editing") {
         {
            putValue(SELECTED_KEY, Boolean.FALSE); // default to unchecked
            putValue(MNEMONIC_KEY, KeyEvent.VK_P);
         }

         @Override
         public void actionPerformed(ActionEvent evt) {
            boolean selection = (Boolean) getValue(SELECTED_KEY);
            textArea.setEditable(!selection);
         }
      });
      JPanel bottomPanel = new JPanel();
      bottomPanel.add(chkBox);

      setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
      add(new JScrollPane(textArea));
      add(Box.createVerticalStrut(10));
      add(bottomPanel);
   }

   private static void createAndShowGui() {
      TextAreaFun mainPanel = new TextAreaFun();

      JFrame frame = new JFrame("TextAreaFun");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
// action to be initiated by key bindings
class KeyAction extends AbstractAction {
   private PlainDocument textAreaDocument;
   private String title;

   public KeyAction(JTextArea textArea, String title) {
      this.textAreaDocument = (PlainDocument) textArea.getDocument();
      this.title = title;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      if (title.equals(TextAreaFun.SPACE)) {
         try {
            textAreaDocument.insertString(textAreaDocument.getLength(), " ",
                  null);
         } catch (BadLocationException e1) {
            e1.printStackTrace();
         }
      } else if (title.equals(TextAreaFun.BACK_SPACE)) {
         if (textAreaDocument.getLength() == 0) {
            return;
         }
         try {
            textAreaDocument.remove(textAreaDocument.getLength() - 1, 1);
         } catch (BadLocationException e1) {
            e1.printStackTrace();
         }
      }
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Thanks it works. Unfortunately, since the textarea is uneditable, I get that annoying high pitched sound on Windows that tells you you're trying to edit something that's uneditable. You wouldn't happen to know how to get rid of that, would you? – gsgx Apr 22 '12 at 04:43
  • @gsingh2011: You're welcome. My code above works for me, and I don't get that sound, so I can't offer any suggestion until I can reproduce this somehow. Consider creating and posting an [sscce](http://sscce.org), similar to what I have posted above, one that reproduces this problem, and then comment to me, and I'll have a look at it. – Hovercraft Full Of Eels Apr 22 '12 at 13:55