Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change icon on mouse over

I want to create button which changes the default picture when I move mouse over. I made this example but it's not working properly:

public class MainApp extends Application
{
    @Override
    public void start(Stage stage) throws Exception
    {
        StackPane bp = new StackPane();
        bp.getChildren().add(ReportsIcon());
        bp.setPrefSize(600, 600);

        Scene scene = new Scene(bp);
        scene.setFill(Color.ANTIQUEWHITE);

        stage.setTitle("JavaFX and Maven");
        stage.setScene(scene);
        stage.show();
    }

    private static final ImageView ReportsFirstIcon;

    static
    {
        ReportsFirstIcon = new ImageView(MainApp.class.getResource("/images/monitoring-colour.png").toExternalForm());
    }

    private static final ImageView RportsIconsSecond;

    static
    {
        RportsIconsSecond = new ImageView(MainApp.class.getResource("/images/monitoring-green.png").toExternalForm());
    }

    private HBox ReportsIcon()
    {
        HBox bpi = new HBox();
        bpi.setAlignment(Pos.CENTER);
        // Add Label to the Icon
        Text inftx = new Text("Reports");
        inftx.setFont(Font.font("Verdana", FontWeight.NORMAL, 13));   // Set font and font size
        inftx.setFill(Color.BLACK); // Set font color

        // Zoom into the picture and display only selected area
        Rectangle2D viewportRect = new Rectangle2D(0, 0, 0, 0);
        ReportsFirstIcon.setViewport(viewportRect);
        BorderPane pp = new BorderPane();
        pp.setCenter(ReportsFirstIcon);

        bpi.getChildren().addAll(pp, inftx);

        bpi.setOnMouseEntered(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent t)
            {
                pp.setCenter(ReportsFirstIcon);
            }
        });

        bpi.setOnMouseExited(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent t)
            {
                pp.setCenter(RportsIconsSecond);
            }
        });

        bpi.setOnMouseClicked(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent t)
            {
                // Open new window
            }
        });

        return bpi;
    }

    private HBox mouseOver(final HBox bp)
    {
        bp.setOnMouseEntered(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent t)
            {
                bp.setStyle("-fx-background-color: linear-gradient(#f2f2f2, #f2f2f2);"
                    + "  -fx-background-insets: 0 0 -1 0, 0, 1, 2;"
                    + "  -fx-background-radius: 3px, 3px, 2px, 1px;");
            }
        });

        bp.setOnMouseExited(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent t)
            {
                bp.setStyle("-fx-background-color: linear-gradient(#f2f2f2, #d4d4d4);"
                    + "  -fx-background-insets: 0 0 -1 0, 0, 1, 2;"
                    + "  -fx-background-radius: 3px, 3px, 2px, 1px;");
            }
        });

        return bp;
    }

    public static void main(String[] args)
    {
        launch(args);
    }

}

Now the code in not working properly the original image is not returned back when I move the mouse outside of the Second BorderPane which is used to hold the picture. Picture is changed when I move the mouse outside of the stage. Any ideas how to fix this?

I want to show by default the first picture and when I move the mouse over it to replace it with the second. When I move the mouse outside I want to restore the original picture.

like image 963
Peter Penzov Avatar asked Dec 25 '22 22:12

Peter Penzov


1 Answers

Solution Approach

You can bind the button's graphic property to an appropriate ImageView based upon the button's hover property.

button.graphicProperty().bind(
    Bindings.when(
        button.hoverProperty()
    )
        .then(meatView)
        .otherwise(lambView)
);

Unhovered:

unhovered

Hovered:

hovered

Executable Sample

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.StackPane;
import javafx.scene.text.*;
import javafx.stage.Stage;

public class MuttonMorph extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        ImageView lambView = new ImageView(
                new Image(
                        lambLoc
                )
        );

        ImageView meatView = new ImageView(
                new Image(
                        meatLoc
                )
        );

        Button button = new Button("Lamb,\nit's what's for dinner");
        button.setContentDisplay(ContentDisplay.TOP);
        button.setTextAlignment(TextAlignment.CENTER);
        button.setFont(Font.font(16));

        button.graphicProperty().bind(
                Bindings.when(
                        button.hoverProperty()
                )
                        .then(meatView)
                        .otherwise(lambView)
        );

        StackPane layout = new StackPane(button);
        layout.setPadding(new Insets(30));

        stage.setScene(new Scene(layout));
        stage.show();
    }

    // Icons are Linkware (Backlink to http://icons8.com required)
    private static final String lambLoc = "http://icons.iconarchive.com/icons/icons8/ios7/96/Animals-Sheep-icon.png";
    private static final String meatLoc = "http://icons.iconarchive.com/icons/icons8/ios7/96/Food-Lamb-Rack-icon.png";
}

Alternate Approach

You could probably do a similar thing without a binding by setting by defining appropriate CSS style rules based on the button's :hover CSS pseudo-class and -fx-graphic attribute.

like image 195
jewelsea Avatar answered Dec 28 '22 06:12

jewelsea