I couldn't find any example for a custom Editor
for the PropertySheet
, but I think I figured it out now. In my case I simply want to use a Slider
as an editor for a Number
. This may not be practical, since you would have no way of seeing the value of the Slider, but I imagine the Slider could simply be replaced by a pane with the slider and a label.
To start with, we need our implementation of Item
, here a slightly modified version of the controlsfx-samples. The Map
was moved into this class, but could be anywhere. You might not want to use a map at all though, since it is already somewhat impractical to have the category and the name combined; plus there is no room to create descriptions for the items.
public class CustomPropertyItem implements PropertySheet.Item {
public static Map<String, Object> customDataMap = new LinkedHashMap<>();
static {
customDataMap.put("basic.My Text", "Same text"); // Creates a TextField in property sheet
customDataMap.put("basic.My Date", LocalDate.of(2016, Month.JANUARY, 1)); // Creates a DatePicker
customDataMap.put("misc.My Enum", SomeEnum.ALPHA); // Creates a ChoiceBox
customDataMap.put("misc.My Boolean", false); // Creates a CheckBox
customDataMap.put("misc.My Number", 500); // Creates a NumericField
customDataMap.put("misc.My Color", Color.ALICEBLUE); // Creates a ColorPicker
}
private String key;
private String category, name;
public CustomPropertyItem(String key)
{
this.key = key;
String[] skey = key.split("\\.", 2);
category = skey[0];
name = skey[1];
}
@Override
public Class<?> getType() {
return customDataMap.get(key).getClass();
}
@Override
public String getCategory() {
return category;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
// doesn't really fit into the map
return null;
}
@Override
public Object getValue() {
return customDataMap.get(key);
}
@Override
public void setValue(Object value) {
customDataMap.put(key, value);
}
@Override
public Optional<ObservableValue<? extends Object>> getObservableValue() {
return Optional.empty();
}
@Override
public Optional<Class<? extends PropertyEditor<?>>> getPropertyEditorClass() {
// for an item of type number, specify the type of editor to use
if (Number.class.isAssignableFrom(getType())) return Optional.of(NumberSliderEditor.class);
// ... return other editors for other types
return Optional.empty();
}
}
Next up, the PropertyEditor
implementation, which is a Node
and a set of methods that connect the property item value with a control. The first constructor is necessary for the implementation and the second constructor is needed, because the method Editors.createCustomEditor(Item)
uses reflection to look for this constructor. You do not have to use this method, but the default PropertyEditorFactory most likely relies on this.
If you want to avoid reflection for some reason, you don't need to override getPropertyEditorClass()
in your Item
and you can use setPropertyEditorFactory(Callback)
and create a new instance of your PropertyEditor
in there.
Note that you don't need to use setPropertyEditorFactory(Callback)
at all (in this example).
public class NumberSliderEditor extends AbstractPropertyEditor<Number, Slider> {
public NumberSliderEditor(Item property, Slider control)
{
super(property, control);
}
public NumberSliderEditor(Item item)
{
this(item, new Slider());
}
@Override
public void setValue(Number n) {
this.getEditor().setValue(n.doubleValue());
}
@Override
protected ObservableValue<Number> getObservableValue() {
return this.getEditor().valueProperty();
}
}
From here on you just create your PropertySheet
and add all the map entries.
PropertySheet propertySheet = new PropertySheet();
for (String key : CustomPropertyItem.customDataMap.keySet()) propertySheet.getItems().add(new CustomPropertyItem(key));
I hope this is helpful to anyone, as there don't seem to be any examples out there that show the use of a custom Editor
. The only hint towards this is the javadoc of Item.getPropertyEditorClass()
, which has a default interface implementation so you normally wouldn't look at it. The fact that there is an answer here saying not to look at this method didn't help either :/