JavaNoob JavaNoob - 5 months ago 8
Java Question

Get the size of a scene to which a custom control is added at the control's class definition

I have a ripple button that once it's clicked, plays a ripple effect animation.
Inside of the button's skin, there's a

Circle
whose opacity is set to
0
at the beginning of the execution of the program and once the button is clicked, the opacity is set to
1
and the radius of the button gets larger.

There is a
DoubleBinding
binding, whose definition is the following:

DoubleBinding circleRippleRadius = new DoubleBinding() {
{
bind(heightProperty(), widthProperty()); // Sets the parameters of the bind method.
}

@Override // Overrides the computeValue method, which computes the value of the binding.
protected double computeValue() {
return Math.max(heightProperty().get(), widthProperty().get()); // Return the greatest of both numbers
}
};


Instead of using the button's
heightProperty
and
widthProperty
properties, I'd like to use the height and width of the scene to which the button is added, since I want the circle that appears once the button is clicked to fill the entire screen.

How could I achieve this?

UPDATE: Here is the code that defines the animation's component's values and the animation itself:

private void createRippleEffect(Circle circleRipple) {

circleRipple.setOpacity(1.0); // Sets the opacity of the circleRipple to 0, since it must not be showed yet.

/*Fade Transition*/
FadeTransition fadeTransition = new FadeTransition(RIPPLE_DURATION, circleRipple);
fadeTransition.setInterpolator(Interpolator.EASE_OUT);
fadeTransition.setFromValue(1.0); // Sets the opacity to %100
fadeTransition.setToValue(1.0); // The opacity doesn't change.

/*Scale Transition*/
Timeline scaleRippleTimeline = new Timeline();

NumberBinding circleRippleRadius =
Bindings.max(Bindings.selectDouble(sceneProperty(), "width"),
Bindings.selectDouble(sceneProperty(), "height"));

circleRippleRadius.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { // Each time it changes
KeyValue scaleValue = new KeyValue(circleRipple.radiusProperty(), newValue, Interpolator.EASE_OUT);
KeyFrame scaleFrame = new KeyFrame(RIPPLE_DURATION, scaleValue);
scaleRippleTimeline.getKeyFrames().add(scaleFrame);
});

private void createRippleEffect(Circle circleRipple) {

circleRipple.setOpacity(1.0); // Sets the opacity of the circleRipple to 0, since it must not be showed yet.

/*Fade Transition*/
FadeTransition fadeTransition = new FadeTransition(RIPPLE_DURATION, circleRipple);
fadeTransition.setInterpolator(Interpolator.EASE_OUT);
fadeTransition.setFromValue(1.0); // Sets the opacity to %100
fadeTransition.setToValue(1.0); // The opacity doesn't change.

/*Scale Transition*/
Timeline scaleRippleTimeline = new Timeline();

NumberBinding circleRippleRadius =
Bindings.max(Bindings.selectDouble(sceneProperty(), "width"),
Bindings.selectDouble(sceneProperty(), "height"));

circleRippleRadius.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { // Each time it changes
KeyValue scaleValue = new KeyValue(circleRipple.radiusProperty(), newValue, Interpolator.EASE_OUT);
KeyFrame scaleFrame = new KeyFrame(RIPPLE_DURATION, scaleValue);
scaleRippleTimeline.getKeyFrames().add(scaleFrame);
});

SequentialTransition rippleTransition = new SequentialTransition(); // The circle must change its opacity and scale at the same time
rippleTransition.getChildren().addAll(
scaleRippleTimeline,
fadeTransition
);

ParallelTransition parallelTransition = new ParallelTransition();

getStyleClass().addListener((ListChangeListener.Change<? extends String> c) -> { // Don't pay attention to this. The style changes if
// the CSS file has "toggle" or "flat" inside its list,
// but these are never added so it doesn't matter.
if (c.getList().indexOf("flat") == -1 && c.getList().indexOf("toggle") == -1) {
setMinWidth(88);
setEffect(new DropShadow(BlurType.GAUSSIAN, Color.rgb(0, 0, 0, 0.30), 5, 0.10, 0, 2));
parallelTransition.getChildren().addAll(rippleTransition); // parallelTransition is basically the same as rippleTransition, since
// "toggle" and "flat" are never added to the CSS's list.
} else {

parallelTransition.getChildren().addAll(rippleTransition);
setMinWidth(USE_COMPUTED_SIZE);
setEffect(null);
}
});

this.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
parallelTransition.stop(); // In case that the parallelTransition is already running, stop it.
circleRipple.setOpacity(0.0); // Sets the opacity of the circle to 0, since the animation must play from he beginning.
circleRipple.setRadius(0.1); // Sets the radius to 0.1 for the same reason as the circle's opacity.
circleRipple.setCenterX(event.getX()); // The center of the circle is the location in which the mouse was clicked.
circleRipple.setCenterY(event.getY()); // The center of the circle is the location in which the mouse was clicked.
parallelTransition.playFromStart(); // Plays the animation.

});
}


being this the method that defines the button's skin:

@Override
public Skin<?> createDefaultSkin() {
ButtonSkin buttonSkin = getButtonSkin();
if (buttonSkin == null) {
buttonSkin = new ButtonSkin(this);
Circle circleRipple = new Circle(0.1, RIPPLE_COLOR);
buttonSkin.getChildren().add(0, circleRipple);
setSkin(buttonSkin);

createRippleEffect(circleRipple);
getStyleClass().add("ripple-button"); // What the CSS does is changing the button's color and text size, nothing important.
}
return buttonSkin;
}


Thanks in advance.

Answer

I did it. All I had to do was passing the widthProperty and heightProperty properties of the stage as parameters through the button's constructor.

Inside of the button's class, I create two ReadOnlyDoubleProperty properties for the width and the height that are empty until a button is created; in which case, the values of the defined ReadOnlyDoubleProperty properties are overwritten by the value of the widthProperty and heightProperty properties passed as parameters.

Having done that, all what I have to do is adding a listener to each property and changing the value of the circleRippleRadius to the greater of the properties' values each time that one of them changes.