Java tutorial
/* 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(); }