I'm trying to use a custom CSS property of type Insets. I have set up a SimpleStyleableObjectProperty<Insets> to hold it, and use StyleConverter.getInsetsConverter() to read it from the CSS file. However, when I set a ChangeListener<Insets> on the property, I get a ClassCastException because the JavaFX runtime is trying to invoke my ChangeListener<Insets>.changed method with a Double as the new value. I think I'm not introducing the Double anywhere myself, but see the code below. Code to reproduce, confirmed exception on Mac OS X 8u5 and 8u20:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.css.CssMetaData;
import javafx.css.SimpleStyleableObjectProperty;
import javafx.css.StyleConverter;
import javafx.css.Styleable;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestInsets extends Application
{
// Sets the VBox insets property via CSS
private static class BorderPaneCustomInsets extends BorderPane
{
private final SimpleStyleableObjectProperty<Insets> frameInsetsProperty = new SimpleStyleableObjectProperty<Insets>(FRAME_INSETS_META_DATA, new Insets(0.0));
public BorderPaneCustomInsets(Node item)
{
// If you change <Insets> to <Object> here, you avoid the exception but can see we are being passed a Double:
frameInsetsProperty.addListener((ChangeListener<Insets>)(a, b, newVal) -> System.out.println(newVal.getClass()));
getChildren().add(item);
BorderPane.setAlignment(item, Pos.CENTER);
getStyleClass().add("myclass");
}
private static final CssMetaData<BorderPaneCustomInsets, Insets> FRAME_INSETS_META_DATA =
cssInsets("-my-frame-insets", b -> b.frameInsetsProperty);
private static final List <CssMetaData <? extends Styleable, ? > > cssMetaDataList = new ArrayList<CssMetaData <? extends Styleable, ? >>() {
{
addAll(BorderPane.getClassCssMetaData());
add(FRAME_INSETS_META_DATA);
}
};
public static List <CssMetaData <? extends Styleable, ? > > getClassCssMetaData() { return cssMetaDataList; }
@Override public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { return getClassCssMetaData(); }
}
public static <T extends Styleable> CssMetaData<T, Insets> cssInsets(String propertyName, Function<T, StyleableObjectProperty<Insets>> propGetter)
{
return new CssMetaData <T, Insets >(propertyName, StyleConverter.getInsetsConverter(), new Insets(0.0)) {
@Override
public boolean isSettable(T node)
{
return true;
}
@Override
public StyleableProperty <Insets> getStyleableProperty(T node) {
return propGetter.apply(node);
}
};
}
@Override
public void start(Stage stage) throws Exception
{
VBox vbox = new VBox();
vbox.getChildren().addAll(new BorderPaneCustomInsets(new Label("Label in pane")) );
Scene scene = new Scene(vbox);
scene.getStylesheets().add("file:custom-insets.css"); // CSS file which contains:
// .myclass {
// -my-frame-insets: 5 0 5 0;
// }
stage.setScene(scene);
stage.show();
}
}
Thankfully, the workaround is quite simple: use 4 Double properties instead of one Insets until this works.
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.css.CssMetaData;
import javafx.css.SimpleStyleableObjectProperty;
import javafx.css.StyleConverter;
import javafx.css.Styleable;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestInsets extends Application
{
// Sets the VBox insets property via CSS
private static class BorderPaneCustomInsets extends BorderPane
{
private final SimpleStyleableObjectProperty<Insets> frameInsetsProperty = new SimpleStyleableObjectProperty<Insets>(FRAME_INSETS_META_DATA, new Insets(0.0));
public BorderPaneCustomInsets(Node item)
{
// If you change <Insets> to <Object> here, you avoid the exception but can see we are being passed a Double:
frameInsetsProperty.addListener((ChangeListener<Insets>)(a, b, newVal) -> System.out.println(newVal.getClass()));
getChildren().add(item);
BorderPane.setAlignment(item, Pos.CENTER);
getStyleClass().add("myclass");
}
private static final CssMetaData<BorderPaneCustomInsets, Insets> FRAME_INSETS_META_DATA =
cssInsets("-my-frame-insets", b -> b.frameInsetsProperty);
private static final List <CssMetaData <? extends Styleable, ? > > cssMetaDataList = new ArrayList<CssMetaData <? extends Styleable, ? >>() {
{
addAll(BorderPane.getClassCssMetaData());
add(FRAME_INSETS_META_DATA);
}
};
public static List <CssMetaData <? extends Styleable, ? > > getClassCssMetaData() { return cssMetaDataList; }
@Override public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { return getClassCssMetaData(); }
}
public static <T extends Styleable> CssMetaData<T, Insets> cssInsets(String propertyName, Function<T, StyleableObjectProperty<Insets>> propGetter)
{
return new CssMetaData <T, Insets >(propertyName, StyleConverter.getInsetsConverter(), new Insets(0.0)) {
@Override
public boolean isSettable(T node)
{
return true;
}
@Override
public StyleableProperty <Insets> getStyleableProperty(T node) {
return propGetter.apply(node);
}
};
}
@Override
public void start(Stage stage) throws Exception
{
VBox vbox = new VBox();
vbox.getChildren().addAll(new BorderPaneCustomInsets(new Label("Label in pane")) );
Scene scene = new Scene(vbox);
scene.getStylesheets().add("file:custom-insets.css"); // CSS file which contains:
// .myclass {
// -my-frame-insets: 5 0 5 0;
// }
stage.setScene(scene);
stage.show();
}
}
Thankfully, the workaround is quite simple: use 4 Double properties instead of one Insets until this works.
- duplicates
-
JDK-8094408 [CSS] Parser doesn't handle <size>{1,4} except for -fx-padding
-
- Resolved
-