Cristian Zaharia Cristian Zaharia - 7 months ago 38
Java Question

[JavaFX]Cannot change a rectangle color before the stage is iconified

I have this FXML file:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Rectangle?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="900.0" style="-fx-background-color: #b8edff;" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="labelme.gui.skeleton.SkeletonPageController">
<children>
<Rectangle fx:id="minButton" fill="DODGERBLUE" height="50.0" onMouseClicked="#minimizeWindow" onMouseEntered="#changeColorEntered" onMouseExited="#changeColorExited" stroke="BLACK" strokeType="INSIDE" strokeWidth="0.0" width="900.0" />
</children>
</AnchorPane>


And also this class:

public class SkeletonPageController implements Initializable {

@FXML
private Rectangle minButton;

@FXML
private void changeColorEntered(MouseEvent event) {
this.minButton.setStyle("-fx-fill: red;");
}

@FXML
private void changeColorExited(MouseEvent event) {
this.minButton.setStyle("-fx-fill: blue;");
}

@FXML
private void minimizeWindow(MouseEvent event){
Stage window = (Stage)((Rectangle)event.getSource()).getScene().getWindow();
this.minButton.setStyle("-fx-fill: blue;");
window.setIconified(true);
}

@Override
public void initialize(URL url, ResourceBundle rb) {
}
}


I am trying to make a rectangle that turns red/blue when MouseEntered/MouseExited event occurs. Also when I click on it, the stage should be minimized.

The problem is that when MouseClicked event occurs, the stage is iconified, but the rectangle is not changing its color. (When the stage is back maximized, the rectangle is red, instead of blue).

What's the explanation? Somehow, the stage is iconified before the rectangle color is changed? And once the stage is minimized, the color can't be changed anymore?

Answer

This is a bug. You can easily confirm this by registering a listener to the style property of your Button that prints the current style.

This seems to be caused by the UI not having enough time to redraw itself before minimizing the window but considering itself to be up to date when the window is restored.

Give the window enough time to redraw itself before minimizing and the issue is fixed.

Code that works as expected, since it ensures a additional frame occurs before iconifying the window:

@FXML
private void minimizeWindow(MouseEvent event) {
    Stage window = (Stage) ((Rectangle) event.getSource()).getScene().getWindow();
    this.minButton.setStyle("-fx-fill: blue;");

    AnimationTimer timer = new AnimationTimer() {

        int count = 2;

        @Override
        public void handle(long now) {
            if (--count <= 0) {
                window.setIconified(true);
                this.stop();
            }
        }

    };

    timer.start();
}