How do I validate a TextField/JTextField to only accept valid IP addresses?
Created May 4, 2012
[FAQ Manager Note]There are two answers submitted for this question. The second appears at the end of the page.
Here is a possible soltion. I wrote this last night using a generic bounded text field class I created some time back. This approach doesn't follow the model view approach but it gets the job done.
I create a IPAddressField class which contains multiple JTextField's which use the BoundedNumberDocument. The BoundedNumberDocument uses a DefaultComparator class to determine if the new string is within the bounds. Take it easy on me because this is my first time posting. I hope that some of this code is useful.
BoundedNumberDocument.java
import java.awt.Toolkit; import java.util.Comparator; import java.math.*; import java.text.*; import javax.swing.text.*; public class BoundedNumberDocument extends PlainDocument { final public static int UNLIMITED_FRACTION_DIGITS = -1; protected Number minValue; protected Number maxValue; protected Comparator comparator; protected Number currentValue = null; protected int maxFracts = UNLIMITED_FRACTION_DIGITS; public BoundedNumberDocument(Number minValue, Number maxValue) { this(minValue,maxValue,new DefaultComparator()); } public BoundedNumberDocument(Number minValue, Number maxValue, Comparator comparator) { if (minValue.getClass() == maxValue.getClass()) { this.minValue = minValue; this.maxValue = maxValue; } else { throw new IllegalArgumentException( "Bounded values must be of the same class"); } setComparator(comparator); } public Number getValue() throws NumberFormatException, BadLocationException { return parseNumberFromString(getText(0,getLength())); } public void setComparator(Comparator comparator) { this.comparator = comparator; } public void setMinimumValue(Number minValue) { this.minValue = minValue; } public void setMaximumValue(Number maxValue) { this.maxValue = maxValue; } public int getMaximumFractionDigits() { return maxFracts; } public void setMaximumFractionDigits(int maxFracts) { this.maxFracts = maxFracts; } public void insertString(int offset, String str, AttributeSet a) throws BadLocationException { String curText = getText(0,getLength()); String preOffset = curText.substring(0,offset); String postOffset = curText.substring(offset,curText.length()); String newStr = preOffset + str + postOffset; if (verifyString(newStr)) super.insertString(offset,str,a); } public void remove(int offset, int len) throws BadLocationException { String curText = getText(0,getLength()); String preOffset = curText.substring(0,offset); String postOffset = curText.substring(len+offset, curText.length()); String newStr = preOffset + postOffset; if (newStr.length()!=0) { if (verifyString(newStr)) super.remove(offset,len); } else { // this is for erasing all the characters super.remove(offset,len); currentValue = null; } } protected boolean verifyString(String newStr) { if (newStr!=null && newStr.length()!=0) { try { if (!isMaximumFractionDigitsExceeded(newStr, getMaximumFractionDigits())) { Number newValue = parseNumberFromString(newStr); if ( (comparator.compare(newValue,minValue) >= 0) && (comparator.compare(newValue,maxValue) = 0)) { currentValue = newValue; return true; } } } catch (NumberFormatException nfe) { } } return false; } public boolean isMaximumFractionDigitsExceeded(String str, int maxDigits) { if (str==null || str.length()==0 || maxDigits==UNLIMITED_FRACTION_DIGITS) return false; else { int digits = 0; boolean decimalFound = false; for (int i=0; i str.length(); i++) { if (!decimalFound) decimalFound = str.charAt(i) == '.'; else { if ( Character.isDigit(str.charAt(i))) digits++; } } return (digits > maxDigits); } } public Number parseNumberFromString(String newStr) throws NumberFormatException { if (minValue instanceof Integer) { return Integer.valueOf(newStr); } else if (minValue instanceof Double) { return Double.valueOf(newStr); } else if (minValue instanceof Float) { return Float.valueOf(newStr); } else if (minValue instanceof BigDecimal) { return new BigDecimal(newStr); } else if (minValue instanceof BigInteger) { return new BigInteger(newStr); } else if (minValue instanceof Byte) { return Byte.valueOf(newStr); } else if (minValue instanceof Long) { return Long.valueOf(newStr); } else if (minValue instanceof Short) { return Short.valueOf(newStr); } else { throw new NumberFormatException("Unknown Number class"); } } }
IPAddressPanel.java
import java.awt.*; import java.awt.geom.*; import java.net.*; import javax.swing.*; import javax.swing.text.*; public class IPAddressPanel extends JPanel { JTextField field0; JTextField field1; JTextField field2; JTextField field3; public IPAddressPanel() { field0 = createBoundedField(new Integer(1),new Integer(255)); field1 = createBoundedField(new Integer(0),new Integer(255)); field2 = createBoundedField(new Integer(0),new Integer(255)); field3 = createBoundedField(new Integer(0),new Integer(255)); initLayout(); } public void initLayout() { Dimension d = new Dimension(2,field0.getPreferredSize().height); Component c; add(field0); c = new DotPanel(2,Color.black); c.setSize(d); add(c); add(field1); c = new DotPanel(2,Color.black); c.setSize(d); add(c); add(field2); c = new DotPanel(2,Color.black); c.setSize(d); add(c); add(field3); } public JTextField createBoundedField(Number n1, Number n2) { Document doc = new BoundedNumberDocument(n1,n2); JTextField field = new JTextField(doc,"",3); field.setHorizontalAlignment(JTextField.RIGHT); return field; } public InetAddress getAddress() throws UnknownHostException { String s = ""; s+= field0.getText() + "."; s+= field1.getText() + "."; s+= field2.getText() + "."; s+= field3.getText(); return InetAddress.getByName(s); } public void setEnabled(boolean enabled) { super.setEnabled(enabled); field0.setEnabled(enabled); field1.setEnabled(enabled); field2.setEnabled(enabled); field3.setEnabled(enabled); } public static class DotPanel extends Canvas { int dotWidth; Color dotColor; public DotPanel(int dotWidth, Color dotColor) { this.dotWidth = dotWidth; this.dotColor = dotColor; } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; int width = getWidth(); int height = getHeight(); g2.setColor(dotColor); int xPos, yPos; xPos = (width / 2) - (dotWidth / 2); yPos = height - 1 - dotWidth; Ellipse2D dot = new Ellipse2D.Float( xPos,yPos,dotWidth,dotWidth); g2.fill(dot); } } }
DefaultComparator.java
import java.math.BigDecimal; import java.math.BigInteger; import java.util.Comparator; import java.util.Date; public class DefaultComparator implements Comparator { public static final int IGNORE_CASE = 0; public static final int CASE_SENSITIVE = 1; protected int caseSensitive = CASE_SENSITIVE; public int getCaseSensitive() { return caseSensitive; } public void setCaseSensitive(int caseSensitive) { if (caseSensitive == 0 || caseSensitive == 1) this.caseSensitive = caseSensitive; else throw new IllegalArgumentException( "Unable to setCaseSensitive. Accepted values are " + "IGNORE_CASE or CASE_SENSITIVE"); } public int compare(Object o1, Object o2) { if (o1 == null || o2 == null) { return getNullComparison(o1,o2); } if (o1 instanceof Boolean && o2 instanceof Boolean) { return compare((Boolean)o1,(Boolean)o2); } else if (o1 instanceof Number && o2 instanceof Number) { return compare((Number)o1,(Number)o2); } else if (o1 instanceof Date && o2 instanceof Date) { return compare((Date)o1,(Date)o2); } else { return this.compare(o1.toString(), o2.toString()); } } public int compare(String s1, String s2) { if (s1 == null || s2 == null ) { return getNullComparison(s1,s2); } else { int result; if (caseSensitive==IGNORE_CASE) result = s1.compareToIgnoreCase(s2); else // Case Sensitive result = s1.compareTo(s2); if (result > 0) return 1; else if (result 0) return -1; else return 0; } } public int compare(Number o1, Number o2) { if (o1 == null || o2 == null ) { return getNullComparison(o1,o2); } try { if (o1 instanceof BigDecimal) { return ((BigDecimal)o1).compareTo(o2); } else if (o1 instanceof BigInteger) { return ((BigInteger)o1).compareTo(o2); } else if (o1 instanceof Byte) { return ((Byte)o1).compareTo(o2); } else if (o1 instanceof Double) { return ((Double)o1).compareTo(o2); } else if (o1 instanceof Float) { return ((Float)o1).compareTo(o2); } else if (o1 instanceof Integer) { return ((Integer)o1).compareTo(o2); } else if (o1 instanceof Long) { return ((Long)o1).compareTo(o2); } else if (o1 instanceof Short) { return ((Short)o1).compareTo(o2); } } catch (ClassCastException cce) {} double n1 = o1.doubleValue(); double n2 = o2.doubleValue(); if (n1 n2) { return -1; } else if (n1 > n2) { return 1; } else { return 0; } } public int compare(Date o1, Date o2) { if (o1 == null || o2 == null ) { return getNullComparison(o1,o2); } else { long n1 = o1.getTime(); long n2 = o2.getTime(); if (n1 n2) { return -1; } else if (n1 > n2) { return 1; } else { return 0; } } } public int compare(Boolean o1, Boolean o2) { if (o1 == null || o2 == null ) { return getNullComparison(o1,o2); } else { boolean b1 = o1.booleanValue(); boolean b2 = o2.booleanValue(); if (b1 == b2) { return 0; } else if (b1) { return 1; } else { return -1; } } } private int getNullComparison(Object o1, Object o2) { if (o1 == null && o2 == null) { return 0; } else if (o1 == null) { return -1; } else { return 1; } } }
Ravi Shrivastava provides another answer
You can extend the javax.swing.text.PlainDocument and override the
void insertString( int offs, String str, javax.swing.text.AttributeSet a )
method (dont forget to call super.insertString(..) at the end of your code). You can check for every char that is entered here - to make sure that it forms the correct IP.