As far as I am concerned -fx-shape
and -fx-background-image
don't work together.
JavaFX CSS offers a lot of styling options ... however there are some limitations and some things are only possible with programming. JavaFX CSS uses impl_setShape()
to coarse the Region class to the defined shape (which is market as deprecated in the api but you can still try it out in javafx 2.2 - which I am using at the moment). Adding the background image ignores the shape and fills the whole pane/region, the same happens if you use addChildren to add ImageView objects into it. So - the css string will not translate into the result you would like.
So I can think of at least 2 ways of applying a pattern to a custom SVGPath shape.
The one I would use is done with ImagePattern. First build the shape like this
SVGPath shape = new SVGPath();
shape.setContent("M0 0 L0 50 L25 25 L50 50 L50 0 Z");
or using shape builder
SVGPath shape = SVGPathBuilder.create()
.content("M0 0 L0 50 L25 25 L50 50 L50 0 Z")
.build();
and then set the image pattern as fill
Image img = new Image("myjavafxapp/resources/texture_bg.png");
shape.setFill(new ImagePattern(img,0,0,10,10,false));
An alternative would use clipping (adding a custom shape clip to a pane with -fx-background-image set in the css style), which would look somewhat like this
Pane test = new Pane();
test.setStyle(" -fx-background-image: url(\"myjavafxapp/res/index.jpeg\");");
SVGPath shape = new SVGPath();
shape.setContent("M0 0 L0 50 L25 25 L50 50 L50 0 Z");
test.setClip(shape);
One of these should do the trick - you get your shape with the textured background. This is the equivalent to what you would expect from a Region or Pane class with style
.myTextureShape {
-fx-shape: "M0 0 L0 50 L25 25 L50 50 L50 0 Z";
-fx-scale-shape: false;
-fx-background-image: url("myjavafxapp/resources/texture_bg.png");
-fx-background-repeat: repeat;
}
So the SVGPath shape is like all Shape classes nonresizable, in contrast to Region/Pane, this is why I set here the -fx-scale-shape
attribute to false. The way you had it was with the default setting - which is setting it to true - which makes the shape fill out the whole parent object ... from which I guess that this would be also your desired result. ... there are now again multiple ways of making the shape scale to the parent object.
I got it to work using Group to embed the shape and with a method translating the group (the image size needs to be adjusted in the ImagePattern, so that the texture doesn't scale with the shape). I'm adding a tiny working app, which I used to see on the above example if I remember everything correctly. (if you would like the shape to scale proportionally, you use the same scale factor instead of scalex and sclaey in the addScale method)
package myjavafxapp;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.SVGPath;
import javafx.scene.shape.SVGPathBuilder;
import javafx.scene.image.Image;
import javafx.scene.paint.*;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
/**
* @author martint
*/
public class MyJavaFXApp extends Application {
private final static String svg = "M0 0 L0 50 L25 25 L50 50 L50 0 Z";
private SVGPath shape;
private Image img;
private Pane resizePane;
private Group shapeGroup;
private Node content;
@Override
public void start(final Stage primaryStage) {
//build the SVGPath shape
shape = SVGPathBuilder.create().content(svg).build();
img = new Image("myjavafxapp/res/index.jpeg");
resizePane = new Pane();
shapeGroup = new Group();
resizePane.getChildren().add(shapeGroup);
StackPane root = new StackPane();
root.getChildren().add(resizePane);
Scene scene = new Scene(root, 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
//fill node content
content = nodeCont();
shapeGroup.getChildren().add(content);
//resizing listening
resizePane.widthProperty().addListener(new ChangeListener<Number>(){
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
addScaling();
}});
resizePane.heightProperty().addListener(new ChangeListener<Number>(){
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
addScaling();
}});
Platform.runLater(new Runnable() {
@Override
public void run() {
addScaling();
}
});
}
private Node nodeCont() {
Group cont = new Group();
cont.getChildren().add(shape);
return cont;
}
private void addScaling() {
shapeGroup.getTransforms().clear();
//shape boundary
double cx = content.getBoundsInParent().getWidth();
double cy = content.getBoundsInParent().getHeight();
//resizePane boundary
double px = resizePane.getWidth();
double py = resizePane.getHeight();
//if pane set
if (px > 0.0 && py > 0.0) {
//scale
double scalex = px/cx;
double scaley = py/cy;
//center
double centerx = 0.5 * (px - cx*scalex);
double centery = 0.5 * (py - cy*scaley);
//transform
shapeGroup.getTransforms().add(new Translate(centerx, centery));
shapeGroup.getTransforms().add(new Scale(scalex, scaley));
shape.setFill(new ImagePattern(img,0,0,10/scalex,10/scaley,false));
}
}
public static void main(String[] args) {
launch(args);
}
}