001/**
002 *   Please feel free to use any fragment of the code in this file that you need
003 *   in your own work. As far as I am concerned, it's in the public domain. No
004 *   permission is necessary or required. Credit is always appreciated if you
005 *   use a large chunk or base a significant product on one of my examples,
006 *   but that's not required either.
007 *
008 *   This code is distributed in the hope that it will be useful,
009 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
010 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
011 *
012 *      --- Joseph A. Huwaldt
013 */
014package jahuwaldt.swing;
015
016import javax.swing.*;
017import java.awt.Toolkit;
018import java.text.*;
019
020/**
021 * A text field that validates it's input and only accepts inputs that are a valid decimal
022 * number such as 3.14159. The user of this class provides the NumberFormat object that
023 * actually does the parsing and formatting for display.
024 *
025 * <p> Modified by: Joseph A. Huwaldt </p>
026 *
027 * @author Joseph A. Huwaldt, Date: February 24, 2000
028 * @version August 3, 2018
029 */
030@SuppressWarnings("serial")
031public class DecimalField extends JTextField {
032
033    // The format object that parses and formats this text field's value.
034    private final NumberFormat format;
035
036    /**
037     * Constructor that takes the number of columns to be displayed, and a number format
038     * object to do the text formatting. The text field display is initially set to blank.
039     *
040     * @param columns The number of columns to use in the text field.
041     * @param nf      The number format object to use for formatting the display of this
042     *                text field.
043     */
044    @SuppressWarnings("OverridableMethodCallInConstructor")
045    public DecimalField(int columns, NumberFormat nf) {
046        super(columns);
047
048        setDocument(new FormattedDocument(nf));
049        format = nf;
050        setText("");
051    }
052
053    /**
054     * Constructor that takes a value to be displayed, the number of columns to be
055     * displayed, and a number format object to do the text formatting.
056     *
057     * @param value   The value to be displayed in the text field.
058     * @param columns The number of columns to use in the text field.
059     * @param nf      The number format object to use for formatting the display of this
060     *                text field.
061     */
062    @SuppressWarnings("OverridableMethodCallInConstructor")
063    public DecimalField(double value, int columns, NumberFormat nf) {
064        super(columns);
065
066        setDocument(new FormattedDocument(nf));
067        format = nf;
068        setValue(value);
069    }
070
071    /**
072     * Return the value represented by the text in this text field. If the text field is
073     * empty, Double.NaN is returned.
074     *
075     * @return The value represented by the text in this text field.
076     */
077    public double getValue() {
078        double retVal = 0.0;
079        String text = getText();
080
081        // Check for blank entries.
082        if (text == null || text.length() == 0)
083            return Double.NaN;
084
085        // Deal with special case of percentage format.
086        if (format instanceof DecimalFormat) {
087            String suffix = ((DecimalFormat)format).getPositiveSuffix();
088            if (suffix.contains("%") && !text.endsWith("%"))
089                text += "%";
090        }
091
092        try {
093            retVal = format.parse(text).doubleValue();
094
095        } catch (ParseException e) {
096            // This should never happen because insertString allows
097            // only properly formatted data to get in the field.
098            Toolkit.getDefaultToolkit().beep();
099            System.err.println("getValue: could not parse: " + text);
100        }
101
102        return retVal;
103    }
104
105    /**
106     * Set the text in this text field to the specified value.
107     *
108     * @param value The value to place in the text field.
109     */
110    public final void setValue(double value) {
111        setText(format.format(value));
112    }
113
114}