How to make Jtable cell character length - java

I want to make my j table column to limit character like allowed only 16 character.I tried various methods nothing works.can anybody helps me?.

Here's what I did
The Call:
JTable table = new JTable();
JTextField textField = new JTextField();
limitCharacters(jtf, 16);
table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(jtf));
The limitCharacters Method:
private void limitCharacters(JTextField textField, final int limit) {
PlainDocument document = (PlainDocument) textField.getDocument();
document.setDocumentFilter(new DocumentFilter() {
#Override
public void replace(DocumentFilter.FilterBypass fb, int offset,
int length, String text, AttributeSet attrs)
throws BadLocationException {
String string = fb.getDocument().getText(0,
fb.getDocument().getLength())
+ text;
if (string.length() <= limit)
super.replace(fb, offset, length, text, attrs);
}
});
}

An answer found here https://community.oracle.com/thread/1482301
"Custom Cell Editors
http://java.sun.com/docs/books/tutorial/uiswing/components/table.html#validtext
and a custom document on a JTextField
One example worth thousand words"
import java.awt.*;
import javax.swing.*;
public class Test2 extends JFrame {
public Test2() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = getContentPane();
String[] head = {"One","Two","Three"};
String[][] data = {{"R1-C1", "12345678", "R1-C3"},
{"R2-C1", "R2-C2", "R2-C3"},
{"R3-C1", "R3-C2", "R3-C3"}};
JTable jt = new JTable(data, head);
content.add(new JScrollPane(jt), BorderLayout.CENTER);
JTextField jtf = new JTextField();
jtf.setDocument(new LimitedPlainDocument(10));
jt.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(jtf));
setSize(300,300);
}
public static void main(String[] args) { new Test2().setVisible(true); }
}
class LimitedPlainDocument extends javax.swing.text.PlainDocument {
private int maxLen = -1;
/** Creates a new instance of LimitedPlainDocument */
public LimitedPlainDocument() {}
public LimitedPlainDocument(int maxLen) { this.maxLen = maxLen; }
public void insertString(int param, String str,
javax.swing.text.AttributeSet attributeSet)
throws javax.swing.text.BadLocationException {
if (str != null && maxLen > 0 && this.getLength() + str.length() > maxLen) {
java.awt.Toolkit.getDefaultToolkit().beep();
return;
}
super.insertString(param, str, attributeSet);
}
}

Related

Using DocumentFilter iteratively

