Hot questions for Using JTextField in documentfilter

Top Java Programmings / JTextField / documentfilter

Question:

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?


Answer:

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();
         }
      });
   }
}

Question:

Is it to possible to capitalize the FIRST letter in a Textfield

E.g. The user would type 'hello' and 'Hello' would appear in the Textfield.

I fined this code to capitalize all letter http://www.java2s.com/Tutorial/Java/0240__Swing/FormatJTextFieldstexttouppercase.htm

and I try to edit it to capitalize only the FIRST letter put it is wrong

this is my edit

public class UppercaseDocumentFilter extends DocumentFilter {

public void insertString(DocumentFilter.FilterBypass fb, int offset, String text,AttributeSet attr) throws BadLocationException {
    fb.insertString(offset, text.substring(0, 1).toUpperCase() + text.substring(1), attr);
  }

  public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text,AttributeSet attrs) throws BadLocationException {
    fb.replace(offset, length, text.substring(0, 1).toUpperCase() + text.substring(1), attrs);
  }

}

Answer:

You're on the right direction, you might have a look at fb.getDocument().getLength() to determine the current length of the Document, when it's 0, update the first character of the text

You might then be able to use something like...

String text = "testing";
StringBuilder sb = new StringBuilder(text);
sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
text = sb.toString();
System.out.println(text);

to capitalize the first character of the input text. You might want to do some other checks, but that's the basic idea

Example

Seems to work okay for me

public class UppercaseDocumentFilter extends DocumentFilter {

    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
        if (fb.getDocument().getLength() == 0) {
            StringBuilder sb = new StringBuilder(text);
            sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
            text = sb.toString();
        }
        fb.insertString(offset, text, attr);
    }

    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
        if (fb.getDocument().getLength() == 0) {
            StringBuilder sb = new StringBuilder(text);
            sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
            text = sb.toString();
        }
        fb.replace(offset, length, text, attrs);
    }

}

Question:

I'm working with Java swing program. I want to insert in my JPanel, a JTextFieldFormat with a limit number of character and that convert all text in UPPER text. So I have build this code:

textCodiceFiscale = new JTextField();
textCodiceFiscale.setDocument(new PersonalizzaJtextField(numberCharacter));
DocumentFilter filter = new UppercaseDocumentFilter();
        ((AbstractDocument) textCodiceFiscale.getDocument()).setDocumentFilter(filter);

this is the UppercaseDocumentFilter class:

class UppercaseDocumentFilter extends DocumentFilter {
    public void insertString(DocumentFilter.FilterBypass fb, int offset,
        String text, AttributeSet attr) throws BadLocationException {

    fb.insertString(offset, text.toUpperCase(), attr);
    }

    public void replace(DocumentFilter.FilterBypass fb, int offset, int length,
        String text, AttributeSet attrs) throws BadLocationException {

    fb.replace(offset, length, text.toUpperCase(), attrs);
    }
}

This is PersonalizzaJTextField class:

public class PersonalizzaJtextField extends PlainDocument {

    //private StringBuffer cache = new StringBuffer();
    private int lunghezzaMax;

    public PersonalizzaJtextField(int lunghezzaMax){
        super();
        this.lunghezzaMax = lunghezzaMax;       
    }

    public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException{
        if (str == null)
            return;

        if ((getLength() + str.length()) <= lunghezzaMax) {
            super.insertString(offset, str, attr);
        }   
    }
}

Now the problems are two:

1) with this code, I can insert only UPPER character in my JTextField but I the second line to limit number of Character, not works.

2) I want create a template for this JTextField, I must insert number or text in this mode:

6 characters 2 numbers 1 character 2 numbers 1 character 3 numbers 1 character.

Is possible to do this?


Answer:

I want create a template for this JTextField, I must insert number or text in this mode:

Use a JFormattedTextField. You can use a MaskFormatter to have the JFormattedTextField do the editing for you. With a proper mask you can specify numbers or upper case characters.

Read the section from the Swing tutorial on How to Use Formatted Text Fields for more information and examples.

By the way the formatted text field creates the DocumentFilter for you automatically using the MaskFormatter, so you need a custom filter.

Bookmark the tutorial. You were also given a link to the tutorial in your last question on this topic. Use the tutorial for Swing basics.

Question:

