Fade Effect with JavaFX - javafx

Im trying to realize a special FadeTransition effect. But I have no idea how I can manage it. For some node I would like to increase the opacity from left to right (for example in Powerpoint, you can change the slides with such an effect). Here is an easy example for rectangles. But the second one should fadeIn from left to right (the opacity should increase on the left side earlier as on the right side). With timeline and KeyValues/KeyFrames I found also no solution.
Thanks in advance.
Rectangle rec2;
#Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 400, 300, Color.BLACK);
stage.setTitle("JavaFX Scene Graph Demo");
Pane pane = new Pane();
Button btnForward = new Button();
btnForward.setText(">");
btnForward.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
FadeTransition ft = new FadeTransition(Duration.millis(2000), rec2);
ft.setFromValue(0.);
ft.setToValue(1.);
ft.play();
}
});
Rectangle rec1 = new Rectangle(0, 0, 300,200);
rec1.setFill(Color.RED);
rec2 = new Rectangle(100, 50, 100,100);
rec2.setFill(Color.GREEN);
rec2.setOpacity(0.);
pane.getChildren().addAll(rec1,rec2);
root.getChildren().add(pane);
root.getChildren().add(btnForward);
stage.setScene(scene);
stage.show();
}

Define the fill of the rectangle using css with a linear gradient which references looked-up colors for the left and right edges of the rectangle. (This can be inline or in an external style sheet.)
Define a couple of DoublePropertys representing the opacities of the left and right edge.
Define the looked-up colors on the rectangle or one of its parents using an inline style bound to the two double properties.
Use a timeline to change the values of the opacity properties.
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class FadeInRectangle extends Application {
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 400, 300, Color.BLACK);
primaryStage.setTitle("JavaFX Scene Graph Demo");
Pane pane = new Pane();
Rectangle rec1 = new Rectangle(0, 0, 300,200);
rec1.setFill(Color.RED);
Rectangle rec2 = new Rectangle(100, 50, 100,100);
rec2.setStyle("-fx-fill: linear-gradient(to right, left-col, right-col);");
final DoubleProperty leftEdgeOpacity = new SimpleDoubleProperty(0);
final DoubleProperty rightEdgeOpacity = new SimpleDoubleProperty(0);
root.styleProperty().bind(
Bindings.format("left-col: rgba(0,128,0,%f); right-col: rgba(0,128,0,%f);", leftEdgeOpacity, rightEdgeOpacity)
);
Button btnForward = new Button();
btnForward.setText(">");
btnForward.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(leftEdgeOpacity, 0)),
new KeyFrame(Duration.ZERO, new KeyValue(rightEdgeOpacity, 0)),
new KeyFrame(Duration.millis(500), new KeyValue(rightEdgeOpacity, 0)),
new KeyFrame(Duration.millis(1500), new KeyValue(leftEdgeOpacity, 1)),
new KeyFrame(Duration.millis(2000), new KeyValue(rightEdgeOpacity, 1)),
new KeyFrame(Duration.millis(2000), new KeyValue(leftEdgeOpacity, 1))
);
timeline.play();
}
});
pane.getChildren().addAll(rec1,rec2);
root.getChildren().add(pane);
root.getChildren().add(btnForward);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

How to make scene local JavaFX