I am trying to run this code:
How to change the color of specific words in a JTextPane?
private final class CustomDocumentFilter extends DocumentFilter
{
private final StyledDocument styledDocument = yourTextPane.getStyledDocument();
private final StyleContext styleContext = StyleContext.getDefaultStyleContext();
private final AttributeSet greenAttributeSet = styleContext.addAttribute(styleContext.getEmptySet(), StyleConstants.Foreground, Color.GREEN);
private final AttributeSet blackAttributeSet = styleContext.addAttribute(styleContext.getEmptySet(), StyleConstants.Foreground, Color.BLACK);
// Use a regular expression to find the words you are looking for
Pattern pattern = buildPattern();
#Override
public void insertString(FilterBypass fb, int offset, String text, AttributeSet attributeSet) throws BadLocationException {
super.insertString(fb, offset, text, attributeSet);
handleTextChanged();
}
#Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
super.remove(fb, offset, length);
handleTextChanged();
}
#Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attributeSet) throws BadLocationException {
super.replace(fb, offset, length, text, attributeSet);
handleTextChanged();
}
/**
* Runs your updates later, not during the event notification.
*/
private void handleTextChanged()
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateTextStyles();
}
});
}
/**
* Build the regular expression that looks for the whole word of each word that you wish to find. The "\\b" is the beginning or end of a word boundary. The "|" is a regex "or" operator.
* #return
*/
private Pattern buildPattern()
{
StringBuilder sb = new StringBuilder();
for (String token : ALL_WORDS_THAT_YOU_WANT_TO_FIND) {
sb.append("\\b"); // Start of word boundary
sb.append(token);
sb.append("\\b|"); // End of word boundary and an or for the next word
}
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1); // Remove the trailing "|"
}
Pattern p = Pattern.compile(sb.toString());
return p;
}
private void updateTextStyles()
{
// Clear existing styles
styledDocument.setCharacterAttributes(0, yourTextPane.getText().length(), blackAttributeSet, true);
// Look for tokens and highlight them
Matcher matcher = pattern.matcher(yourTextPane.getText());
while (matcher.find()) {
// Change the color of recognized tokens
styledDocument.setCharacterAttributes(matcher.start(), matcher.end() - matcher.start(), greenAttributeSet, false);
}
}
}
And
((AbstractDocument) yourTextPane.getDocument()).setDocumentFilter(new CustomDocumentFilter());
I would like to use it iteratively, that is, that any new string ALL_WORDS_THAT_YOU_WANT_TO_FIND will be automatically colored. I thought of deleting
styledDocument.setCharacterAttributes(0, yourTextPane.getText().length(), blackAttributeSet, true);
(that is, to not destroy the previous colored words) but it does not work: it only keeps colored the input words given at the last iteration. How could I do that?
Edit: updated after two questions in the comments
So you want to add words to the list and update the JTextPane? In that case you would want to make sure that the list gets updated and used each time the updateTextStyles method runs.
You can use multiple lists of words that can apply unique formatting to the text. The code that you started with uses a regular expression, which you could expand to multiple regular expressions. You can also search for exact case sensitive matches of sub strings (or text fragments) without looking at word boundaries, as is used in the code below.
This means that the formatting of some text might be changed multiple times by matches from different groups. The order in which you search will determine the end result. For example, this small example allows you to fill a text pane and add new words to three highlight groups (with colors red, orange, and blue):
Here is the code of the three classes in the example (using Java 8):
IterativeDocumentFilter.java:
import java.awt.*;
import java.util.List;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.*;
public class IterativeDocumentFilter {
public static void main(String[] arguments) {
SwingUtilities.invokeLater(
() -> new IterativeDocumentFilter().createAndShowGui()
);
}
private void createAndShowGui() {
JFrame frame = new JFrame("Stack Overflow");
frame.setBounds(100, 100, 1000, 600);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel(new BorderLayout());
JTextPane textPane = new JTextPane(new DefaultStyledDocument());
CustomDocumentFilter documentFilter = new CustomDocumentFilter(textPane);
textPane.setBorder(new LineBorder(Color.BLACK, 1));
enlargeFont(textPane);
mainPanel.add(textPane, BorderLayout.CENTER);
mainPanel.add(createBottomPanels(documentFilter), BorderLayout.PAGE_END);
frame.getContentPane().add(mainPanel);
frame.setVisible(true);
}
private JPanel createBottomPanels(CustomDocumentFilter documentFilter) {
JPanel bottomPanels = new JPanel();
bottomPanels.setLayout(new BoxLayout(bottomPanels, BoxLayout.PAGE_AXIS));
for (HighlightGroup highlightGroup : documentFilter.getHighlightGroups()) {
List<String> textFragments = highlightGroup.getTextFragments();
JPanel groupPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
JLabel textFragmentsLabel = new JLabel("Current text fragments: "
+ textFragments);
textFragmentsLabel.setForeground(highlightGroup.getColor());
JLabel addTextFragmentLabel = new JLabel("Additional text fragment:");
addTextFragmentLabel.setForeground(highlightGroup.getColor());
JTextField addTextFragmentTextField = new JTextField(28);
JButton addTextFragmentButton = new JButton("Add text fragment");
addTextFragmentButton.setForeground(highlightGroup.getColor());
addTextFragmentButton.addActionListener(actionEvent -> {
String newTextFragment = addTextFragmentTextField.getText().trim();
if (!textFragments.contains(newTextFragment)) {
textFragments.add(newTextFragment);
documentFilter.handleTextChanged();
textFragmentsLabel.setText("Current text fragments: "
+ textFragments);
}
addTextFragmentTextField.setText("");
});
groupPanel.add(addTextFragmentLabel);
groupPanel.add(addTextFragmentTextField);
groupPanel.add(addTextFragmentButton);
textFragmentsLabel.setBorder(new EmptyBorder(0, 42, 0, 0));
groupPanel.add(textFragmentsLabel);
enlargeFont(addTextFragmentLabel);
enlargeFont(addTextFragmentTextField);
enlargeFont(addTextFragmentButton);
enlargeFont(textFragmentsLabel);
bottomPanels.add(groupPanel);
}
return bottomPanels;
}
private void enlargeFont(Component component) {
component.setFont(component.getFont().deriveFont(16f));
}
}
CustomDocumentFilter.java:
import java.awt.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.text.*;
public class CustomDocumentFilter extends DocumentFilter
{
private final JTextPane textPane;
private final List<HighlightGroup> highlightGroups;
private final StyleContext styleContext = StyleContext.getDefaultStyleContext();
private final AttributeSet blackAttributeSet
= styleContext.addAttribute(styleContext.getEmptySet(),
StyleConstants.Foreground, Color.BLACK);
public CustomDocumentFilter(JTextPane textPane) {
this.textPane = textPane;
highlightGroups = createHighlightGroups();
((AbstractDocument) textPane.getDocument()).setDocumentFilter(this);
}
private List<HighlightGroup> createHighlightGroups() {
List<HighlightGroup> groups = new ArrayList<>();
groups.add(new HighlightGroup(Arrays.asList("one", "two", "three"), Color.RED));
groups.add(new HighlightGroup(Arrays.asList("a", "the"), Color.ORANGE));
groups.add(new HighlightGroup(Arrays.asList("th", "o"), Color.BLUE));
return groups;
}
public List<HighlightGroup> getHighlightGroups() {
return highlightGroups;
}
#Override
public void insertString(FilterBypass fb, int offset, String text,
AttributeSet attributeSet) throws BadLocationException {
super.insertString(fb, offset, text, attributeSet);
handleTextChanged();
}
#Override
public void remove(FilterBypass fb, int offset, int length)
throws BadLocationException {
super.remove(fb, offset, length);
handleTextChanged();
}
#Override
public void replace(FilterBypass fb, int offset, int length, String text,
AttributeSet attributeSet) throws BadLocationException {
super.replace(fb, offset, length, text, attributeSet);
handleTextChanged();
}
/**
* Runs your updates later, not during the event notification.
*/
public void handleTextChanged()
{
SwingUtilities.invokeLater(this::updateTextStyles);
}
private void updateTextStyles()
{
// Reset the existing styles by using the default black style for all text.
StyledDocument document = textPane.getStyledDocument();
document.setCharacterAttributes(0, textPane.getText().length(),
blackAttributeSet, true);
// Apply styling for the different groups (the order of the groups is relevant).
for (HighlightGroup highlightGroup : highlightGroups) {
highlightGroup.highlightWords(textPane);
}
}
}
HighlightGroup.java:
import java.awt.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.text.*;
public class HighlightGroup {
private final List<String> textFragments;
private final Color color;
private final AttributeSet attributeSet;
public HighlightGroup(List<String> textFragments, Color color) {
this.textFragments = new ArrayList<>(textFragments);
this.color = color;
StyleContext styleContext = StyleContext.getDefaultStyleContext();
this.attributeSet = styleContext.addAttribute(styleContext.getEmptySet(),
StyleConstants.Foreground,
color);
}
public List<String> getTextFragments() {
return textFragments;
}
public Color getColor() {
return color;
}
public void highlightWords(JTextPane textPane) {
String text = textPane.getText();
StyledDocument styledDocument = textPane.getStyledDocument();
for (String textFragment : textFragments) {
int fromIndex = 0;
int startIndex = text.indexOf(textFragment, fromIndex);
while (startIndex != -1) {
// Change the color of recognized text fragments.
styledDocument.setCharacterAttributes(startIndex, textFragment.length(),
attributeSet, false);
fromIndex = startIndex + textFragment.length();
startIndex = text.indexOf(textFragment, fromIndex);
}
}
}
}