class MyDocumentFilter extends DocumentFilter {

@Override
public void replace(FilterBypass fb, int i, int i1, String string, AttributeSet as) throws BadLocationException {

    for (int n = string.length(); n > 0; n--) {//an inserted string may be more than a single character i.e a copy and paste of 'aaa123d', also we iterate from the back as super.XX implementation will put last insterted string first and so on thus 'aa123d' would be 'daa', but because we iterate from the back its 'aad' like we want
        char c = string.charAt(n - 1);//get a single character of the string

        if (Character.isAlphabetic(c) || c == ' ') {//if its an alphabetic character or white space
            super.replace(fb, i, i1, String.valueOf(c), as);//allow update to take place for the given character
        } else {//it was not an alphabetic character or white space

        }

    }

}

@Override
public void remove(FilterBypass fb, int i, int i1) throws BadLocationException {
    super.remove(fb, i, i1);

}

@Override
public void insertString(FilterBypass fb, int i, String string, AttributeSet as) throws BadLocationException {
    super.insertString(fb, i, string, as);

}

}

I added this in JTextField. Now I want to clear JTextField text on button click. This is how I'm filling form

thanks in advance**


Answer:

Is because i used DocumentFilter on JTextField its not removing the text from JtextField. Text will be removed with DocumentFilter remove() method

    try {
        txtFirstName.getDocument().remove(0, txtFirstName.getText().length());
    } catch (BadLocationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Question:

Problem: I want to know whether can we get the JTextfield type from the DocumentFilter?? I have read java docs and searched a lot but did not find any information.

Need: I set same DocumentFilter on 2 JTextfields. When the event occur, in the "replace" method of DocumentFilter, I want to know action on which textfield resulted in the event.

Use Case: I have near about 15 texfields(may increase in future) and I want separate checks on all which are: - maximum text length for input - only certain characters must be entered(this will be same for all textfields) For e.g: textfield1 can take maximum 10 chars but textfield2 can take maximum 5 chars.

What I have done so far: I have created separate filters for every textfield which results in lots of redundant code and increases complexity to handle, for future use.

Looking forward for any help. :-)


Answer:

Ok, now your need is more clear but, once again, you can't (and you should not) check which textfield are you typing in from inside the DocumentFilter to decide what to do in your replace () method.

Possible solution: create your own DocumentFilter class, passing all the parameters you need (maximum text length, and maybe an array of forbidden characters, or whatever else). All your textfields will have a distinct DocumentFilter instance, with the parameters set in order to suit your needs. This way you will have a clean solution without reduntant code.

For example:

import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
public class FilterTextField
{
    public static void main (String [] a) {
        SwingUtilities.invokeLater (new Runnable () {
            @Override public void run () {
                createAndShowGUI ();
            }
        });
    }
    private static void createAndShowGUI () {
        JFrame frame = new JFrame ("Test");
        frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        frame.setContentPane (new MainPanel ());
        frame.pack ();
        frame.setLocationRelativeTo (null);
        frame.setVisible (true);
    }
}
class MainPanel extends JPanel
{
    public MainPanel () {
        super (new GridLayout (3, 1, 0, 20));

        JTextField t1 = new JTextField (20);
        JTextField t2 = new JTextField (20);
        JTextField t3 = new JTextField (20);

        ((AbstractDocument) t1.getDocument ()).setDocumentFilter (new MyDocumentFilter (5));
        ((AbstractDocument) t2.getDocument ()).setDocumentFilter (new MyDocumentFilter (10, '!', '?'));
        ((AbstractDocument) t3.getDocument ()).setDocumentFilter (new MyDocumentFilter (15, new char [] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}));

        add (t1);
        add (t2);
        add (t3);

        setBorder (new EmptyBorder (20, 20, 20, 20));
    }


}
class MyDocumentFilter extends DocumentFilter
{
    private char [] forbiddenCharacters;
    private int maximumLength;

    public MyDocumentFilter (int maximumLength, char ... forbiddenCharacters) {
        this.maximumLength = maximumLength;
        this.forbiddenCharacters = forbiddenCharacters;
    }
    @Override public void replace (FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
        // Get the full text you would have after replacement
        Document document = fb.getDocument ();
        String fullText = new StringBuilder (document.getText (0, document.getLength ())).replace (offset, offset + length, text).toString ();
        // Check your requirements ...
        if (fullText.length () <= maximumLength) {
            if (forbiddenCharacters != null) {
                for (char c : forbiddenCharacters) if (fullText.indexOf (c) > -1) return;
            }
            // Replace method is called only if your requirements are met.
            super.replace (fb, offset, length, text, attrs);
        }
    }
}

Question:

I have extended DocumentFilter class to limit the number of characters to be entered to the specified number in text field. Here's my SSCE:

Main class:

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.net.*;
import java.io.*;
import java.util.Date;
import java.util.StringTokenizer;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.text.PlainDocument;

public class Sandbox implements Runnable {
    private JFrame frame;
    private JTextField inputField;
    private JButton searchButton; 
    private int MAX_CHAR_LIMIT = 1;