The scene at the start of lambda has an error that is not local. How to make it local. I tried adding up top but shows null. How to make scene local at the lambda because scene sets primaryStage. I need the other nodes for GridPane. I am trying to draw on the canvas. Please help fix this problem. Thank you in advanced!
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TestFX extends Application {
Node scene; // i tried adding this but throws null at the lambda
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("MyPaint");
RadioButton radioButton1 = new RadioButton("Draw");
RadioButton radioButton2 = new RadioButton("Erase");
RadioButton radioButton3 = new RadioButton("Circle");
ToggleGroup radioGroup = new ToggleGroup();
radioButton1.setToggleGroup(radioGroup);
radioButton2.setToggleGroup(radioGroup);
radioButton3.setToggleGroup(radioGroup);
Button b1 = new Button("Clear Canvas");
TextField colorText = new TextField();
colorText.setText("Colors");
Canvas canvas = new Canvas(300, 250);
GraphicsContext gc = canvas.getGraphicsContext2D();
// scene cannot be resolved without initializing at top: Node scene;
scene.setOnMousePressed(q -> {
gc.setFill(Color.BLACK);
gc.setLineWidth(1);
gc.beginPath();
gc.lineTo(q.getSceneX(),
q.getSceneY());
gc.getStroke();
});
gc.strokeText("Hello Canvas", 150, 100);
GridPane gridPane = new GridPane();
GridPane.setConstraints(radioButton1, 0, 0);
GridPane.setConstraints(radioButton2, 0, 1);
GridPane.setConstraints(radioButton3, 0, 2);
GridPane.setConstraints(colorText, 0, 3);
GridPane.setConstraints(b1, 0, 4);
GridPane.setConstraints(canvas, 1, 1);
// adding spaces between radiobutton, button and radiobutton
radioButton1.setPadding(new Insets(15));
radioButton2.setPadding(new Insets(15));
radioButton3.setPadding(new Insets(15));
b1.setPadding(new Insets(15));
colorText.setPadding(new Insets(15));
gridPane.getChildren().addAll(radioButton1, radioButton2, radioButton3, colorText, b1, canvas);
Scene scene = new Scene(gridPane, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You define Scene in this part of the code:
gridPane.getChildren().addAll(radioButton1, radioButton2, radioButton3, colorText, b1, canvas);
Scene scene = new Scene(gridPane, 800, 800);
primaryStage.setScene(scene);
primaryStage.show()
but you are calling this code before you define Scene.
// scene cannot be resolved without initializing at top: Node scene;
scene.setOnMousePressed(q -> {
gc.setFill(Color.BLACK);
gc.setLineWidth(1);
gc.beginPath();
gc.lineTo(q.getSceneX(),
q.getSceneY());
gc.getStroke();
});
You need to delete Node scene. and move the scene.setOnMousePressed() code to a place after where you defined the Scene.
Full Code:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TestFX extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("MyPaint");
RadioButton radioButton1 = new RadioButton("Draw");
RadioButton radioButton2 = new RadioButton("Erase");
RadioButton radioButton3 = new RadioButton("Circle");
ToggleGroup radioGroup = new ToggleGroup();
radioButton1.setToggleGroup(radioGroup);
radioButton2.setToggleGroup(radioGroup);
radioButton3.setToggleGroup(radioGroup);
Button b1 = new Button("Clear Canvas");
TextField colorText = new TextField();
colorText.setText("Colors");
Canvas canvas = new Canvas(300, 250);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.strokeText("Hello Canvas", 150, 100);
GridPane gridPane = new GridPane();
GridPane.setConstraints(radioButton1, 0, 0);
GridPane.setConstraints(radioButton2, 0, 1);
GridPane.setConstraints(radioButton3, 0, 2);
GridPane.setConstraints(colorText, 0, 3);
GridPane.setConstraints(b1, 0, 4);
GridPane.setConstraints(canvas, 1, 1);
// adding spaces between radiobutton, button and radiobutton
radioButton1.setPadding(new Insets(15));
radioButton2.setPadding(new Insets(15));
radioButton3.setPadding(new Insets(15));
b1.setPadding(new Insets(15));
colorText.setPadding(new Insets(15));
gridPane.getChildren().addAll(radioButton1, radioButton2, radioButton3, colorText, b1, canvas);
Scene scene = new Scene(gridPane, 800, 800);
scene.setOnMousePressed(q -> {
gc.setFill(Color.BLACK);
gc.setLineWidth(1);
gc.beginPath();
gc.lineTo(q.getSceneX(),
q.getSceneY());
gc.getStroke();
});
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX ScrollPane and Scaling of the Content

I would like to show a photo as an ImageView in a ScrollPane with an ZoomIn and ZoomOut Function. But if I reduce by means of scale the imageview, an undesirable empty edge is created in the ScrollPane. How can you make sure that the ScrollPane is always the size of the scaled ImageView?
See the following example. For simplicity, I replaced the ImageView with a rectangle.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ScrollPaneDemo extends Application {
double scale;
Pane contPane = new Pane();
#Override
public void start(Stage primaryStage) {
BorderPane pane = new BorderPane();
ScrollPane sp = new ScrollPane();
sp.setContent(contPane);
sp.setVvalue(0.5);
sp.setHvalue(0.5);
Rectangle rec = new Rectangle(2820, 1240,Color.RED);
scale = 0.2;
contPane.setScaleX(scale);
contPane.setScaleY(scale);
contPane.getChildren().add(rec);
Button but1 = new Button("+");
but1.setOnAction((ActionEvent event) -> {
scale*=2;
contPane.setScaleX(scale);
contPane.setScaleY(scale);
});
Button but2 = new Button("-");
but2.setOnAction((ActionEvent event) -> {
scale/=2;
contPane.setScaleX(scale);
contPane.setScaleY(scale);
});
HBox buttons = new HBox(but1, but2);
pane.setTop(buttons);
pane.setCenter(sp);
Scene scene = new Scene(pane, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
contPane scaled by using transform don't change its layoutBounds automatically. If you want not to make empty space in contPane, you'd better wrap the node in Group.
See this post. Layout using the transformed bounds
sp.setContent(new Group(contPane));
In addition, if you don't want to make empty space in ScrollPane, limit minimum scale to rate which width or height of the content fits viewport's one.
Button but1 = new Button("+");
but1.setOnAction((ActionEvent event) -> {
updateScale(scale * 2.0d);
});
Button but2 = new Button("-");
but2.setOnAction((ActionEvent event) -> {
updateScale(scale / 2.0d);
});
HBox buttons = new HBox(but1, but2);
pane.setTop(buttons);
pane.setCenter(sp);
Scene scene = new Scene(pane, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
updateScale(0.2d);
private void updateScale(double newScale) {
scale = Math.max(newScale, Math.max(sp.getViewportBounds().getWidth() / rec.getWidth(), sp.getViewportBounds().getHeight() / rec.getHeight()));
contPane.setScaleX(scale);
contPane.setScaleY(scale);
}
Consider a case of the image is smaller than ScrollPane's viewport. Because for showing no empty space, this code will stretch contents when it doesn't have enough size.
In a case of huge images, TravisF's comment helps you.

multiple windows not showing up upon execution ( 1 out of 3)

quick question,
why are my multiple windows not appearing from this code?
also any tips on how to make the circle's diameter increase only by the stage's resolution when the window is increased in size; anyway of doing this internally through "circ3."
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Circles extends Application {
#Override
public void start(Stage primaryStage){
Pane pane = new Pane();
Circle circ = new Circle();
circ.setStroke(Color.DARKBLUE);
circ.setFill(Color.YELLOW);
circ.centerXProperty().bind(pane.widthProperty().divide(10));
circ.centerYProperty().bind(pane.heightProperty().subtract(20));
circ.centerXProperty().bind(pane.widthProperty().subtract(20));
circ.setRadius(20);
pane.getChildren().add(circ);
Scene scene = new Scene(pane, 500, 200);
primaryStage.setTitle("Bottom Right");
primaryStage.setScene(scene);
primaryStage.show();
Pane pane2 = new Pane();
Circle circ2 = new Circle();
circ2.setStroke(Color.PEACHPUFF);
circ2.setFill(Color.YELLOWGREEN);
circ2.centerXProperty().bind(pane2.widthProperty().divide(2));
circ2.centerYProperty().bind(pane2.heightProperty().subtract(20));
circ2.setRadius(20);
pane2.getChildren().add(circ2);
Scene scene2 = new Scene(pane2, 200, 500);
primaryStage.setTitle("Bottom Centered");
primaryStage.setScene(scene2);
primaryStage.show();
Pane pane3 = new Pane();
Circle circ3 = new Circle();
circ3.setStroke(Color.PEACHPUFF);
circ3.setFill(Color.YELLOWGREEN);
circ3.centerXProperty().bind(pane3.widthProperty().subtract(150));
circ3.centerYProperty().bind(pane3.heightProperty().divide(2));
circ3.setRadius(150);
//size (circle diameter) needs to scale with width resolution
pane3.getChildren().add(circ3);
//boilerplate
Scene scene3 = new Scene(pane3, 300, 500);
primaryStage.setTitle("Radius / Width ");
primaryStage.setScene(scene3);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
You can make the circle change size with the window size using bindings:
Pane pane3 = new Pane();
Circle circ3 = new Circle();
circ3.setStroke(Color.PEACHPUFF);
circ3.setFill(Color.YELLOWGREEN);
circ3.centerXProperty().bind(pane3.widthProperty().divide(2));
circ3.centerYProperty().bind(pane3.heightProperty().divide(2));
circ3.radiusProperty().bind(pane3.widthProperty().divide(2));

Move viewpoint of ScrollPane on Button click

There is concept of my JavaFX applictions:
All screens in one ScrollPane.
For example, if user click on button "Options" in loginScreen i want to animate Y-value of ViewPort to move it to optionsScreen.
How can i programmatically move viewport of ScrollPane with smooth animation?
Or you can offer better idea?
How can I programmatically move viewport of ScrollPane with smooth animation?
You can use a combination of Timeline and vvalueProperty of ScrollPane to perform a smooth animation of scrolling.
Here is a simple application where you I have three sections
Top
Center
Bottom
I am changing the vvalue of the ScrollPane through a Timeline on the action of the button.
The vvalue can have a value between 0.0 to 1.0, so you may have to do your own calculations to find the exact value which you want to be assigned to it.
The KeyValue performs the operation on scrollRoot.vvalueProperty().
The KeyFrame for the complete timeline is set at 500 milliseconds. You may increase or decrease it depending on the time you want the animation to run.
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
// For just adjusting the center rectangle w.r.t ScrollPane
private final int ADJUSTMENT_RATIO = 175;
#Override
public void start(Stage stage) {
Rectangle topRegion = new Rectangle(300, 300, Color.ALICEBLUE);
StackPane top = new StackPane(topRegion, new Label("Top"));
Rectangle centerRegion = new Rectangle(300, 300, Color.GOLDENROD);
StackPane center = new StackPane(centerRegion, new Label("center"));
Rectangle bottomRegion = new Rectangle(300, 300, Color.BISQUE);
StackPane bottom = new StackPane(bottomRegion, new Label("bottom"));
Button topButton = new Button("Top");
Button centerButton = new Button("Center");
Button bottomButton = new Button("Bottom");
HBox buttonBox = new HBox(15, topButton, centerButton, bottomButton);
buttonBox.setPadding(new Insets(20));
buttonBox.setAlignment(Pos.CENTER);
final VBox root = new VBox();
root.setSpacing(10);
root.setPadding(new Insets(10, 10, 10, 10));
root.getChildren().addAll(top, center, bottom);
ScrollPane scrollRoot = new ScrollPane(root);
Scene scene = new Scene(new VBox(buttonBox, scrollRoot));
stage.setTitle("Market");
stage.setWidth(350);
stage.setHeight(400);
stage.setScene(scene);
stage.show();
topButton.setOnAction(event -> {
final Timeline timeline = new Timeline();
final KeyValue kv = new KeyValue(scrollRoot.vvalueProperty(), 0.0);
final KeyFrame kf = new KeyFrame(Duration.millis(500), kv);
timeline.getKeyFrames().add(kf);
timeline.play();
});
centerButton.setOnAction(event -> {
final Timeline timeline = new Timeline();
final KeyValue kv = new KeyValue(scrollRoot.vvalueProperty(), (top.getBoundsInLocal().getHeight() + ADJUSTMENT_RATIO) / root.getHeight());
final KeyFrame kf = new KeyFrame(Duration.millis(500), kv);
timeline.getKeyFrames().add(kf);
timeline.play();
});
bottomButton.setOnAction(event -> {
final Timeline timeline = new Timeline();
final KeyValue kv = new KeyValue(scrollRoot.vvalueProperty(), 1.0);
final KeyFrame kf = new KeyFrame(Duration.millis(500), kv);
timeline.getKeyFrames().add(kf);
timeline.play();
});
}
public static void main(String[] args) {
launch(args);
}
}
Output

How can I stop a MouseEvent in JavaFX?

(Sorry for my poor English)
I don't know how I can stop a Mouse Event in JavaFX.
This code generates a small image into a large rectangle when I press a button and then pressed the large rectangle, but if I press again the big rectangle is rebuilt a new image.
I dont want to generate a new image, how Can I do that?
button.setOnAction((ActionEvent t) -> {
rectangle.setOnMouseClicked((MouseEvent me) -> {
Rectangle asdf = new Rectangle(48, 48, Color.TRANSPARENT);
StackPane imageContainer = new StackPane();
ImageView image = new ImageView("firefox-icono-8422-48.png");
imageContainer.getChildren().addAll(asdf, image);
imageContainer.setTranslateX(me.getX());
imageContainer.setTranslateY(me.getY());
enableDragging(imageContainer);
rootGroup.getChildren().add(imageContainer);
myList2.add(imageContainer);
});
});
Thanks
PS: t.consume() and me.consume(); don't anything.
I'm not sure I have interpreted your question correctly, but if you want to "turn off" the mouse click handler on the rectangle, you can just call
rectangle.setOnMouseClicked(null);
Complete example:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ActivateRectangleWithButton extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle border = new Rectangle(100, 100, Color.TRANSPARENT);
Rectangle rect = new Rectangle(80, 80, Color.CORNFLOWERBLUE);
StackPane stack = new StackPane(border, rect);
Button button = new Button("Activate");
button.setOnAction(evt -> {
border.setFill(Color.BLUE);
rect.setOnMouseClicked(me -> {
System.out.println("Active rectangle was clicked!");
// de-activate:
border.setFill(Color.TRANSPARENT);
rect.setOnMouseClicked(null);
});
});
VBox root = new VBox(20, stack, button);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Resources