9

I have this SVG:

M421.985,229.833L217.847,25.981c-7.235-7.238-16.94-13.374-29.121-18.416C176.541,2.522,165.407,0,155.318,0H36.547 C26.648,0,18.083,3.619,10.85,10.848C3.617,18.081,0.002,26.646,0.002,36.545v118.771c0,10.088,2.519,21.219,7.564,33.404   s11.182,21.792,18.417,28.837L230.118,421.98c7.043,7.043,15.602,10.564,25.697,10.564c9.89,0,18.558-3.521,25.98-10.564   l140.186-140.47c7.043-7.046,10.561-15.604,10.561-25.693C432.542,245.919,429.024,237.258,421.985,229.833z M117.202,117.201   c-7.142,7.138-15.752,10.709-25.841,10.709c-10.085,0-18.699-3.571-25.837-10.709c-7.138-7.139-10.706-15.749-10.706-25.837   c0-10.089,3.568-18.702,10.706-25.837c7.139-7.139,15.752-10.71,25.837-10.71c10.089,0,18.702,3.571,25.841,10.71   c7.135,7.135,10.706,15.749,10.706,25.837C127.908,101.452,124.341,110.062,117.202,117.201z

It's copied from here: http://www.flaticon.com/free-icon/tag-black-shape_25679#term=label&page=1&position=56

I need to have some component (most likely a button), that has this shape, that has size 24x24 and that has some effect on hover (like gradient).

Is that even possible, in JavaFX? CSS border properties don't work with scaling, SVG can't be scaled, I just can't achieve all of these requirements.

fabian
  • 80,457
  • 12
  • 86
  • 114
Patrik Bak
  • 528
  • 1
  • 7
  • 14
  • I think this is helps you.[drawing-a-region-with-css-fx-shape-how-it-is-posible](http://stackoverflow.com/questions/24124819/drawing-a-region-with-css-fx-shape-how-it-is-posible) – CTN Nov 23 '16 at 06:24

1 Answers1

25

You can use the SVG as shape for a Region. Depending on your needs this Region could be the Button itself or a graphic assigned to it:

Button only

Button btn = new Button();
btn.getStyleClass().add("icon-button");
btn.setPickOnBounds(true);

CSS stylesheet

.icon-button {
    -icon-paint: red;
    -fx-background-color: -icon-paint;
    -size: 24;
    -fx-min-height: -size;
    -fx-min-width: -size;
    -fx-max-height: -size;
    -fx-max-width: -size;

    -fx-shape: "M421.985,229.833L217.847,25.981c-7.235-7.238-16.94-13.374-29.121-18.416C176.541,2.522,165.407,0,155.318,0H36.547 C26.648,0,18.083,3.619,10.85,10.848C3.617,18.081,0.002,26.646,0.002,36.545v118.771c0,10.088,2.519,21.219,7.564,33.404   s11.182,21.792,18.417,28.837L230.118,421.98c7.043,7.043,15.602,10.564,25.697,10.564c9.89,0,18.558-3.521,25.98-10.564   l140.186-140.47c7.043-7.046,10.561-15.604,10.561-25.693C432.542,245.919,429.024,237.258,421.985,229.833z M117.202,117.201   c-7.142,7.138-15.752,10.709-25.841,10.709c-10.085,0-18.699-3.571-25.837-10.709c-7.138-7.139-10.706-15.749-10.706-25.837   c0-10.089,3.568-18.702,10.706-25.837c7.139-7.139,15.752-10.71,25.837-10.71c10.089,0,18.702,3.571,25.841,10.71   c7.135,7.135,10.706,15.749,10.706,25.837C127.908,101.452,124.341,110.062,117.202,117.201z";
}

.icon-button:hover {
    -icon-paint: linear-gradient(to bottom, red, black);
}

Button with graphic

Button btn = new Button();
btn.getStyleClass().add("icon-button");
btn.setPickOnBounds(true);

Region icon = new Region();
icon.getStyleClass().add("icon");
btn.setGraphic(icon);

CSS stylesheet

.icon-button {
    -icon-paint: red;
    -fx-content-display: graphic-only;

    -icon-paint: red;
}

.icon-button:hover {
    -icon-paint: linear-gradient(to bottom, red, black);
}

.icon-button .icon {
    -fx-background-color: -icon-paint;
    -size: 24;
    -fx-min-height: -size;
    -fx-min-width: -size;
    -fx-max-height: -size;
    -fx-max-width: -size;

    -fx-shape: "M421.985,229.833L217.847,25.981c-7.235-7.238-16.94-13.374-29.121-18.416C176.541,2.522,165.407,0,155.318,0H36.547 C26.648,0,18.083,3.619,10.85,10.848C3.617,18.081,0.002,26.646,0.002,36.545v118.771c0,10.088,2.519,21.219,7.564,33.404   s11.182,21.792,18.417,28.837L230.118,421.98c7.043,7.043,15.602,10.564,25.697,10.564c9.89,0,18.558-3.521,25.98-10.564   l140.186-140.47c7.043-7.046,10.561-15.604,10.561-25.693C432.542,245.919,429.024,237.258,421.985,229.833z M117.202,117.201   c-7.142,7.138-15.752,10.709-25.841,10.709c-10.085,0-18.699-3.571-25.837-10.709c-7.138-7.139-10.706-15.749-10.706-25.837   c0-10.089,3.568-18.702,10.706-25.837c7.139-7.139,15.752-10.71,25.837-10.71c10.089,0,18.702,3.571,25.841,10.71   c7.135,7.135,10.706,15.749,10.706,25.837C127.908,101.452,124.341,110.062,117.202,117.201z";
}

Results

The Button with a graphic with the shape is shown left, the Button with the shape applied directly to it is shown right.

Edit: to combine multiple paths you could combine several SVGPaths

Update

For more complex icons SVGPaths could be combined to be used as graphic for a button:

private static SVGPath createPath(String d, String fill, String hoverFill) {
    SVGPath path = new SVGPath();
    path.getStyleClass().add("svg");
    path.setContent(d);
    path.setStyle("-fill:" + fill + ";-hover-fill:"+hoverFill+';');
    return path;
}
Group svg = new Group(
        createPath("M0,0h100v100h-100z", "red", "darkred"),
        createPath("M20,20h60v60h-60z", "blue", "darkblue")
);

Bounds bounds = svg.getBoundsInParent();
double scale = Math.min(20/bounds.getWidth(), 20 / bounds.getHeight());
svg.setScaleX(scale);
svg.setScaleY(scale);

Button btn = new Button();
btn.setGraphic(svg);
btn.setMaxSize(30, 30);
btn.setMinSize(30, 30);
btn.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

CSS

.button .svg {
    -fx-fill: -fill;
}

.button:hover .svg {
    -fx-fill: -hover-fill;
}
fabian
  • 80,457
  • 12
  • 86
  • 114
  • Thank you. This was really helpful. But it turns out I can't use this with more complicated svg files, like this: http://image.flaticon.com/icons/svg/214/214340.svg What should I do with this please? There are more paths in the svg...Hint would be enough – Patrik Bak Nov 29 '16 at 01:08
  • Thank you, you helped me a lot. – Patrik Bak Nov 29 '16 at 16:01
  • using javafx 14. Does the scaling have to be done programmatically or can it be done in FXML? – itzjackyscode May 28 '20 at 20:27
  • @itzjackyscode Most JavaFX properties can be assigned in fxml. The only exception being, if you need to initialize types that neither provide a default constructor or constructor with `@NamedArg` annotated arguments not provides a `static` factory method. `scaleX` and `scaleY` can be applied via fxml, e.g.: ``. – fabian May 29 '20 at 05:34
  • Of course you don't have the option of computing it from the original size, but you could create a helper method in a `Utils` class (or similar) `public static void setSizeTransform(double targetSize)` + corresponding getter and use it as ``, but I'm pretty sure SceneBuilder wouldn't like that, if you're using that tool... – fabian May 29 '20 at 05:34