    public Sandbox() {
        inputField = new JTextField(); 
        inputField.setColumns(10);
        inputField.setFont(new Font(null, Font.BOLD, 20));
    }

    @Override
    public void run() {
        frame = new JFrame("SSCE");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(500, 300));

        PlainDocument doc = (PlainDocument) inputField.getDocument();
        doc.setDocumentFilter(new DocumentCharLimitFilter(MAX_CHAR_LIMIT));
        frame.getContentPane().setLayout(new FlowLayout());
        frame.getContentPane().add(inputField);

        frame.pack();
        frame.setVisible(true);
    }

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

}

DocumentCharLimitFilter class

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class DocumentCharLimitFilter extends DocumentFilter {

    private int MAX_CHAR_LIMIT;

    public DocumentCharLimitFilter(int maxChars) {
        this.MAX_CHAR_LIMIT = maxChars;
    }

    // You don't need insertString() when entering text in JTextField. 
    @Override
public void replace(FilterBypass fb, int offset, int length, String newText, AttributeSet aSet) throws BadLocationException {
    int oldTextLength = fb.getDocument().getLength();
    String oldText = fb.getDocument().getText(0, oldTextLength);
    String combinedText = oldText + newText;        

    if (combinedText.length() <= MAX_CHAR_LIMIT) {
        super.replace(fb, offset, length, newText, aSet);

        // paste characters upto maximum allowed limit 
    } else if (oldTextLength < MAX_CHAR_LIMIT) {
        int cutPosition = MAX_CHAR_LIMIT - oldTextLength;
        String cutToFit = newText.substring(0, cutPosition);
        super.replace(fb, offset, length, cutToFit, aSet);

    } else {
        System.out.println("Character limit of " + MAX_CHAR_LIMIT + " exceeded.");
    }
}
}

When I fire up the above program and try to paste some new character on top of existing character using Ctrl+V, it takes me to else loop of replace() method of DocumentCharLimitFilter and I get:

Character limit of 1 exceeded.

From what I understand through all this, the new character that I am pasting using mouse and Ctrl+V is taken as additional character on top of existing character and I get the above message. When I use keyboard to input characters, it works just fine. If I increase the MAX_CHAR_LIMIT to 2, I can paste in the text but now when I give input from keyboard, I am able to input two characters which I don't want.

How do I make the above code such that it works like normal pasting on top of existing text and replacing it, using Ctr + V and still limiting the keyboard characters to the specified limit? I am a beginner to Java. If I need to provide any information, I would be glad to do so. Thank you.

Update: @camickr, @VGR thank you so much! I didn't pay attention to the length argument in replace() method. This is what I did in DocumentCharLimitFilter class:

@Override
public void replace(FilterBypass fb, int offset, int length, String newText, AttributeSet aSet) throws BadLocationException {
    System.out.println(fb.getClass());
    int oldTextLength = fb.getDocument().getLength();
    String oldText = fb.getDocument().getText(0, oldTextLength);
    String combinedText = oldText + newText;

    if (combinedText.length() <= MAX_CHAR_LIMIT) {
        super.replace(fb, offset, length, newText, aSet);

        // paste characters upto maximum allowed limit 
    } else if (oldTextLength < MAX_CHAR_LIMIT) {
        int cutPosition = MAX_CHAR_LIMIT - oldTextLength;
        String cutToFit = newText.substring(0, cutPosition);
        super.replace(fb, offset, length, cutToFit, aSet);

        // NEW CODE 
        // http://stackoverflow.com/questions/42512743/pasting-replacing-a-character-using-mouse-selection-in-java-textfield-with-spec
        // length indicates number of characters highlighted using mouse or keyboard. This will work only when 
        // the entire text is highlighted (if entire text is not highlighted, it would get complicated)
        // and when it is highlighted, I make sure that the new text to be pasted is within limits of the MAX_CHAR_LIMIT
    } else if (length == MAX_CHAR_LIMIT) {
        String correctedString = newText;
        if (newText.length() > MAX_CHAR_LIMIT) {
            correctedString = newText.substring(0, MAX_CHAR_LIMIT);
        }
        super.replace(fb, offset, length, correctedString, aSet);

    } else {
        System.out.println("Entered characters exceed specified limit of " + MAX_CHAR_LIMIT + "exceeded.");
    }
}

Answer:

You are ignoring the length argument passed to the replace method, which contains the number of existing characters being replaced.

If you highlight one or more characters in the JTextField, then type or paste some new text, length will contain a positive value. The new length of the JTextField’s content will be oldTextLength - length + newText.length() (unless you change it).