Referencing from an inner class

I have the following code
import javax.swing.*;
import java.awt.*;
import net.miginfocom.swing.MigLayout;
import Sorts.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.Color;
public class SortsGui
{
JFrame myMainWindow = new JFrame("Sorts");
JPanel sortPanel = new JPanel();
//first panel components
public int nextTextBox = 20;
JTextField[] allField = new JTextField [25];
//end first panel
public void runGUI()
{
myMainWindow.setBounds(10, 10, 800, 800);
myMainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myMainWindow.setLayout(new GridLayout(1,1));
createSortTestPanel();
myMainWindow.getContentPane().add(sortPanel);
myMainWindow.setVisible(true);
}
public void createSortTestPanel()
{
MigLayout layout = new MigLayout("" , "[grow]");
sortPanel.setLayout(layout);
refreshScreen();
}
public void refreshScreen()
{
sortPanel.removeAll();
for(int i = 0; i<nextTextBox;i++)
{
int fix = i+1;
allField[i] = new JTextField("");
sortPanel.add(allField[i],"growx");
allField[i].addKeyListener(new KeyListener ()
{
public void keyPressed(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
char c = e.getKeyChar();
if(Character.isDigit(c))
{
}
else
{
e.consume();
}
try
{
int parseTest = Integer.parseInt(allField[i].getText());
}
catch(Exception exc)
{
allField[i].setBackground(Color.RED);
}
}
});
}
}
public static void main(String[] args)
{
SortsGui sG = new SortsGui();
sG.runGUI();
}
}
My aim here is to create an array of JTextFields which have a keylistener on. This keylistener should prevent anything other than numbers being entered in the JTextField. It should also change the color of the JTextField's background if the number entered is not an int. For example 2147483647554.
However when I compile this I get the error
So how do I make this so that it is either final or effectively final on all the JTextFields?
My aim here is to create an array of JTextFields which have a keylistener on. This keylistener should prevent anything other than numbers being entered in the JTextField
The short answer to this is, don't use KeyListener, it won't capture the use cases of the user pasting text into the field or if the field is updated programmatically
Instead you want to use a DocumentFilter, for example
public class IntFilter extends DocumentFilter {
#Override
public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
StringBuilder buffer = new StringBuilder(text.length());
for (int index = 0; index < text.length(); index++) {
if (Character.isDigit(text.charAt(index))) {
buffer.append(text.charAt(index));
}
}
super.insertString(fb, offset, buffer.toString(), attr);
ValidationListener listener = getValidationListener();
}
#Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
if (length > 0) {
fb.remove(offset, length);
}
insertString(fb, offset, string, attr);
}
}
See Implementing a Document Filter for more details and DocumentFilter Examples for more examples
It should also change the color of the JTextField's background if the number entered is not an int
You can do post validation using a InputVerifier, but that might not meet your needs.
This creates a problem. The DocumentFilter, shouldn't care about the field it's applied to, but since, it's doing the validation, it will know when something has gone wrong, so we need some way for the filter to provide notification when the validation fails...
First, we need some callback which tells us when validation has failed or passed...
public interface ValidationListener {
public void validationFailed();
public void validationPassed();
}
Then we need to update the filter to raise those notifications based on it's rules...
public class IntFilter extends DocumentFilter {
private ValidationListener validationListener;
public void setValidationListener(ValidationListener validationListener) {
this.validationListener = validationListener;
}
public ValidationListener getValidationListener() {
return validationListener;
}
#Override
public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
boolean validationFailed = false;
StringBuilder buffer = new StringBuilder(text.length());
for (int index = 0; index < text.length(); index++) {
if (Character.isDigit(text.charAt(index))) {
buffer.append(text.charAt(index));
} else {
validationFailed = true;
}
}
super.insertString(fb, offset, buffer.toString(), attr);
ValidationListener listener = getValidationListener();
if (listener != null) {
if (validationFailed) {
listener.validationFailed();
} else {
listener.validationPassed();
}
}
}
#Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
if (length > 0) {
fb.remove(offset, length);
}
insertString(fb, offset, string, attr);
}
}
Then we need to define our implementation of the ValidationListener to perform the actions we need...
public class DefaultValidationHandler implements ValidationListener {
private JTextField field;
public DefaultValidationHandler(JTextField field) {
this.field = field;
}
public JTextField getField() {
return field;
}
#Override
public void validationFailed() {
getField().setBackground(Color.RED);
}
#Override
public void validationPassed() {
getField().setBackground(UIManager.getColor("TextField.background"));
}
}
Here, the listener maintains a reference to the field which we want to control
Then we bind it altogether...
JTextField field = new JTextField(10);
DefaultValidationHandler handler = new DefaultValidationHandler(field);
IntFilter filter = new IntFilter();
filter.setValidationListener(handler);
((AbstractDocument)field.getDocument()).setDocumentFilter(filter);
This is all a bit crude, but it gets the basic idea across.
Some improvements might include passing the reference of the DocumentFilter back via the methods of the ValidationListener, you could then use this to lookup the field which triggered the event and update it, reducing the number of handlers you might need to create, for example.
For example
Updated ValidationListener
public interface ValidationListener {
public void validationFailed(DocumentFilter filter);
public void validationPassed(DocumentFilter filter);
}
Updated IntFilter
public class IntFilter extends DocumentFilter {
private ValidationListener validationListener;
public void setValidationListener(ValidationListener validationListener) {
this.validationListener = validationListener;
}
public ValidationListener getValidationListener() {
return validationListener;
}
#Override
public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
boolean validationFailed = false;
StringBuilder buffer = new StringBuilder(text.length());
for (int index = 0; index < text.length(); index++) {
if (Character.isDigit(text.charAt(index))) {
buffer.append(text.charAt(index));
} else {
validationFailed = true;
}
}
super.insertString(fb, offset, buffer.toString(), attr);
ValidationListener listener = getValidationListener();
if (listener != null) {
if (validationFailed) {
listener.validationFailed(this);
} else {
listener.validationPassed(this);
}
}
}
#Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
if (length > 0) {
fb.remove(offset, length);
}
insertString(fb, offset, string, attr);
}
}
Example implementation...
public class TestPane extends JPanel {
private Map<DocumentFilter, JTextField> fields;
public TestPane() {
fields = new HashMap<>(25);
ValidationListener listener = new ValidationListener() {
#Override
public void validationFailed(DocumentFilter filter) {
JTextField field = fields.get(filter);
if (field != null) {
field.setBackground(Color.RED);
}
}
#Override
public void validationPassed(DocumentFilter filter) {
JTextField field = fields.get(filter);
if (field != null) {
field.setBackground(UIManager.getColor("TextField.background"));
}
}
};
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
for (int index = 0; index < 10; index++) {
JTextField field = new JTextField(10);
IntFilter filter = new IntFilter();
filter.setValidationListener(listener);
((AbstractDocument) field.getDocument()).setDocumentFilter(filter);
fields.put(filter, field);
add(field, gbc);
}
}
}
You have a scoping issue that's why getting this error:
for(int i = 0; i<nextTextBox;i++) //you are declaring i here
using inside KeyListener , This is prohibited. Because local non-final variable cant be accessed from inner class to access it must be final. In your case I don't think it is possible to make i final
So, one quick fix is declare i in the class scope with the JFrame and JPanel
JFrame myMainWindow = new JFrame("Sorts");
JPanel sortPanel = new JPanel();
int i;
then use it any where
for(i = 0; i<nextTextBox;i++)

