jtextarea is showing character for a moment when character is masked which shouldn't

75 Views Asked by At

I have a requirement where I am entering input in JTextarea at run time and input should be masked. I am able to achieve this through below code snippet

if(encryptKeystroke == true) {
            jTextArea.addKeyListener(new KeyListener() {
                public void keyTyped(KeyEvent e) {
                }

                public void keyPressed(KeyEvent e) {
                    if (e.getExtendedKeyCode() == KeyEvent.VK_BACK_SPACE) {
                        if(text.length() > 0)
                         text = text.substring(0, text.length() - 1);
                    }
                    else {
                        text += String.valueOf(e.getKeyChar());
                    }
                    jTextArea.setText(text.replaceAll(".", "*"));

                }
                public void keyReleased(KeyEvent e) {
                    jTextArea.setText(text.replaceAll(".", "*"));
                }
            });
        }

Issue is when I am running this, entered character is visible for a small moment and then getting masked(like it happened in Android). I am using JTextarea because unable to achieve the scrollable & wrapstyle in Ttextfield. Any suggestion how this can be achieved ?

1

There are 1 best solutions below

2
camickr On

Don't use a KeyListener for something like this. What if the user:

  1. pastes text into the text area. The code won't handle multiple characters
  2. moves the caret to the beginning of the text area. The code assumes text is always added at the end.
  3. uses the Delete key
  4. highlights a block of text and then enters a character

A KeyListener can't handle all these special situations. Swing has better and newer API's to use.

Instead you can use a DocumentFilter. The DocumentFilter allows you to filter the text BEFORE it is added to the Document of the JTextArea.

Basic example:

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;

public class AsteriskFilter extends DocumentFilter
{
    private StringBuilder realText = new StringBuilder();

    @Override
    public void insertString(FilterBypass fb, int offset, String text, AttributeSet attributes)
        throws BadLocationException
    {
        replace(fb, offset, 0, text, attributes);
    }

    @Override
    public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attributes)
        throws BadLocationException
    {
        //  Update the StringBuilder to contain the real text

        Document doc = fb.getDocument();
        realText.replace(offset, offset + length, text);

        //  Update the Document with asterisks

        text = text.replaceAll(".", "*");
        super.replace(fb, offset, length, text, attributes);
    }

    @Override
    public void remove(DocumentFilter.FilterBypass fb, int offset, int length)
        throws BadLocationException
    {
        realText.delete(offset, offset + length);

        super.remove(fb, offset, length);
    }

    public String getRealText()
    {
        return realText.toString();
    }

    private static void createAndShowGUI()
    {
        JTextArea textArea = new JTextArea(3, 20);
        AbstractDocument doc = (AbstractDocument) textArea.getDocument();
        AsteriskFilter filter = new AsteriskFilter();
        doc.setDocumentFilter( filter );

        JButton button = new JButton("Display Text");
        button.addActionListener(e -> JOptionPane.showMessageDialog(textArea, filter.getRealText()));

        JFrame frame = new JFrame("Asterisk Filter");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(textArea, BorderLayout.CENTER);
        frame.add(button, BorderLayout.PAGE_END);
        frame.setSize(220, 200);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args) throws Exception
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }

}