![JAR search and dependency download from the Maven repository](/logo.png)
jidefx.scene.control.field.NumberField Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jidefx-fields Show documentation
Show all versions of jidefx-fields Show documentation
JideFX Common Layer is a collection of several extend feature for JavaFX
The newest version!
/*
* @(#)NumberField.java 5/19/2013
*
* Copyright 2002 - 2013 JIDE Software Inc. All rights reserved.
*/
package jidefx.scene.control.field;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.util.StringConverter;
import jidefx.scene.control.field.verifier.FractionDigitsPatternVerifier;
import jidefx.scene.control.field.verifier.IntegerDigitsPatternVerifier;
import jidefx.utils.CommonUtils;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
/**
* A {@code FormattedTextField} for {@link Number}.
*/
public class NumberField extends FormattedTextField {
public static enum NumberType {Normal, Integer, Percent, Currency}
private BooleanProperty _positiveOnlyProperty;
public NumberField() {
setNumberType(NumberType.Normal);
}
public NumberField(NumberType type) {
setNumberType(type);
}
private static final String STYLE_CLASS_DEFAULT = "number-field"; //NON-NLS
@Override
protected void initializeStyle() {
super.initializeStyle();
getStyleClass().addAll(STYLE_CLASS_DEFAULT);
}
@Override
protected void initializeTextField() {
super.initializeTextField();
setSpinnersVisible(true);
}
private boolean isNegative(Number value) {
// null is considered as positive as that matches our default pattern
return value != null && value.doubleValue() < 0;
}
@Override
protected void registerListeners() {
super.registerListeners();
valueProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue extends Number> observable, Number oldValue, Number newValue) {
if (!isNegative(oldValue) && isNegative(newValue)) {
initializePatternVerifiersForDecimalFormat(getDecimalFormat());
}
if (isNegative(oldValue) && !isNegative(newValue)) {
initializePatternVerifiersForDecimalFormat(getDecimalFormat());
}
}
});
}
private ObjectProperty _numberTypeProperty;
public ObjectProperty numberTypeProperty() {
if (_numberTypeProperty == null) {
_numberTypeProperty = new SimpleObjectProperty(this, "numberType") { //NON-NLS
@Override
protected void invalidated() {
super.invalidated();
DecimalFormat format = (DecimalFormat) DecimalFormat.getNumberInstance();
NumberType newValue = get();
switch (newValue) {
case Percent:
format = (DecimalFormat) DecimalFormat.getPercentInstance();
break;
case Currency:
format = (DecimalFormat) DecimalFormat.getCurrencyInstance();
break;
case Normal:
format = (DecimalFormat) DecimalFormat.getNumberInstance();
break;
case Integer:
format = (DecimalFormat) DecimalFormat.getIntegerInstance();
break;
}
format.setGroupingUsed(false);
setDecimalFormat(format);
}
};
}
return _numberTypeProperty;
}
public NumberType getNumberType() {
return numberTypeProperty().get();
}
public void setNumberType(NumberType numberType) {
numberTypeProperty().set(numberType);
}
private ObjectProperty _decimalFormatProperty;
public ObjectProperty decimalFormatProperty() {
if (_decimalFormatProperty == null) {
_decimalFormatProperty = new SimpleObjectProperty(this, "decimalFormat") { //NON-NLS
@Override
protected void invalidated() {
super.invalidated();
initializePatternVerifiersForDecimalFormat(get());
setStringConverter(null);
}
};
}
return _decimalFormatProperty;
}
/**
* Gets the DecimalFormat.
*
* @return the DecimalFormat.
*/
public DecimalFormat getDecimalFormat() {
return decimalFormatProperty().get();
}
/**
* Sets the DecimalFormat that will format the value. We currently only support DateFormat and DecimalFormat.
* Because the way the FormattedTextField works, we will automatically call the following line for any
* DecimalFormats.
* {@code
* DecimalFormat format = ...
* ..
* format.setMinimumFractionDigits(format.getMaximumFractionDigits());
* }
*
* @param format the new DecimalFormat.
*/
public void setDecimalFormat(DecimalFormat format) {
decimalFormatProperty().set(format);
}
public BooleanProperty positiveOnlyProperty() {
if (_positiveOnlyProperty == null) {
_positiveOnlyProperty = new SimpleBooleanProperty(this, "positiveOnly") { //NON-NLS
@Override
protected void invalidated() {
super.invalidated();
initializePatternVerifiersForDecimalFormat(getDecimalFormat());
}
};
}
return _positiveOnlyProperty;
}
/**
* Gets the flag to allow only positive values in the field.
*
* @return true or false.
*/
public boolean isPositiveOnly() {
return positiveOnlyProperty().get();
}
/**
* Sets the flag to allow only positive values in the field.
*
* @param positiveOnly true to allow only possible values. False to allow both negative and positive values.
*/
public void setPositiveOnly(boolean positiveOnly) {
positiveOnlyProperty().set(positiveOnly);
}
@Override
protected String toString(Number value) {
DecimalFormat format = getDecimalFormat();
if (format != null) {
try {
return format.format(value);
}
catch (Exception e) {
CommonUtils.ignoreException(e);
}
}
return super.toString(value);
}
@Override
protected Number fromString(String text) {
DecimalFormat format = getDecimalFormat();
if (format != null) {
try {
return format.parse(text);
}
catch (ParseException e) {
CommonUtils.ignoreException(e);
}
}
return super.fromString(text);
}
@Override
protected boolean supportFromString() {
return getDecimalFormat() != null || super.supportFromString();
}
protected void initializePatternVerifiersForDecimalFormat(DecimalFormat decimalFormat) {
int multiplier = decimalFormat.getMultiplier();
String text = decimalFormat.format((getValue() != null && getValue().doubleValue() < 0 ? -1.2 : 1.2) / (double) multiplier);
text = text.replace("0", "").replace('2', 'f').replace('1', 'n');
final int integerDigits = decimalFormat.getMaximumIntegerDigits();
if (integerDigits >= 1) {
IntegerDigitsPatternVerifier patternVerifier = new IntegerDigitsPatternVerifier(
isPositiveOnly() ? 0 : -(int) Math.pow(10, integerDigits) + 1, (int) Math.pow(10, integerDigits) - 1, 1, multiplier) {
@Override
public Number toTargetValue(Number fieldValue) {
return fieldValue;
}
@Override
public Number fromTargetValue(Number previousFieldValue, Number targetValue) {
return targetValue;
}
};
patternVerifier.setStringConverter(new StringConverter() {
private NumberFormat getIntegerFormat(NumberFormat format) {
NumberFormat instance = NumberFormat.getInstance();
instance.setMaximumIntegerDigits(format.getMaximumIntegerDigits());
instance.setMinimumIntegerDigits(format.getMinimumIntegerDigits());
instance.setMaximumFractionDigits(0);
instance.setGroupingUsed(format.isGroupingUsed());
instance.setParseIntegerOnly(true);
return instance;
}
@Override
public String toString(Number object) {
return getIntegerFormat(decimalFormat).format(object);
}
@Override
public Number fromString(String string) {
try {
return getIntegerFormat(decimalFormat).parse(string);
}
catch (ParseException e) {
CommonUtils.ignoreException(e);
}
return Integer.parseInt(string);
}
});
getPatternVerifiers().put("n", patternVerifier); //NON-NLS
}
if (decimalFormat.getMaximumFractionDigits() >= 1) {
getPatternVerifiers().put("f", new FractionDigitsPatternVerifier(decimalFormat.getMaximumFractionDigits(), multiplier) {
@Override
public Number toTargetValue(Number fieldValue) {
return fieldValue;
}
@Override
public Number fromTargetValue(Number previousFieldValue, Number targetValue) {
return targetValue;
}
});
// we have to enforce the MinimumFractionDigits because the way group works
decimalFormat.setMinimumFractionDigits(decimalFormat.getMaximumFractionDigits());
}
setPattern(text);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy