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++)
Related
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++)
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));
In the following example I have created two texFields. While writing on first text filed if the space or number typed by user then it should show message on another textField_1. But once user entered number/space it giving java.lang.NullPointerException.
public class NewDemo extends JFrame {
private JPanel p1;
private JTextField textField,textField_1;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
NewDemo frame = new NewDemo();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public NewDemo() {
setTitle("New Demo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 500, 500);
p1 = new JPanel();
p1.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(p1);
p1.setLayout(null);
textField = new JTextField();
textField.setBounds(70, 71, 86, 20);
p1.add(textField);
textField.setColumns(10);
JLabel lblNewLabel = new JLabel("");
lblNewLabel.setBounds(70, 96, 86, 14);
p1.add(lblNewLabel);
textField_1 = new JTextField();
textField_1.setBounds(204, 71, 86, 20);
p1.add(textField_1);
textField_1.setColumns(10);
System.out.println("before calling");
((AbstractDocument) textField.getDocument()).setDocumentFilter(new MyDocumentFilter());
System.out.println("AfterCalling");
}
public JTextField getTextField_1() {
return textField_1;
}}
Here is the second class MyDocumentFilter where the java.lang.NullPointerException error occurring in the else block of replace method.
class MyDocumentFilter extends DocumentFilter {
private NewDemo n1;
#Override
public void replace(FilterBypass fb, int i, int i1, String string, AttributeSet as) throws BadLocationException {
System.out.println("Starting: replace Method");
for (int n = string.length(); n > 0; n--)
char c = string.charAt(n - 1);
System.out.println(c);
if (Character.isAlphabetic(c)) {
System.out.println("In if: replace method");
super.replace(fb, i, i1, String.valueOf(c), as);
} else {
System.out.println("Not allowed:BEFORE");
n1.getTextField_1().setText("not allowed");//***HERE IS THE ERROR
System.out.println("Not allowed:AFTER");
}
}
}
#Override
public void remove(FilterBypass fb, int i, int i1) throws BadLocationException {
System.out.println("In :remove method");
super.remove(fb, i, i1);
}
#Override
public void insertString(FilterBypass fb, int i, String string, AttributeSet as) throws BadLocationException {
System.out.println("In: insterString Method");
super.insertString(fb, i, string, as);
}}
Your DocumentFilter needs a reference to the displayed NewDemo GUI object. Don't just create a new NewDemo instance as another has suggested, since that will create a non-displayed separate instance, but rather pass in the appropriate displayed reference.
e.g.,
((AbstractDocument) textField.getDocument())
.setDocumentFilter(new MyDocumentFilter(this)); //!!
and
class MyDocumentFilter extends DocumentFilter {
private NewDemo n1;
public MyDocumentFilter(NewDemo n1) {
this.n1 = n1;
}
But yeah, also follow any recommendation from MadProgrammer as he knows his Swing and Java backwards and forwards. Also You should avoid use of null layout and use of setBounds(...) for component placement as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.
Edit using MadProgrammer's suggestion, consider allowing your GUI to add PropertyChangeListener to the DocumentFilter. This way, any class can listen for changes in the "state" of the DocumentFilter. Here I've created a boolean state called "valid" that notifies listeners any time the boolean variable changes.
For example:
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
import javax.swing.text.*;
public class NewDemo extends JPanel {
private static final long serialVersionUID = 1L;
private JTextField textField, textField_1;
private static void createAndShowGui() {
NewDemo mainPanel = new NewDemo();
JFrame frame = new JFrame("New Demo");
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();
}
});
}
public NewDemo() {
setLayout(new GridLayout(1, 0, 5, 5));
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
textField = new JTextField();
textField.setColumns(10);
add(textField);
textField_1 = new JTextField();
textField_1.setColumns(10);
add(textField_1);
MyDocumentFilter docFilter = new MyDocumentFilter(); // !!
((AbstractDocument) textField.getDocument()).setDocumentFilter(docFilter); // !!
docFilter.addPropertyChangeListener(MyDocumentFilter.VALID,
new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String text = ((Boolean) evt.getNewValue()) ? "Allowed"
: "Not Allowed";
textField_1.setText(text);
}
});
}
}
class MyDocumentFilter extends DocumentFilter {
public static final String VALID = "valid";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private boolean valid = true;
#Override
public void replace(FilterBypass fb, int i, int i1, String string,
AttributeSet as) throws BadLocationException {
for (int n = string.length(); n > 0; n--) {
char c = string.charAt(n - 1);
System.out.println(c);
if (Character.isAlphabetic(c)) {
super.replace(fb, i, i1, String.valueOf(c), as);
setValid(true);
} else {
setValid(false);
}
}
}
#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);
}
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
boolean oldValue = this.valid;
boolean newValue = valid;
this.valid = valid;
pcSupport.firePropertyChange(VALID, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener l) {
pcSupport.addPropertyChangeListener(propertyName, l);
}
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener l) {
pcSupport.removePropertyChangeListener(propertyName, l);
}
}
It is not the responsibility of the DocumentFilter to modify the state of the UI. Instead, it should provide notification that the state has errored (or what ever else you want to know) and let the delegate make decisions about what should be done.
public interface DocumentFilterListener {
public void documentFilterValidationFailed(DocumentFilter filter, String message);
}
public class MyDocumentFilter extends DocumentFilter {
private DocumentFilterListener filterListener;
public MyDocumentFilter(DocumentFilterListener filterListener) {
this.filteristener = filterListener;
}
#Override
public void replace(FilterBypass fb, int i, int i1, String string, AttributeSet as) throws BadLocationException {
System.out.println("Starting: replace Method");
for (int n = string.length(); n > 0; n--)
char c = string.charAt(n - 1);
System.out.println(c);
if (Character.isAlphabetic(c)) {
System.out.println("In if: replace method");
super.replace(fb, i, i1, String.valueOf(c), as);
} else if (filterListener != null) {
System.out.println("Not allowed:BEFORE");
filterListener.documentFilterValidationFailed(this, "not allowed");
System.out.println("Not allowed:AFTER");
}
}
}
#Override
public void remove(FilterBypass fb, int i, int i1) throws BadLocationException {
System.out.println("In :remove method");
super.remove(fb, i, i1);
}
#Override
public void insertString(FilterBypass fb, int i, String string, AttributeSet as) throws BadLocationException {
System.out.println("In: insterString Method");
super.insertString(fb, i, string, as);
}
}
Then you would simply implement the requirements of the interface
((AbstractDocument) textField.getDocument()).setDocumentFilter(
new MyDocumentFilter(new DocumentFilterListener() {
public void documentFilterValidationFailed(DocumentFilter filter, String message) {
getTextField_1().setText(message);
}
}));
As an example.
I want my program to be able to tell if what is inside my two JTextFields is an integer or a String.
CODE
public void actionPerformed(ActionEvent e){
if(inputH.getText().equals(" Set Height ") ||
inputW.getText().equals(" Set Width ")){
JOptionPane.showMessageDialog(frame,
"Change Height And Width To A Number.",
"Change Height To A Number",
JOptionPane.ERROR_MESSAGE);
}
}
});
This if statement tests if what is in the JTextField is " Set Height " or " Set Width " but i want them to test if what is in them is a number, how would I do that?
i cant figure out the Integer.ParseInt. Please help.
Not sure exactly where in your code the test is being performed, but you can use this method to determine if a String is an integer:
public static boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch(NumberFormatException e) {
return false;
}
// if exception isn't thrown, then it is an integer
return true;
}
Less expensive none exception based way, assuming your code does not need to throw an exception:
public static boolean isInt(String s){
for(int i = 0; i < s.length(); i++){
if(!Character.isDigit(s.charAt(i))){
return false;
}
}
return true;
}
For restricting a User from entering anything but digits, you can set a DocumentFilter on the JTextField.
Here is a small example :
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();
}
}
Or one can simply use this approach, as given by #Carlos Heuberger
#Override
public void insertString(FilterBypass fb, int off
, String str, AttributeSet attr)
throws BadLocationException
{
// remove non-digits
fb.insertString(off, str.replaceAll("\\D++", ""), attr);
}
#Override
public void replace(FilterBypass fb, int off
, int len, String str, AttributeSet attr)
throws BadLocationException
{
// remove non-digits
fb.replace(off, len, str.replaceAll("\\D++", ""), attr);
}
You can process the key event in the action method also. Try this
First make a JTextField
JTextField j=new JTextField();
Then add KeyListner to this JTextField as
j.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
if(arg0.getKeyCode()>57 || arg0.getKeyCode()<48) {
//your error message and other handling code here
JOptionPane.showMessageDialog(PatentFrame, "Only integer allowed", "Message title",JOptionPane.ERROR_MESSAGE);
}
}
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
});
48 is ASCII code for 0 and 57 is ASCII code for 9. You can also ignore virtual keys like shift. See ASCII chart
I need to not allow any characters to be entered after X have been typed. I need to send a beep after X characters have been typed. I know how to do this after the user presses enter, but I need to do it before the user presses enter. The approach I found from Oracle's site is to add a DocumentSizeFilter to the JTextPane. I can't get this to notify the user when they have gone over (it doesn't work until they press enter). This is a sample of what I have.
public class EndCycleTextAreaRenderer extends JTextPane
implements TableCellRenderer {
private final int maxNumberOfCharacters = 200;
public EndCycleTextAreaRenderer() {
StyledDocument styledDoc = this.getStyledDocument();
AbstractDocument doc;
doc = (AbstractDocument)styledDoc;
doc.setDocumentFilter(new DocumentSizeFilter(maxNumberOfCharacters ));
}
Override the insertString method of the document in the JTextPane so that it doesn't insert any more characters once the maximum has been reached.
For example:
JTextPane textPane = new JTextPane(new DefaultStyledDocument() {
#Override
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
if ((getLength() + str.length()) <= maxNumberOfCharacters) {
super.insertString(offs, str, a);
}
else {
Toolkit.getDefaultToolkit().beep();
}
}
});
Update:
You can change your class as follows:
public class EndCycleTextAreaRenderer extends JTextPane implements TableCellRenderer {
private final int maxNumberOfCharacters = 200;
public EndCycleTextAreaRenderer() {
setStyledDocument(new DefaultStyledDocument() {
#Override
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
if ((getLength() + str.length()) <= maxNumberOfCharacters) {
super.insertString(offs, str, a);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
});
}
}
Here is a sample program, for you where, as you enter the fourth time into the TextPane it will beep, without even you pressing the Enter key:
import javax.swing.*;
import javax.swing.text.*;
import java.awt.Toolkit;
public class TextPaneLimit extends JFrame
{
private JPanel panel;
private JTextPane tpane;
private AbstractDocument abDoc;
public TextPaneLimit()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
panel = new JPanel();
tpane = new JTextPane();
Document doc = tpane.getStyledDocument();
if (doc instanceof AbstractDocument)
{
abDoc = (AbstractDocument)doc;
abDoc.setDocumentFilter(new DocumentSizeFilter(3));
}
panel.add(tpane);
add(panel);
pack();
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new TextPaneLimit().setVisible(true);
}
});
}
}
class DocumentSizeFilter extends DocumentFilter {
private int max_Characters;
private boolean DEBUG;
public DocumentSizeFilter(int max_Chars) {
max_Characters = max_Chars;
DEBUG = false;
}
public void insertString(FilterBypass fb
, int offset
, String str
, AttributeSet a)
throws BadLocationException {
if (DEBUG) {
System.out.println("In DocumentSizeFilter's insertString method");
}
if ((fb.getDocument().getLength() + str.length()) <= max_Characters)
super.insertString(fb, offset, str, a);
else
Toolkit.getDefaultToolkit().beep();
}
public void replace(FilterBypass fb
, int offset, int length
, String str, AttributeSet a)
throws BadLocationException {
if (DEBUG) {
System.out.println("In DocumentSizeFilter's replace method");
}
if ((fb.getDocument().getLength() + str.length()
- length) <= max_Characters)
super.replace(fb, offset, length, str, a);
else
Toolkit.getDefaultToolkit().beep();
}
}
Hope this might help.
I would suggest checking the # of characters with every key entered by adding a keyReleasedListener, it is something I used in a recent GUI of mine to check bounds seemingly instantly and display errors to the user as they typed.
Here is how I implemented it on one of my TextFields:
carbonTextField.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(java.awt.event.KeyEvent evt)
{
carbonTextFieldKeyReleased(evt);
}
});
Check the following code:
txtpnDesc.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
if(txtpnDesc.getText().length() == 30)
{
e.consume();
}
}
});