javaswingloopsinvokelaterswingutilities

DocumentListener method being called repeatedly


I've made a documentlistener that will call a method when text is inserted. It works but the problem is that it acts as if it's in a loop and is kept being called.
The method uses swingutilties.invokelater from inside the method.

   private void addNewLine() {
       SwingUtilities.invokeLater( () -> {
        textArea.append(System.getProperty("line.separator")+"hey");
       });
   }


    private final DocumentListener addNewLine = Handlers.forDocumentUpdate((event) -> {
         addNewLine();
    });

    @SuppressWarnings("serial")
    static DocumentListener forDocumentUpdate(Consumer<? super DocumentEvent> eventHandler) {
    return new DocumentListener() {
        @Override
        public void insertUpdate(DocumentEvent event) {
            eventHandler.accept(event);
        }
        @Override
        public void removeUpdate(DocumentEvent event) {
        }
        @Override
        public void changedUpdate(DocumentEvent event) {
        }
      };
    }

Solution

  • Before I had used DocumentListener to do the task, but there was a problem with recursive looping. The proper way is to add a DocumentFilter that will simply add a newline along with the code that inserts the original text to be inserted.

    ((AbstractDocument) textArea.getDocument()).
                setDocumentFilter(new NewLineFilter()); 
    
    public class NewLineFilter extends DocumentFilter {
    @Override
    public void insertString(FilterBypass fb,int offs,String str,AttributeSet a)
            throws BadLocationException {
    }
    @Override 
    public void replace(FilterBypass fb, int offs,int length, String str, AttributeSet a)
            throws BadLocationException {
        System.out.println("in replace");
        super.replace(fb,offs,length,str,a);
        super.insertString(fb, fb.getDocument().getLength(), System.lineSeparator(), a);
    }}
    

    If you know a better way to write this or If you know of a way to make a handler that would create an anonymous class for this that would be great. I couldn't use Consumer because replace() has more than one parameter. I could make another functional interface, but I don't know how useful it would be. I figure could potentially just reuse this class if I need to the same thing again.