JavaFX Transition - Darken button on hover - button

I'm a beginner in JavaFX. I'm trying to create my own Button subclass that would have its on animations for mouse enter and mouse exit. The animation I'm trying to achieve is a simple "darken" or "dim" transition that would darken the color of the button background when user hovers over the button , and would animate back to normal state when the mouse exits the button.
First I thought I can achieve this with FillTransition, but for that I would need the specific darker color of the button, that depends on the button color.
So now I'm trying to basically fade in and fade out a low-opacity black rectangle on top of the button, but the rectangle doesn't seem to appear at all.
Here's the code of my button:
public class FlatButton extends Button {
private Rectangle dimRectangle;
private Duration dimDuration = Duration.millis(250);
private Color dimColor = new Color(0,0,0,0.11);
public FlatButton(String text) {
super(text);
getStyleClass().addAll("flat-button-style");
createEffect();
}
private void createEffect()
{
dimRectangle = new Rectangle(this.getWidth(), this.getHeight(), dimColor);
dimRectangle.setOpacity(1.0);
dimRectangle.setX(this.get);
FadeTransition enterTransition = new FadeTransition(dimDuration, this);
enterTransition.setInterpolator(Interpolator.EASE_OUT);
enterTransition.setFromValue(0.0);
enterTransition.setToValue(1.0);
FadeTransition exitTransition = new FadeTransition(dimDuration, this);
exitTransition.setInterpolator(Interpolator.EASE_OUT);
exitTransition.setFromValue(1.0);
exitTransition.setToValue(0.0);
this.setOnMouseEntered(new EventHandler<MouseEvent>(){
public void handle(MouseEvent mouseEvent){
enterTransition.play();
}
});
this.setOnMouseExited(new EventHandler<MouseEvent>(){
public void handle(MouseEvent mouseEvent){
exitTransition.play();
}
});
}
}
EDIT: The part in the code "new FadeTransition(dimDuration, this);" should be "new FadeTransition(dimDuration, dimRectangle);". It's just something I was testing.
EDIT2: I figured that "dimRectangle = new Rectangle(this.getWidth(), this.getHeight(), dimColor);" is not really working , but I havent found a way yet how to make the rectangle fill the button dimensions.

You could use a ColorAdjust effect and change it's brightness property using a Timeline.
public class ButtonFadeDemo extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Button button = new Button("Click me!");
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setBrightness(0.0);
button.setEffect(colorAdjust);
button.setOnMouseEntered(e -> {
Timeline fadeInTimeline = new Timeline(
new KeyFrame(Duration.seconds(0),
new KeyValue(colorAdjust.brightnessProperty(), colorAdjust.brightnessProperty().getValue(), Interpolator.LINEAR)),
new KeyFrame(Duration.seconds(1), new KeyValue(colorAdjust.brightnessProperty(), -1, Interpolator.LINEAR)
));
fadeInTimeline.setCycleCount(1);
fadeInTimeline.setAutoReverse(false);
fadeInTimeline.play();
});
button.setOnMouseExited(e -> {
Timeline fadeOutTimeline = new Timeline(
new KeyFrame(Duration.seconds(0),
new KeyValue(colorAdjust.brightnessProperty(), colorAdjust.brightnessProperty().getValue(), Interpolator.LINEAR)),
new KeyFrame(Duration.seconds(1), new KeyValue(colorAdjust.brightnessProperty(), 0, Interpolator.LINEAR)
));
fadeOutTimeline.setCycleCount(1);
fadeOutTimeline.setAutoReverse(false);
fadeOutTimeline.play();
});
root.getChildren().addAll(button);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX: Mouse Hover event for a PopOver (ControlsFX)

