javaswingjbuttonjtextfielddocumentfilter

Checking Text Backspace Issue


I made it where a button is disabled and the only way to enable it is to type text into a field.

Here is my code:

import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

class checkText extends DocumentFilter {
public void replace(DocumentFilter.FilterBypass fb, int offset, int length,         String text,
    AttributeSet attrs) throws BadLocationException {
    super.replace(fb, offset, length, text, attrs);
    main.enableButton();
   }
  }

public class main extends JFrame {
static JFrame inputFrame = new JFrame();
static JTextField myTextfield = new JTextField(10);
static JButton myButton = new JButton("Test");

public main() {
inputGUI();
}

private static void inputGUI() {
inputFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
inputFrame.setTitle("The INPUT");
inputFrame.setLayout(new FlowLayout());
inputFrame.setSize(640, 480);
inputFrame.setVisible(true);
inputFrame.setLocationRelativeTo(null);

inputFrame.add(myButton);

DocumentFilter filter = new checkText();
((AbstractDocument) myTextfield.getDocument()).setDocumentFilter(filter);
inputFrame.add(myTextfield);
myButton.setEnabled(false);
}

public static void enableButton() {
myButton.setEnabled(true);
}

public static void main(String args[]) { new main(); }
}

Whenever I backspace and erase all the text. The button is still active. How do I disable it back when there are no text inside the field?


Solution

  • Your DocumentFilter never checks the Document or what affect the filter's methods would have on the Document so you shouldn't be surprised that it's not working. Your also only overriding one out of the three DocumentFilter methods. Also, your main class has an enableButton() but there's no way for outside classes to disable the button. ....

    Myself, I wouldn't use a DocumentFilter but rather a DocumentListener since you want to check the Document after the text changes have been registered, not before, and so using a DocumentFilter would only confuse the issue. I'd simply check the length of the text in the Document and that would be all that was needed. To get the Document, call getDocument() on the DocumentEvent object passed into all overridden methods. Then simply call getLength() on this. If it's > 0, enable the button, else disable it.

    e.g.,

    import javax.swing.*;
    import javax.swing.event.DocumentEvent;
    import javax.swing.event.DocumentListener;
    import javax.swing.text.Document;
    
    
    public class Main2 extends JPanel {
       private JButton testButton = new JButton("Test");
       private JTextField textField = new JTextField(11);
    
       public Main2() {
          add(testButton);
          add(textField);
    
          testButton.setEnabled(false);
          textField.getDocument().addDocumentListener(new DocumentListener() {
    
             @Override
             public void removeUpdate(DocumentEvent e) {
                checkDoc(e);
             }
    
             @Override
             public void insertUpdate(DocumentEvent e) {
                checkDoc(e);
             }
    
             @Override
             public void changedUpdate(DocumentEvent e) {
                checkDoc(e);
             }
    
             private void checkDoc(DocumentEvent e) {
                Document doc = e.getDocument();
                testButton.setEnabled(doc.getLength() > 0);
             }
          });
       }
    
       private static void createAndShowGui() {
          Main2 mainPanel = new Main2();
    
          JFrame frame = new JFrame("Main2");
          frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
             }
          });
       }
    }