JTextField set input limit

Hi I am trying to use setDocument method to limit the number of characters a user can input in the text field. But somehow it does not limit the no of input characters. Here's the code
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
public class JTextFieldCharLimit extends PlainDocument {
private int limit;
public JTextFieldCharLimit(int limit)
{
super();
this.limit = limit;
}
public void inserString(int offset, String str, AttributeSet set) throws BadLocationException
{
if(str == null)
{
return;
} else if((getLength() + str.length()) <= limit)
{
str = str.toUpperCase();
super.insertString(offset, str, set);
}
}
}
I am using this class in another class where I have declared my text field as follows:
void playerInfoScreen(JFrame mainFrame, JPanel menuPanel)
{
final ScreenConstructor playerName = new ScreenConstructor();
final JFrame frame = mainFrame;
final JPanel returnPanel = menuPanel;
final JPanel panel = playerName.createPanel("menu panel");
final JButton returnButton = playerName.createButton("MAIN MENU");
final JTextField textEntry = playerName.createTextField(10);
// text field length needs to be set to prevent long texts
final JLabel label = playerName.createLabel("Enter Player Name:");
playerName.addButtonToPanel(panel, returnButton);
playerName.addLabelToPanel(panel, label);
playerName.addJTextFieldToPanel(panel, textEntry);
textEntry.setDocument(new JTextFieldCharLimit(5));
playerName.displayScreen(frame, panel);
// check for esc button to let user return back to main menu
textEntry.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String player = textEntry.getText(); // save entered player name
storedPlayerName = player; // store player in order to use it in highscores and display on game screen
GameScreen game = new GameScreen(frame, panel); // go to game screen
}
});
returnButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
frame.setContentPane(returnPanel); // go back to previous panel
}
});
}
Use a DocumentFilter. See Implementing a Document Filter and DocumentFilter Examples for more details.
public class SizeFilter extends DocumentFilter {
private int maxCharacters;
public SizeFilter(int maxChars) {
maxCharacters = maxChars;
}
public void insertString(FilterBypass fb, int offs, String str, AttributeSet a)
throws BadLocationException {
if ((fb.getDocument().getLength() + str.length()) <= maxCharacters)
super.insertString(fb, offs, str, a);
else
Toolkit.getDefaultToolkit().beep();
}
public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
throws BadLocationException {
if ((fb.getDocument().getLength() + str.length()
- length) <= maxCharacters)
super.replace(fb, offs, length, str, a);
else
Toolkit.getDefaultToolkit().beep();
}
}
Credit to MDP
((AbstractDocument)textEntry.getDocument()).setDocumentFilter(new SizeFilter(5));