I am having the following code to display a PopOver
#Override
public void start(Stage primaryStage) {
try {
Label lblName = new Label("Tetsing name");
Label lblStreet = new Label("Some street name");
Label lblCityStateZip = new Label("Some city, 111111");
VBox vBox = new VBox(lblName, lblStreet, lblCityStateZip);
PopOver popOver = new PopOver(vBox);
Label label = new Label("Mouse mouse over me");
label.setOnMouseEntered(mouseEvent -> {
popOver.show(label, -3);
});
label.setOnMouseExited(mouseEvent -> {
if (popOver.isShowing()) {
popOver.hide();
}
});
StackPane root = new StackPane();
root.getChildren().add(label);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest((WindowEvent event) -> {
System.exit(0);
});
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
The problem is ,
I want the pop-up to be displayed when mouse entered the Label - works fine.
I want the pop-up to be hidden when user exits mouse from Label but not if he enters mouse in to the pop-up window.
I have added MouseEntered and MouseExited actions on Label but how can i handle the another scenario where i don't want to hide the pop-up if user enters mouse in to pop-up.

How to disable right click on a menu in javafx

In javaFX code, a menu can popup by left click or right click. How to disable right click?
public void start(Stage primaryStage)
{
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
When I right click the "hello" menu, it will popup menuitem "laugh".
The basic approach is to register a eventFilter on the MenuBar that consumes the events that should not be delivered to the children.
Doing so manually in your application code:
public class DisableRightClickOpenMenu extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you want this behaviour across all your applications, you can implement a custom menuBarSkin that registers the filter and install the custom skin via a stylesheet.
The skin:
public class ExMenuBarSkin extends MenuBarSkin {
/**
* Instantiates a skin for the given MenuBar. Registers an
* event filter that consumes right mouse press.
*
* #param menuBar
*/
public ExMenuBarSkin(MenuBar menuBar) {
super(menuBar);
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
}
}
In your stylesheet (replace with your fully qualified class name):
.menu-bar {
-fx-skin: "de.swingempire.fx.event.ExMenuBarSkin";
}
Its usage (replace the name with your stylesheet file name):
URL uri = getClass().getResource("contextskin.css");
primaryStage.getScene().getStylesheets().add(uri.toExternalForm());
This is usual behavior of menu in many programs. I don't think you can change it. However, you can use some other controls and simulate menu. (Like HBox and Labels).
I agree as far as I know there's no a standard way to do this, but you may want to consider the following workaround.
It is replacing the Menu node with a Menu object composed by an HBox and a Label: an EventHandler is added to the HBox and by checking the mouse button pressed we add/remove on the fly the MenuItem to its parent.
#Override
public void start(final Stage primaryStage) {
final BorderPane root = new BorderPane();
final MenuBar menuBar = new MenuBar();
final Menu menuHello = new Menu();
final Menu menuWorld = new Menu("world");
final MenuItem menuitem = new MenuItem("laugh");
final HBox hbox = new HBox();
menuBar.getMenus().addAll(menuHello, menuWorld);
root.setCenter(menuBar);
hbox.setPrefWidth(30);
hbox.getChildren().add(new Label("hello"));
menuHello.setGraphic(hbox);
menuHello.getItems().add(menuitem);
hbox.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent e) {
if (e.getButton() == MouseButton.SECONDARY) {
System.out.println("Right click");
menuHello.getItems().remove(menuitem);
} else {
System.out.println("Left click");
if (!menuHello.getItems().contains(menuitem)) {
menuHello.getItems().add(menuitem);
menuHello.show(); // The .show method prevent 'losing' the current click }
}
}
});
final Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
This will produce the following result - preview
Note that I've used an HBox just for habit, there's no a particular reason.
While using a workaround like this, my suggestion would be to fill all the Menus with the same 'pattern', such as the HBox + Label combo in my example, and stylize them via css/code (width/height, background/fill/hover... colors etc.) in order to have them as uniform as possible and avoid creating graphic inconsistencies due to have different nodes types in the same menubar.

JAVAFX binding imageview on button(responsive)

Here i would like to create a responsive button alongwith imageview,but the problem is imageview not binding properly with button and if i clicked on the button or try to resize the window, automatically the image size increeses and lot of irrelevent scaling problems occuring,eventhough i have'nt set an eventhandler for that button.
This is my sample code
public class ImageController extends Application{
private DoubleProperty fontSize = new SimpleDoubleProperty(10);
#Override
public void start(Stage primaryStage) {
FlowPane fp=new FlowPane(); //here i used flowpane to make imagegallery(productview) that will be in responsive in thier position and i tested my problem not with the flowpane
for(int j=0;j<1;j++)
{
try {
Button button = new Button();
button.styleProperty().bind(Bindings.concat("-fx-font-size: ", fontSize.asString(), ";")); //button size binded to the scene
FileInputStream input = new FileInputStream("images/wine.png");
Image image = new Image(input, 100, 100, true,true);
ImageView imageView=new ImageView(image);
imageView.setPreserveRatio(true);
imageView.fitWidthProperty().bind(button.widthProperty()); //image size binded to the button
imageView.fitHeightProperty().bind(button.heightProperty());
button.setGraphic(imageView);
fp.getChildren().add(button);
} catch (FileNotFoundException ex) {
Logger.getLogger(ImageController.class.getName()).log(Level.SEVERE, null, ex);
}
}
Scene scene = new Scene(fp, 500, 500);
fontSize.bind(scene.widthProperty().add(scene.heightProperty()).divide(50));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
you can see my problem dairectly by running my code and resize the window or clicking on button.I need a button alongwith imageview both will resize according to screen resize(responsive)that's all.ThankYou in advance

Why my JavaFX ImageView is not showing/hiding using the Fade Transition?

I m trying to add a fade transition to my login and logout ImageViews, I tried to use the same pattern as the JFeonix Hamburger, I also used some tutorial at oracle docs but, there is no fade transition my ImageViews are hiding and showing instantly. What I'm missing ?
below is my code :
#FXML
private JFXHamburger menu;
#FXML
private ImageView login;
#FXML
private ImageView logout;
private LoginLogic logic;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
final HamburgerSlideCloseTransition slideCloseTransition = new HamburgerSlideCloseTransition(menu);
slideCloseTransition.setRate(-1);
FadeTransition t = new FadeTransition(new Duration(3000), login);
FadeTransition t1 = new FadeTransition(new Duration(3000), logout);
t.setCycleCount(1);
t1.setCycleCount(1);
t.setAutoReverse(false);
t1.setAutoReverse(false);
t.setRate(-1);
t1.setRate(-1);
menu.addEventHandler(MouseEvent.MOUSE_PRESSED, (MouseEvent event) -> {
t1.setRate(t1.getRate() * -1);
t.setRate(t.getRate() * -1);
slideCloseTransition.setRate(slideCloseTransition.getRate() * -1);
slideCloseTransition.play();
t.play();
t1.play();
login.setVisible(!login.isVisible());
logout.setVisible(!logout.isVisible());
});
}
Thanks.
You're not changing the look of the node with the FadeTransition, since you're still using the default values for fromValue, toValue and byValue.
This means effectively you simply toggle the visibility on and off...
Usually only the opacity is modified by a FadeTransition.
Example:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("fade in/out");
ImageView image = new ImageView("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png");
image.setOpacity(0);
VBox root = new VBox(10, btn, image);
root.setPadding(new Insets(10));
FadeTransition t = new FadeTransition(Duration.seconds(3), image);
t.setCycleCount(1);
t.setAutoReverse(false);
t.setRate(-1);
t.setFromValue(0);
t.setToValue(1);
btn.setOnAction(evt -> {
t.setRate(t.getRate() * -1);
t.play();
});
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

How to give a fade background when a new window appears in java fx?

I want to bring a fade effect when a new window appears. Also nothing should be possible without closing the window. My code to open the new window when a button is pressed in given below :
Button b4 = new Button("ABOUT");
b4.setFont(Font.font("Calibri", FontWeight.BOLD, 17));
b4.setPrefSize(100, 30);
b4.setStyle(" -fx-base: #ffffff;");
b4.setTextFill(Color.BLACK);
b4.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
Stage usrpagestage = new Stage();
usrpagestage.setMaxHeight(160);
usrpagestage.setMaxWidth(210);
usrpagestage.setResizable(false);
usrpagestage.initStyle(StageStyle.UTILITY);
usrpagestage.setScene(new Scene(new About()));
usrpagestage.show();
}
});
The current look of my 2 windows is given below. I only want to make visible the small window and the rest should appear as faded. How can I do it ?
try this..
b4.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
//Before open a add effect here
anchpane.setEffect(new BoxBlur(5, 10, 10)); // anchpane is anchor pane of main stage. change values of efect according your need. you can use any kind of pane of scene.
Stage usrpagestage = new Stage();
usrpagestage.setMaxHeight(160);
usrpagestage.setMaxWidth(210);
usrpagestage.setResizable(false);
usrpagestage.initStyle(StageStyle.UTILITY);
usrpagestage.setScene(new Scene(new About()));
usrpagestage.show();
}
});
Look like :
When you close the stage set it to default.
usrpagestage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
anchpane.setEffect(new BoxBlur(0, 0, 0));
}
});

Resources