I am able to retrive the style class(es) of a JavaFx Node "node" with
List<String> styleClasses = node.getStyleClass();
This gives me for example the style class "chart-plot-background".
How can I retrive the corresponding currently active stylesheet entry from the node?
The Caspian.css file contains the entry
.chart-plot-background {
-fx-background-color: #f5f5f5;
}
and I would expect to be able to retrieve this information from the node with at least on of the following code snippets:
A.
Style style = node.getStyle();
//is empty
B.
Parent parent = (Parent) node;
List<String> styleSheets = parent.getStyleSheets();
//... loop through the list and search for the entry...
//however, the list is empty
C.
List<CssMetaData<? extends Styleable, ?>> cssMetaDataList = node.getCssMetaData();
//... loop through the list and search for the entry...
//however, the property "-fx-background-color" is null
Related old article:
Resolving CSS property for node
points to the bug ticket
http://bugs.openjdk.java.net/browse/JDK-8091202
Motivation
I would like to write a converter from JavaFx charts to scalable vector graphic (*.svg) files. In order to do so I need the active properties of each node, e.g. fill color and stroke-width.
Just a note to start: JavaFX 8 uses modena.css
by default, not caspian.css
. Since you are using JavaFX 8 (getCssMetaData()
was introduced in version 8), you want to refer to modena.css
, unless you are using a system property switch to use the old user-agent stylesheet.
This is something of a partial answer; digging into exactly how to do this would take more time than I have. This should get you started though. If someone has already done the work figuring this out, they may be able to provide a more complete answer.
-fx-background-color
is actually a sub-property of -fx-region-background
, as is hinted in the CSS reference for Region
. The code snippet
Region node = (Region)root.lookup(".chart-plot-background");
node.getCssMetaData().stream().filter(p -> p.getProperty().equals("-fx-region-background"))
.findFirst()
.ifPresent(System.out::println);
produces the output
CSSProperty {property: -fx-region-background, converter: javafx.scene.layout.BackgroundConverter@6f457c5c, initalValue: null, inherits: false, subProperties: [CSSProperty {property: -fx-background-color, converter: Paint.SequenceConverter, initalValue: [Ljavafx.scene.paint.Paint;@737bd041, inherits: false, subProperties: []}, CSSProperty {property: -fx-background-insets, converter: InsetsSequenceConverter, initalValue: [Ljavafx.geometry.Insets;@22e4912, inherits: false, subProperties: []}, CSSProperty {property: -fx-background-radius, converter: javafx.scene.layout.CornerRadiiConverter@3d63caf3, initalValue: [Ljavafx.scene.layout.CornerRadii;@7980e69f, inherits: false, subProperties: []}, CSSProperty {property: -fx-background-image, converter: URLSeqType, initalValue: null, inherits: false, subProperties: []}, CSSProperty {property: -fx-background-repeat, converter: RepeatStructConverter, initalValue: [Lcom.sun.javafx.scene.layout.region.RepeatStruct;@54d4d836, inherits: false, subProperties: []}, CSSProperty {property: -fx-background-position, converter: LayeredBackgroundPositionConverter, initalValue: [Ljavafx.scene.layout.BackgroundPosition;@24c26d67, inherits: false, subProperties: []}, CSSProperty {property: -fx-background-size, converter: com.sun.javafx.scene.layout.region.LayeredBackgroundSizeConverter@7550f5e, initalValue: [Ljavafx.scene.layout.BackgroundSize;@791fb535, inherits: false, subProperties: []}]}
which, if you dig into a little, you will see contains
subProperties: [CSSProperty {property: -fx-background-color, converter: Paint.SequenceConverter, initalValue: [Ljavafx.scene.paint.Paint;@737bd041, inherits: false, subProperties: []}, ...]
So the -fx-background-color
is in there.
The way this works, to the best of my knowledge, is that the CssMetaData
objects describe how to map the CSS into an actual JavaFX property (an instance of StyleableProperty
, which is a subclass of WritableValue
. So if you dig through this, you should be able to figure out that -fx-region-background
maps to Region.backgroundProperty()
, and -fx-background-color
maps to the fill
property of each element of Region.getBackground().getFills()
. The code snippet
Background bg = node.getBackground();
bg.getFills().forEach(fill -> System.out.println(fill.getFill()));
produces the output
0xf4f4f4ff
which I believe is the background color defined in modena.css
for the chart-plot-background
.
So if you want to automate this, it seems pretty tricky, albeit possible. You'll need to account for "nested" css meta data, which you can access via getSubProperties()
. You should then be able to call getStyleableProperty().getValue()
, and (possibly by reflection) dig into the resulting object to get the values set by the "subProperties".
Good luck...
Complete code I used for testing:
import java.util.Random;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.Background;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class CssPropertyLookupTest extends Application {
@Override
public void start(Stage primaryStage) {
LineChart<Number, Number> chart = new LineChart<>(new NumberAxis(), new NumberAxis());
chart.setAnimated(false);
Random rng = new Random();
Series<Number, Number> series = new Series<>();
for (int x = 1; x <= 10; x++) {
Data<Number, Number> data = new Data<>(x, rng.nextDouble());
series.getData().add(data);
}
chart.getData().add(series);
Rectangle rect = new Rectangle(400, 20);
BorderPane root = new BorderPane(chart, null, null, rect, null);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
Region node = (Region)root.lookup(".chart-plot-background");
node.getCssMetaData().stream()
.filter(p -> p.getProperty().equals("-fx-region-background"))
.findFirst()
.ifPresent(System.out::println);
Background bg = node.getBackground();
bg.getFills().forEach(fill -> System.out.println(fill.getFill()));
}
public static void main(String[] args) {
launch(args);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With