Why does the DocumentFilter not give the intended result?
Asked Answered
D

1

5

I figure this must be a simple mistake in the code or a misunderstanding on my part, but I cannot get a DocumentFilter to detect insertString events. Below is a simple filter for upper case letters, but that is not as important as the fact that the insertString(..) method never seems to be called!

Why is the insertString(..) method of the DocumentFilter not called?

The filter is applied to the JTextField at the top. Every time insertString(..) is called, it should append information to the JTextArea in the CENTER. At the moment, there is no action in the text field that causes text to be appended to the text area.

enter image description here

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

public class FilterUpperCaseLetters {

    private JComponent ui = null;
    private final JTextField textField = new JTextField(25);
    private final JTextArea textArea = new JTextArea(5, 20);

    FilterUpperCaseLetters() {
        initUI();
    }

    public void initUI() {
        // The document filter that seems to do nothing.
        DocumentFilter capsFilter = new DocumentFilter() {
            @Override
            public void insertString(
                    DocumentFilter.FilterBypass fb,
                    int offset,
                    String string,
                    AttributeSet attr) throws BadLocationException {
                textArea.append("insertString! " + string + "\n");
                if (!string.toUpperCase().equals(string)) {
                    textArea.append("Insert!\n");
                    super.insertString(fb, offset, string, attr);
                } else {
                    textArea.append("DON'T insert!\n");
                }
            }
        };
        AbstractDocument abstractDocument
                = (AbstractDocument) textField.getDocument();
        abstractDocument.setDocumentFilter(capsFilter);

        ui = new JPanel(new BorderLayout(4, 4));
        ui.setBorder(new EmptyBorder(4, 4, 4, 4));

        ui.add(textField, BorderLayout.PAGE_START);
        ui.add(new JScrollPane(textArea), BorderLayout.CENTER);
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                FilterUpperCaseLetters o = new FilterUpperCaseLetters();

                JFrame f = new JFrame(o.getClass().getSimpleName());
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setLocationByPlatform(true);

                f.setContentPane(o.getUI());
                f.pack();
                f.setMinimumSize(f.getSize());

                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
Dowson answered 18/7, 2015 at 3:24 Comment(2)
"Why is insertString not called?" Why should it be? Have you tried seeing in what order the methods are called? insertString/remove/replace and seeing when the are called and maybe trying to see if you can determine in which conditions you need to apply your filter?Elonore
One needs to override replace as well :-)Hohenlohe
T
8

The text components use the replaceSelection(...) method which will in turn invoke the replace(...) method of the AbstractDocument which will invoke the replace(...) method of the DocumentFilter.

The insertString(...) method of the DocumentFilter is only called when you use the Document.insertString(...) method to directly update the Document.

So in reality you need to override both methods to make sure the upper case conversion is done.

A simple example showing how to easily implement both methods:

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

public class UpperCaseFilter extends DocumentFilter
{
    public void insertString(FilterBypass fb, int offs, String str, AttributeSet a)
        throws BadLocationException
    {
        replace(fb, offs, 0, str, a);
    }

    public void replace(FilterBypass fb, final int offs, final int length, final String text, final AttributeSet a)
        throws BadLocationException
    {
        if (text != null)
        {
            super.replace(fb, offs, length, text.toUpperCase(), a);
        }
    }

    private static void createAndShowGUI()
    {
        JTextField textField = new JTextField(10);
        AbstractDocument doc = (AbstractDocument) textField.getDocument();
        doc.setDocumentFilter( new UpperCaseFilter() );

        JFrame frame = new JFrame("Upper Case Filter");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout( new java.awt.GridBagLayout() );
        frame.add( textField );
        frame.setSize(220, 200);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args) throws Exception
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}
Triplenerved answered 18/7, 2015 at 3:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.