JFormattedTextField for Double still takes characters [duplicate]

This question already has answers here:
Is there any way to accept only numeric values in a JTextField?
(20 answers)
Closed 9 years ago.
I have a JFormattedTextField where the user would input prices, I have this, but if I type a character, it'll let me anyway. I need this text field to only read numbers or , from the keyboard, and ignore if it's a char. How should I change it in order to make it work?
JFormattedTextField formattedTextField = new JFormattedTextField();
formattedTextField.setBounds(25, 330, 56, 20);
contentPanel.add(formattedTextField);
formattedTextField.setValue(new Double(10.0));
You need to set a Formatter:
NumberFormat f = NumberFormat.getNumberInstance();
JFormattedTextField field = new JFormattedTextField(f);
Take a look: Format
and
NumberFormat
Then try this:
PlainDocument doc = new PlainDocument();
doc.setDocumentFilter(new DocumentFilter() {
#Override
public void insertString(FilterBypass fb, int off, String str, AttributeSet attr)
throws BadLocationException
{
fb.insertString(off, str.replaceAll("\\D++", ""), attr); // remove non-digits
}
#Override
public void replace(FilterBypass fb, int off, int len, String str, AttributeSet attr)
throws BadLocationException
{
fb.replace(off, len, str.replaceAll("\\D++", ""), attr); // remove non-digits
}
});
JFormattedTextField field = new JFormattedTextField();
field.setDocument(doc);
A JFormattedTextField can be used for many things, it can be also used to filter dates or phone numbers. You will either need to set a NumberFormater to the TextField or you use the DocumentFilter (works with JTextField only too).
Check this code snippet, that's how you allow only digits in JTextField, by using DocumentFilter, as the most effeciive way :
import java.awt.*;
import javax.swing.*;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.DocumentFilter.FilterBypass;
public class InputInteger
{
private JTextField tField;
private MyDocumentFilter documentFilter;
private void displayGUI()
{
JFrame frame = new JFrame("Input Integer Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5));
tField = new JTextField(10);
((AbstractDocument)tField.getDocument()).setDocumentFilter(
new MyDocumentFilter());
contentPane.add(tField);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
Runnable runnable = new Runnable()
{
#Override
public void run()
{
new InputInteger().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class MyDocumentFilter extends DocumentFilter
{
#Override
public void insertString(DocumentFilter.FilterBypass fp
, int offset, String string, AttributeSet aset)
throws BadLocationException
{
int len = string.length();
boolean isValidInteger = true;
for (int i = 0; i < len; i++)
{
if (!Character.isDigit(string.charAt(i)))
{
isValidInteger = false;
break;
}
}
if (isValidInteger)
super.insertString(fp, offset, string, aset);
else
Toolkit.getDefaultToolkit().beep();
}
#Override
public void replace(DocumentFilter.FilterBypass fp, int offset
, int length, String string, AttributeSet aset)
throws BadLocationException
{
int len = string.length();
boolean isValidInteger = true;
for (int i = 0; i < len; i++)
{
if (!Character.isDigit(string.charAt(i)))
{
isValidInteger = false;
break;
}
}
if (isValidInteger)
super.replace(fp, offset, length, string, aset);
else
Toolkit.getDefaultToolkit().beep();
}
}

JTextField: How to limit the number of characters?

Please have a look at the following code.
import java.awt.FlowLayout;
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class Bean extends JFrame
{
private JTextField field1, field2, field3, field4;
private JLabel text;
private JButton ok, cancel;
private JPanel centerPanel,southPanel, textPanel;
private GridLayout grid;
private FlowLayout flow1, flow2;
public Bean()
{
//Declaring instance Variables
field1 = new JTextField(10);
field2 = new JTextField(5);
field3 = new JTextField(5);
field4 = new JTextField(5);
text = new JLabel("Insert Your Numbers Here");
AbstractDocument d = (AbstractDocument) field1.getDocument();
d.setDocumentFilter(new Bean.Field1Listener());
ok = new JButton("OK");
cancel = new JButton("Cancel");
/***********************Creating the main view*************************/
centerPanel = new JPanel();
grid = new GridLayout(2,1,1,1);
//Adding TextFields
textPanel = new JPanel();
flow1 = new FlowLayout(FlowLayout.CENTER);
textPanel.setLayout(flow1);
textPanel.add(field1);
//Adding Buttons
southPanel = new JPanel();
southPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
southPanel.add(ok);
southPanel.add(cancel);
//Creating Center View
centerPanel.setLayout(grid);
centerPanel.add(text);
centerPanel.add(textPanel);
//Gathering everything together
getContentPane().add(centerPanel,"Center");
getContentPane().add(southPanel,"South");
this.setSize(500,200);
this.validate();
this.setVisible(true);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private class Field1Listener extends DocumentFilter
{
#Override
public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException
{
if(fb.getDocument().getLength()+string.length()>5)
{
return;
}
fb.insertString(offset, string, attr);
}
#Override
public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException
{
fb.insertString(offset, "", null);
}
#Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs)throws BadLocationException
{
if(fb.getDocument().getLength()+text.length()>5)
{
System.out.println("OK");
return;
}
fb.insertString(offset, text, attrs);
}
}
public static void main(String[]args)
{
new Bean();
}
}
In here, I am trying to limit the number of character to 5. OK, it stops inserting anymore characters when it reaches 5, but the case is, it also doesn't allow to delete the inserted characters, replace, or anything. How to correct this issue?
simply change your current remove method:
#Override
public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException
{
fb.insertString(offset, "", null);
}
for this one:
#Override
public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException
{
fb.remove(offset, length);
}
it should now work.
You should make your own class that checks whether you gave more input than the maximum allowed length: See an example on http://www.java2s.com/Tutorial/Java/0240__Swing/LimitJTextFieldinputtoamaximumlength.htm.

Categories