A Custom Float PropertyEditor
Join the DZone community and get the full member experience.
Join For FreeBoth Java SE and the NetBeans Platform have default property editors for several primitive and common data types. These are suitable for most cases and most of us almost never need to worry about it. There are, however, those few moments where the one-size-fits-all approach does not actually fit. For instance, the default float editor is a text editor:
For general-purpose cases, this should be fine. Now, what if you want to restrict the values your property can have or have other control over it? Or simply give the user a more comfortable control for data input, like a JSpinner:
Most of what I'll show was taken from the NetBeans tutorials and Javadoc, so I will not extend in details what you can find easily there.
First, lets implement the PropertyEditor and the InlineEditor (don't forget to <Shift+Ctrl+I> to fix imports):
public abstract class FloatPropertyEditor
extends PropertyEditorSupport
implements ExPropertyEditor, InplaceEditor.Factory{
protected InplaceEditor ed = null;
protected SpinnerNumberModel model;
public FloatPropertyEditor(Object source, SpinnerNumberModel model) {
super(source);
this.model = model;
}
public FloatPropertyEditor(SpinnerNumberModel model) {
this.model = model;
}
@Override
public String getAsText() {
Float d = (Float)getValue();
if (d == null) {
return "0.0";
}
return NumberFormat.getNumberInstance().format(d.floatValue());
}
@Override
public void setAsText(String s) {
try {
setValue(new Float(
NumberFormat.getNumberInstance().parse(s).floatValue()));
} catch (ParseException ex) {
setValue(Float.valueOf(0.0f));
}
}
@Override
public void attachEnv(PropertyEnv env) {
env.registerInplaceEditorFactory(this);
}
@Override
public InplaceEditor getInplaceEditor() {
if (ed == null) {
ed = new FloatInplaceEditor(model);
}
return ed;
}
protected static class FloatInplaceEditor implements InplaceEditor {
private final JSpinner spinner;
private PropertyEditor editor = null;
private PropertyModel model;
public FloatInplaceEditor(SpinnerNumberModel model) {
this.spinner = new JSpinner(model);
}
@Override
public void connect(PropertyEditor propertyEditor, PropertyEnv env) {
editor = propertyEditor;
reset();
}
@Override
public JComponent getComponent() {
return spinner;
}
@Override
public void clear() {
//avoid memory leaks:
editor = null;
model = null;
}
@Override
public Object getValue() {
return spinner.getValue();
}
@Override
public void setValue(Object object) {
try {
spinner.setValue(object);
} catch (IllegalArgumentException e) {
spinner.setValue(null);
}
}
@Override
public boolean supportsTextEntry() {
return true;
}
@Override
public void reset() {
Float d = (Float) editor.getValue();
if (d != null) {
setValue(d);
}
}
@Override
public KeyStroke[] getKeyStrokes() {
return new KeyStroke[0];
}
@Override
public PropertyEditor getPropertyEditor() {
return editor;
}
@Override
public PropertyModel getPropertyModel() {
return model;
}
@Override
public void setPropertyModel(PropertyModel propertyModel) {
this.model = propertyModel;
}
@Override
public boolean isKnownComponent(Component component) {
return component == spinner || spinner.isAncestorOf(component);
}
@Override
public void addActionListener(ActionListener actionListener) {
//do nothing - not needed for this component
}
@Override
public void removeActionListener(ActionListener actionListener) {
//do nothing - not needed for this component
}
}
}
So far, we've been closely following the tutorials. Notice that the FloatPropertyEditor class is abstract. This is because PropertyEditor classes should have a default constructor (more on this below).
Not much of a gain, maybe, but now you have a JSpinner as an editor. Now imagine you are developing a 3D "bodies in space" application. You can select an item and you can change its dimensions and coordinates at will. Coordinates can have any real value, whether negative, zero, or positive (besides the practical dimensional limits your universe might have), while dimensions must be at least be zero.
This is where the abstract plays its role. By inheriting the class above, you can decide which values our properties can have. For coordinate properties, set this class as PropertyEditor:
public class CoordinateFloatPropertyEditor extends FloatPropertyEditor {
public CoordinateFloatPropertyEditor() {
super(new SpinnerNumberModel(0.0, -100000.0, 100000.0, 0.5));
}
}
And, for dimension properties, use this one, instead:
public class DimensionFloatPropertyEditor extends FloatPropertyEditor {
public DimensionFloatPropertyEditor() {
super(new SpinnerNumberModel(0.0, 0.09999, 100000.0, 0.5));
}
}
It's up to you to decide the maximum, minimum, and step values, and tweak this sample for your needs.
I want also to add that this is part of a real application, from where I was inspired to write this article. I'll be further extending this subject in the next posts.
Thanks for you attention.
Muchas gracias por su atención.
Opinions expressed by DZone contributors are their own.
Comments