Mega Code Archive

 
Categories / Java / Swing JFC
 

Numeric TextField

/* Core SWING Advanced Programming  By Kim Topley ISBN: 0 13 083292 8        Publisher: Prentice Hall   */ import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.text.ParseException; import java.text.ParsePosition; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.PlainDocument; import javax.swing.text.AbstractDocument.Content; public class NumericTextField extends JTextField implements     NumericPlainDocument.InsertErrorListener {   public NumericTextField() {     this(null, 0, null);   }   public NumericTextField(String text, int columns, DecimalFormat format) {     super(null, text, columns);     NumericPlainDocument numericDoc = (NumericPlainDocument) getDocument();     if (format != null) {       numericDoc.setFormat(format);     }     numericDoc.addInsertErrorListener(this);   }   public NumericTextField(int columns, DecimalFormat format) {     this(null, columns, format);   }   public NumericTextField(String text) {     this(text, 0, null);   }   public NumericTextField(String text, int columns) {     this(text, columns, null);   }   public void setFormat(DecimalFormat format) {     ((NumericPlainDocument) getDocument()).setFormat(format);   }   public DecimalFormat getFormat() {     return ((NumericPlainDocument) getDocument()).getFormat();   }   public void formatChanged() {     // Notify change of format attributes.     setFormat(getFormat());   }   // Methods to get the field value   public Long getLongValue() throws ParseException {     return ((NumericPlainDocument) getDocument()).getLongValue();   }   public Double getDoubleValue() throws ParseException {     return ((NumericPlainDocument) getDocument()).getDoubleValue();   }   public Number getNumberValue() throws ParseException {     return ((NumericPlainDocument) getDocument()).getNumberValue();   }   // Methods to install numeric values   public void setValue(Number number) {     setText(getFormat().format(number));   }   public void setValue(long l) {     setText(getFormat().format(l));     ;   }   public void setValue(double d) {     setText(getFormat().format(d));   }   public void normalize() throws ParseException {     // format the value according to the format string     setText(getFormat().format(getNumberValue()));   }   // Override to handle insertion error   public void insertFailed(NumericPlainDocument doc, int offset, String str,       AttributeSet a) {     // By default, just beep     Toolkit.getDefaultToolkit().beep();   }   // Method to create default model   protected Document createDefaultModel() {     return new NumericPlainDocument();   }   // Test code   public static void main(String[] args) {     try {         UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");     } catch (Exception evt) {}        DecimalFormat format = new DecimalFormat("#,###.###");     format.setGroupingUsed(true);     format.setGroupingSize(3);     format.setParseIntegerOnly(false);     JFrame f = new JFrame("Numeric Text Field Example");     final NumericTextField tf = new NumericTextField(10, format);     tf.setValue((double) 123456.789);     JLabel lbl = new JLabel("Type a number: ");     f.getContentPane().add(tf, "East");     f.getContentPane().add(lbl, "West");     tf.addActionListener(new ActionListener() {       public void actionPerformed(ActionEvent evt) {         try {           tf.normalize();           Long l = tf.getLongValue();           System.out.println("Value is (Long)" + l);         } catch (ParseException e1) {           try {             Double d = tf.getDoubleValue();             System.out.println("Value is (Double)" + d);           } catch (ParseException e2) {             System.out.println(e2);           }         }       }     });     f.pack();     f.setVisible(true);   } } class NumericPlainDocument extends PlainDocument {   public NumericPlainDocument() {     setFormat(null);   }   public NumericPlainDocument(DecimalFormat format) {     setFormat(format);   }   public NumericPlainDocument(AbstractDocument.Content content,       DecimalFormat format) {     super(content);     setFormat(format);     try {       format           .parseObject(content.getString(0, content.length()),               parsePos);     } catch (Exception e) {       throw new IllegalArgumentException(           "Initial content not a valid number");     }     if (parsePos.getIndex() != content.length() - 1) {       throw new IllegalArgumentException(           "Initial content not a valid number");     }   }   public void setFormat(DecimalFormat fmt) {     this.format = fmt != null ? fmt : (DecimalFormat) defaultFormat.clone();     decimalSeparator = format.getDecimalFormatSymbols()         .getDecimalSeparator();     groupingSeparator = format.getDecimalFormatSymbols()         .getGroupingSeparator();     positivePrefix = format.getPositivePrefix();     positivePrefixLen = positivePrefix.length();     negativePrefix = format.getNegativePrefix();     negativePrefixLen = negativePrefix.length();     positiveSuffix = format.getPositiveSuffix();     positiveSuffixLen = positiveSuffix.length();     negativeSuffix = format.getNegativeSuffix();     negativeSuffixLen = negativeSuffix.length();   }   public DecimalFormat getFormat() {     return format;   }   public Number getNumberValue() throws ParseException {     try {       String content = getText(0, getLength());       parsePos.setIndex(0);       Number result = format.parse(content, parsePos);       if (parsePos.getIndex() != getLength()) {         throw new ParseException("Not a valid number: " + content, 0);       }       return result;     } catch (BadLocationException e) {       throw new ParseException("Not a valid number", 0);     }   }   public Long getLongValue() throws ParseException {     Number result = getNumberValue();     if ((result instanceof Long) == false) {       throw new ParseException("Not a valid long", 0);     }     return (Long) result;   }   public Double getDoubleValue() throws ParseException {     Number result = getNumberValue();     if ((result instanceof Long) == false         && (result instanceof Double) == false) {       throw new ParseException("Not a valid double", 0);     }     if (result instanceof Long) {       result = new Double(result.doubleValue());     }     return (Double) result;   }   public void insertString(int offset, String str, AttributeSet a)       throws BadLocationException {     if (str == null || str.length() == 0) {       return;     }     Content content = getContent();     int length = content.length();     int originalLength = length;     parsePos.setIndex(0);     // Create the result of inserting the new data,     // but ignore the trailing newline     String targetString = content.getString(0, offset) + str         + content.getString(offset, length - offset - 1);     // Parse the input string and check for errors     do {       boolean gotPositive = targetString.startsWith(positivePrefix);       boolean gotNegative = targetString.startsWith(negativePrefix);       length = targetString.length();       // If we have a valid prefix, the parse fails if the       // suffix is not present and the error is reported       // at index 0. So, we need to add the appropriate       // suffix if it is not present at this point.       if (gotPositive == true || gotNegative == true) {         String suffix;         int suffixLength;         int prefixLength;         if (gotPositive == true && gotNegative == true) {           // This happens if one is the leading part of           // the other - e.g. if one is "(" and the other "(("           if (positivePrefixLen > negativePrefixLen) {             gotNegative = false;           } else {             gotPositive = false;           }         }         if (gotPositive == true) {           suffix = positiveSuffix;           suffixLength = positiveSuffixLen;           prefixLength = positivePrefixLen;         } else {           // Must have the negative prefix           suffix = negativeSuffix;           suffixLength = negativeSuffixLen;           prefixLength = negativePrefixLen;         }         // If the string consists of the prefix alone,         // do nothing, or the result won't parse.         if (length == prefixLength) {           break;         }         // We can't just add the suffix, because part of it         // may already be there. For example, suppose the         // negative prefix is "(" and the negative suffix is         // "$)". If the user has typed "(345$", then it is not         // correct to add "$)". Instead, only the missing part         // should be added, in this case ")".         if (targetString.endsWith(suffix) == false) {           int i;           for (i = suffixLength - 1; i > 0; i--) {             if (targetString                 .regionMatches(length - i, suffix, 0, i)) {               targetString += suffix.substring(i);               break;             }           }           if (i == 0) {             // None of the suffix was present             targetString += suffix;           }           length = targetString.length();         }       }       format.parse(targetString, parsePos);       int endIndex = parsePos.getIndex();       if (endIndex == length) {         break; // Number is acceptable       }       // Parse ended early       // Since incomplete numbers don't always parse, try       // to work out what went wrong.       // First check for an incomplete positive prefix       if (positivePrefixLen > 0 && endIndex < positivePrefixLen           && length <= positivePrefixLen           && targetString.regionMatches(0, positivePrefix, 0, length)) {         break; // Accept for now       }       // Next check for an incomplete negative prefix       if (negativePrefixLen > 0 && endIndex < negativePrefixLen           && length <= negativePrefixLen           && targetString.regionMatches(0, negativePrefix, 0, length)) {         break; // Accept for now       }       // Allow a number that ends with the group       // or decimal separator, if these are in use       char lastChar = targetString.charAt(originalLength - 1);       int decimalIndex = targetString.indexOf(decimalSeparator);       if (format.isGroupingUsed() && lastChar == groupingSeparator           && decimalIndex == -1) {         // Allow a "," but only in integer part         break;       }       if (format.isParseIntegerOnly() == false           && lastChar == decimalSeparator           && decimalIndex == originalLength - 1) {         // Allow a ".", but only one         break;       }       // No more corrections to make: must be an error       if (errorListener != null) {         errorListener.insertFailed(this, offset, str, a);       }       return;     } while (true == false);     // Finally, add to the model     super.insertString(offset, str, a);   }   public void addInsertErrorListener(InsertErrorListener l) {     if (errorListener == null) {       errorListener = l;       return;     }     throw new IllegalArgumentException(         "InsertErrorListener already registered");   }   public void removeInsertErrorListener(InsertErrorListener l) {     if (errorListener == l) {       errorListener = null;     }   }   public interface InsertErrorListener {     public abstract void insertFailed(NumericPlainDocument doc, int offset,         String str, AttributeSet a);   }   protected InsertErrorListener errorListener;   protected DecimalFormat format;   protected char decimalSeparator;   protected char groupingSeparator;   protected String positivePrefix;   protected String negativePrefix;   protected int positivePrefixLen;   protected int negativePrefixLen;   protected String positiveSuffix;   protected String negativeSuffix;   protected int positiveSuffixLen;   protected int negativeSuffixLen;   protected ParsePosition parsePos = new ParsePosition(0);   protected static DecimalFormat defaultFormat = new DecimalFormat(); }