
nu.zoom.swing.field.FloatField Maven / Gradle / Ivy
/*
* Copyright (C) 2004 Johan Maasing johan at zoom.nu Licensed under the Apache
* License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
* or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package nu.zoom.swing.field;
import java.text.*;
import java.awt.Toolkit;
import javax.swing.*;
import javax.swing.text.*;
/**
* This class implements a swing JTextField which only accepts float numbers. It
* does so by checking anything entered in the field and at all times it must be
* parsable as a float value. This means you can't enter plain text or other
* symbols in the field. It has some utility methods to put and retrieve the
* float value directly.
* Default values for the field are approx. 11 columns width. The formatter used
* is initialized to display max 6 integer numbers, max 6 fraction numbers and
* min 1 fraction number. This will be noticeable by e.g. using
* setValue(0.123456789f) ;
where the field will truncate the value to
* 0.123456. To change these default values you can retrieve the formatter by
* the get/setFormatter methods.
* In the spirit of most of Swing this class is not thread safe.
*
* @author $Author: johan $
* @version $Revision: 1.2 $
*/
@SuppressWarnings("serial")
public class FloatField extends JTextField {
protected DecimalFormat formatter;
/**
* Constructs a FloatField with the default values and initialized to 0.0.
*/
public FloatField() {
super(11);
setDocument(new TexCoordDocument());
formatter = new DecimalFormat();
formatter.setMaximumFractionDigits(6);
formatter.setMinimumFractionDigits(1);
formatter.setMaximumIntegerDigits(6);
formatter.setDecimalSeparatorAlwaysShown(true);
formatter.setGroupingUsed(false);
setValue(0.0f);
}
/**
* Constructs a FloatField with the default values and initialized with a
* value.
*
* @param value
* The intitial float value the field will display.
*/
public FloatField(float value) {
super(11);
setDocument(new TexCoordDocument());
formatter = new DecimalFormat();
formatter.setMaximumFractionDigits(6);
formatter.setMinimumFractionDigits(1);
formatter.setMaximumIntegerDigits(6);
formatter.setDecimalSeparatorAlwaysShown(true);
formatter.setGroupingUsed(false);
setValue(value);
}
/**
* Constructs a FloatField with the default values and initialized with a
* value.
*
* @param value
* The intitial float value the field will display.
* @param enabled
* Indicates if the field should initially be enabled for
* editing.
*/
public FloatField(float value, boolean enabled) {
super(11);
setDocument(new TexCoordDocument());
formatter = new DecimalFormat();
formatter.setMaximumFractionDigits(6);
formatter.setMinimumFractionDigits(1);
formatter.setMaximumIntegerDigits(6);
formatter.setDecimalSeparatorAlwaysShown(true);
formatter.setGroupingUsed(false);
setValue(value);
setEnabled(enabled);
}
/**
* Retrieves the float value displayed in the field. There is one case where
* the field could actually be considered legal but still not contain a
* float value, that is if the field have been emptied in which case an
* exception will be thrown.
*
* @return The value currently in the field.
* @throws ParseException
* If the field does not contain a legal float value.
*/
public float getValue() throws ParseException {
Number ret = formatter.parse(getText());
return ret.floatValue();
}
/**
* Set the value the field displays.
*
* @param value
* The new value the field should display.
*/
public void setValue(float value) {
String t = formatter.format(value);
// This is the verbatim of the setText in JTextComponent
try {
Document doc = getDocument();
doc.remove(0, doc.getLength());
doc.insertString(0, t, null);
} catch (BadLocationException e) {
getToolkit().beep();
}
}
/**
* Get a reference to the formatter the field uses to parse and format to
* displayed number.
*
* @return The DecimalFormat object this field uses to format the output and
* validate the input.
*/
public DecimalFormat getFormat() {
return formatter;
}
/**
* Set the formatter the field uses to parse and format numbers.
*
* @param format
* The DecimalFormat the field should use in parsing and
* formatting the value.
*/
public void setFormat(DecimalFormat format) {
formatter = format;
}
/**
* Overriden document to handle the validation of the value.
*/
class TexCoordDocument extends PlainDocument {
ParsePosition ppos = new ParsePosition(0);
TexCoordDocument() {
super();
}
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
// Check special cases
if ((str == null) || (str == "")) {
// Empty string or null is special case.
// They don't parse to a legal number but should be
// allowed anyway to clear the text field
int len = getLength();
try {
remove(0, len);
} catch (Exception exc) {
System.err.println(exc.toString());
}
return;
}
// Ordinary case, construct the proposed resulting string
// and see if it parses to a number.
// If the proposed result is not a number, beep the speaker
// and ignore the change.
String currentText = getText(0, getLength());
String beforeOffset = currentText.substring(0, offs);
String afterOffset = currentText.substring(offs, currentText.length());
String proposedResult = beforeOffset + str + afterOffset;
ppos.setIndex(0);
formatter.parseObject(proposedResult, ppos);
// Now check if the entire string could be parsed
if (ppos.getIndex() == proposedResult.length()) {
// Parsed OK
super.insertString(offs, str, a);
} else {
// Parse failed
Toolkit.getDefaultToolkit().beep();
}
}
public void remove(int offs, int len) throws BadLocationException {
String currentText = getText(0, getLength());
String beforeOffset = currentText.substring(0, offs);
String afterOffset = currentText.substring(len + offs, currentText.length());
String proposedResult = beforeOffset + afterOffset;
if (proposedResult.length() == 0) {
// Just empty the document
super.remove(offs, len);
} else {
ppos.setIndex(0);
formatter.parseObject(proposedResult, ppos);
// Now check if the entire string could be parsed
if (ppos.getIndex() == proposedResult.length()) {
// Parsed OK
super.remove(offs, len);
} else {
// Parse failed
Toolkit.getDefaultToolkit().beep();
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy