Ivar Eriksson
Ivar Eriksson

Reputation: 973

JavaFX - Create Button from Icon

I've been into custom controls with JavaFX recently and was wondering what the best way is to create a button that simply is an image. For instance here on Stack Overflow we have these buttons (I suppose that in reality they are links but I want the same effect in JavaFX) that do not look like buttons at all.

enter image description here

What is the best way of creating something similar in JavaFX? I know you can add images to buttons but is there then also a way of completely removing the background (I suspect there is)?

Upvotes: 3

Views: 4942

Answers (3)

Ry-
Ry-

Reputation: 49

Despite this being an old post, it still might be nice for those using a SceneBuilder to know that you can do this with a Button and an ImageView:

(I am using Gluon SceneBuilder)

Button Setup:

Under 'Graphic' set the Display to 'GRAPHIC_ONLY'

Then for the in-line CSS use: -fx-background-colour: transparent;

ImageView:

Set the image to whatever you want
In the 'Hierarchy' pick up and drop the ImageView onto the button

What it looks like when done:

Transparent Button ~ with only Image shown

Upvotes: 2

Zephyr
Zephyr

Reputation: 10253

I use a custom ImageButton class in my projects. This is similar to fabian's approach, but uses an ImageView. It is also a bit simpler to implement, in my view.

public class ImageButton extends Button {

    private final String STYLE_NORMAL = "-fx-background-color: transparent; -fx-padding: 2, 2, 2, 2;";
    private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";

    public ImageButton(Image originalImage, double h, double w) {

        ImageView image = new ImageView(originalImage);
        image.setFitHeight(h);
        image.setFitHeight(w);
        image.setPreserveRatio(true);
        setGraphic(image);
        setStyle(STYLE_NORMAL);

        setOnMousePressed(event -> setStyle(STYLE_PRESSED));
        setOnMouseReleased(event -> setStyle(STYLE_NORMAL));
    }

}

Then you just need to pass it the Image and dimensions:

ImageButton newButton = new ImageButton(new Image("icon.png"), 16, 16);

Upvotes: 5

fabian
fabian

Reputation: 82451

Just set the graphic property of the button accordingly.

Since stackoverflow uses svg paths, the following example uses SVGPath, but it could easily be changed to an ImageView and the scaling could replaced with setting fitWidth/fitHeight. If you do want to use ImageView though, you should be aware of the fact that ImageView does not provide a fill property and you need to work with opacity or with different images instead.

public static Button createIconButton(String svg) {
    SVGPath path = new SVGPath();
    path.setContent(svg);
    Bounds bounds = path.getBoundsInLocal();

    // scale to size 20x20 (max)
    double scaleFactor = 20 / Math.max(bounds.getWidth(), bounds.getHeight());
    path.setScaleX(scaleFactor);
    path.setScaleY(scaleFactor);
    path.getStyleClass().add("button-icon");

    Button button = new Button();
    button.setPickOnBounds(true); // make sure transparent parts of the button register clicks too
    button.setGraphic(path);
    button.setAlignment(Pos.CENTER);
    button.getStyleClass().add("icon-button");

    return button;
}

@Override
public void start(Stage primaryStage) {
    // the following svg paths were copied from the stackoverflow website
    HBox root = new HBox(
            createIconButton("M15.19 1H4.63c-.85 0-1.6.54-1.85 1.35L0 10.79V15c0 1.1.9 2 2 2h16a2 2 0 0 0 2-2v-4.21l-2.87-8.44A2 2 0 0 0 15.19 1zm-.28 10l-2 2h-6l-2-2H1.96L4.4 3.68A1 1 0 0 1 5.35 3h9.12a1 1 0 0 1 .95.68L17.86 11h-2.95z"),
            createIconButton("M15 2V1H3v1H0v4c0 1.6 1.4 3 3 3v1c.4 1.5 3 2.6 5 3v2H5s-1 1.5-1 2h10c0-.4-1-2-1-2h-3v-2c2-.4 4.6-1.5 5-3V9c1.6-.2 3-1.4 3-3V2h-3zM3 7c-.5 0-1-.5-1-1V4h1v3zm8.4 2.5L9 8 6.6 9.4l1-2.7L5 5h3l1-2.7L10 5h2.8l-2.3 1.8 1 2.7h-.1zM16 6c0 .5-.5 1-1 1V4h1v2z"));

    Scene scene = new Scene(root);
    scene.getStylesheets().add("style.css");
    primaryStage.setScene(scene);
    primaryStage.show();
}

style.css

/* set default fill of svg path */
.icon-button .button-icon {
    -fx-fill: #888888;
}

/* set default fill of svg path */
.icon-button:focused {
    -fx-background-color: lightblue;
    -fx-background-radius: 0;
}

/* remove default button style & set size */
.icon-button {
    -fx-background-color: transparent, transparent, transparent, transparent, transparent;
    -fx-pref-height: 30;
    -fx-pref-width: 30;
    -fx-min-height: 30;
    -fx-min-width: 30;
    -fx-max-height: 30;
    -fx-max-width: 30;
}

/* modify svg path fill for hovered/pressed button */
.icon-button:pressed .button-icon,
.icon-button:hover .button-icon {
    -fx-fill: #444444;
}

Upvotes: 5

Related Questions