Set a shape drawn on another shape as Invisible - javafx

I want to draw a line passing through a circle. However, I do not want the line to be shown while its inside the circle. How can I accomplish this? Note that I'm drawing the circle first and then the line.
I used a couple of things like:
Circle.setOpacity to 1, which didn't help!
Used line.toBack() after adding the circle and line in the same group. This didnt help either

line.toBack()
line.toFront()
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class LineUnderCircle extends Application {
#Override
public void start(Stage stage) throws Exception {
Line line = new Line(10, 10, 50, 50);
line.setStrokeWidth(3);
Circle left = new Circle(10, 10, 8, Color.FORESTGREEN);
Circle right = new Circle(50, 50, 8, Color.FIREBRICK);
Button lineToBack = new Button("Line to back");
lineToBack.setOnAction(e -> line.toBack());
Button lineToFront = new Button("Line to front");
lineToFront.setOnAction(e -> line.toFront());
Pane shapePane = new Pane(line, left, right);
HBox controlPane = new HBox(10, lineToBack, lineToFront);
VBox layout = new VBox( 10, controlPane, shapePane);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX scale ScrollPane content centered

My goal is to have the ScrollPane with some content inside (vbox with some controls) scalable, so that when the scaled content reaches visible bounds, ScrollPane shows horizontal and vertical scroll bars. But there's a catch - in order to do so, I must wrap my content in a Group and by doing so, the scaling is not from the center but rather from the top left corner (0,0) of the ScrollPane, while without wrapping the content of the Group makes the scaling from the center but no scroll bars show. Here is the test application:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Slider;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ZoomScrollExample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
Scene scene = new Scene(root, 450, 450, Color.WHITE);
stage.setScene(scene);
VBox layout = new VBox();
layout.setMinHeight(400);
layout.setMinWidth(400);
Rectangle r = new Rectangle(200, 200);
r.setStroke(Color.RED);
r.setFill(Color.WHITE);
layout.getChildren().add(r);
layout.setAlignment(Pos.CENTER);
ScrollPane sp = new ScrollPane();
//comment this to get no scroll bars but scaling is centered
Group g = new Group(layout);
sp.setContent(g);
//uncomment this
//sp.setContent(layout);
sp.setPrefSize(450, 450);
Slider s = new Slider();
root.getChildren().add(sp);
root.getChildren().add(s);
s.setMin(100);
s.setMax(200);
// actual scaling
layout.scaleXProperty()
.bind(s.valueProperty().divide(100));
layout.scaleYProperty()
.bind(s.valueProperty().divide(100));
stage.show();
}
}
Is there any (easy) way to have both scroll bars and centered scaling?

I want to move the text so that when I display the image it is to the bottom right of the pane. I'm not exactly sure how to set the position

When I run the program, the text appears in the center of the image. I want to move it to the bottom right corner, but nothing happens when I try to change the position. I'm not sure how to set the position of the text.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
public class Art extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
//this will create a canvas with a width of 400px and height of 200px
StackPane pane = new StackPane();
Scene scene = new Scene(pane, 400, 250);
primaryStage.setScene(scene);
primaryStage.show();
//draw three ellipses with different colors
Ellipse e1 = new Ellipse(150, 0, 100, 25);
e1.setFill(Color.PINK);
Ellipse e2 = new Ellipse(75, 25, 75, 25);
e2.setFill(Color.DARKGRAY);
Ellipse e3 = new Ellipse(0, 50, 40, 25);
e3.setFill(Color.GRAY);
/*this will set the color, font and size of the text and place it at the
lower right corner*/
Text t1 = new Text(150, 300, "text");
t1.setFont(Font.font("Century Gothic", 14));
t1.setStroke(Color.BLACK);
//display the stage
pane.getChildren().addAll(e1, e2, e3, t1);
primaryStage.setScene(scene);
primaryStage.show();
}
}
As #Slaw suggested in his comment to your question, the below code uses several different layouts to achieve what you want. I suggest you refer to the javadoc for details on how they work.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.NodeOrientation;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Art extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
// draw three ellipses with different colors
Ellipse e1 = new Ellipse(150, 0, 100, 25);
e1.setFill(Color.PINK);
Ellipse e2 = new Ellipse(75, 25, 75, 25);
e2.setFill(Color.DARKGRAY);
Ellipse e3 = new Ellipse(0, 50, 40, 25);
e3.setFill(Color.GRAY);
/*
* this will set the color, font and size of the text and place it at the lower
* right corner
*/
Text t1 = new Text(150, 300, "text");
t1.setFont(Font.font("Century Gothic", 14));
t1.setStroke(Color.BLACK);
FlowPane flow = new FlowPane(t1);
flow.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
flow.setPadding(new Insets(0.0d, 0.0d, 20.0d, 20.0d));
// display the stage
pane.getChildren().addAll(e1, e2, e3);
BorderPane root = new BorderPane(pane);
root.setBottom(flow);
Scene scene = new Scene(root, 400, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

How to create custom border style in JavaFX CSS?

I would like to create border style similar to predifened "dashed" style
(-fx-border-style: dashed).
How to create dashed border in CSS with custom lengths of dash segments, line cap and line join?
See the JavaFX CSS reference for Region, in particular the possible values for -fx-border-style. You can use segments(...) to define arbitrary line segment lengths: there are also settings for line-cap (square, butt, or round) and line-join (miter, bevel, or round).
Quick example:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class CustomBorderExample extends Application {
#Override
public void start(Stage primaryStage) {
Region region = new Region();
region.getStyleClass().add("custom-dashed-border");
region.setMinSize(400, 400);
StackPane root = new StackPane(region);
root.setPadding(new Insets(16));
Scene scene = new Scene(root, 480, 480);
scene.getStylesheets().add("custom-dashed-border.css");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
with
custom-dashed-border.css:
.custom-dashed-border {
-fx-border-color: blue ;
-fx-border-width: 5 ;
-fx-border-style: segments(10, 15, 15, 15) line-cap round ;
}
which gives

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);
}
}

Fade Effect with 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);
}
}

Resources