I'm working with Java and I have a JTextField which can only have 4 digits. I'm using a class that extends DocumentFilter to filter out any other character, and to limit the number of characters to 4.
The problem is that once I have 4 digits, if I select all of them and try to overwrite them by typing another digit it doesn't auto overwrite and does nothing, I have to explicitly type "Backspace" or "Delete" in my keyboard to remove the 4 digits and then (once the field is clear) I can type again.
How can I make the JTextField act as the rest of the operating system that once I have some text selected if I type a character it “removes all, then writes the character” (it substitutes the contents).
I have one aux class, JustLimitDigitFilter.java:
import javax.swing.text.DocumentFilter;
import javax.swing.text.BadLocationException;
import java.awt.Toolkit;
import javax.swing.text.AttributeSet;
public class JustLimitDigitFilter extends DocumentFilter {
int limit;
public JustLimitDigitFilter(int limit) {
this.limit = limit;
}
@Override
public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
// if (text == null) {
// return;
// }
String str = text.replaceAll("\\D", "");
if (!str.isEmpty() && (fb.getDocument().getLength() + str.length()) <= limit) {
super.insertString(fb, offset, str, attr);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
@Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attr)
throws BadLocationException {
// if (text == null) {
// return;
// }
String str = text.replaceAll("\\D", "");
if (!str.isEmpty() && (fb.getDocument().getLength() + str.length()) <= limit) {
super.replace(fb, offset, length, str, attr);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}
And the main class, App.java:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JTextField;
import javax.swing.text.AbstractDocument;
import javax.swing.text.DocumentFilter;
public class App {
private JFrame frame;
private JTextField textField;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
App window = new App();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public App() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 191, 96);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBounds(6, 6, 179, 62);
frame.getContentPane().add(panel);
panel.setLayout(null);
textField = new JTextField();
textField.setBounds(6, 6, 167, 26);
panel.add(textField);
textField.setColumns(10);
// without this code below this, the textfield is “normal” when
// something is selected if I write it overwrites the selection
AbstractDocument doc = (AbstractDocument) textField.getDocument();
doc.setDocumentFilter(new JustLimitDigitFilter(4));
}
}
Any suggestion is welcome since I'm new to this, apart from the doubt I explicitly have.
Method
replace()in classDocumentFilteractually performs two operations. First it removeslengthcharacters starting atoffset, after which it insertstextatoffset. Hence the following line in yourreplace()method causes nothing to happen when theJTextFieldcontains the maximum allowable number of characters...If the
JTextFieldis full, then its length will be the maximum number of characters, so adding the length ofstrwill always be greater thanlimit.