Line painting in painting program JavaFX - java

I created a simple paint program which allows the user to choose between 4 shapes(line,circle,rectangle,ellipse) , the user can change the width height and stroke width , he can save the design he makes , undo and redo , the user can also choose the stroke type (solid or dashed) ,I'm almost done with the program but I'm facing one problem , the line is getting displayed not in the way I want it to be displayed as the photo below :
So the line here is of width 32 and height 32 , my line is getting printed in a different way.Is it correct the way I'm printing my line ?
NOTE : I'm using the line shape in the code to make the code small.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class paintLine extends Application {
#Override
public void start(Stage primaryStage) {
Image image1 = new
Image("C:\\Users\\Mhamd\\Desktop\\laol\\src\\resources\\Daco_70400.png",
100, 100, false, false);
ImageView view1 = new ImageView(image1);
view1.setFitHeight(40);
view1.setPreserveRatio(true);
ToggleButton linebtn = new ToggleButton();
linebtn.setGraphic(view1);
ToggleButton[] toolsArr = {linebtn};
ToggleGroup tools = new ToggleGroup();
for (ToggleButton tool : toolsArr) {
tool.setMinWidth(50);
tool.setToggleGroup(tools);
tool.setCursor(Cursor.HAND);
}
ColorPicker cpLine = new ColorPicker(Color.BLACK);
ColorPicker cpFill = new ColorPicker(Color.TRANSPARENT);
TextField textWidth = new TextField("32");
TextField textHeight = new TextField("32");
TextField contouring = new TextField("2");
Label line_color = new Label("Line Color");
Label fill_color = new Label("Fill Color");
Label line_width = new Label("3.0");
Label imgWidth = new Label("Width");
Label imgHeight = new Label("Height");
String week_days[] =
{"Solid", "Dotted"};
ChoiceBox choiceBox = new ChoiceBox(FXCollections
.observableArrayList(week_days));
VBox btns = new VBox(10);
btns.getChildren().addAll(linebtn, imgWidth, textWidth, imgHeight,
textHeight, line_color, cpLine,
fill_color, cpFill, line_width, contouring, choiceBox);
btns.setPadding(new Insets(5));
btns.setStyle("-fx-background-color: #999");
btns.setPrefWidth(100);
Canvas canvas = new Canvas(1080, 790);
GraphicsContext gc;
gc = canvas.getGraphicsContext2D();
gc.setLineWidth(1);
Line line = new Line();
canvas.setOnMouseClicked(e -> {
if (linebtn.isSelected()) {
// double widthSize =
Double.parseDouble(textWidth.getText());
// double heightSize =
Double.parseDouble(textHeight.getText());
double strokeWidth =
Double.parseDouble(contouring.getText());
// gc.setLineWidth(strokeWidth);
gc.setStroke(cpLine.getValue());
if (choiceBox.getSelectionModel().isSelected(0)) {
gc.setLineWidth(strokeWidth);
} else if (choiceBox.getSelectionModel().isSelected(1)) {
gc.setLineWidth(strokeWidth);
gc.setLineDashes(10);
}
gc.setFill(cpFill.getValue());
line.setStartX(e.getX());
line.setStartY(e.getY());
line.setEndX(e.getX() / 2);
line.setEndY(e.getY() / 2);
gc.strokeLine(line.getStartX(), line.getStartY(),
line.getEndX(), line.getEndY());
}
});
BorderPane pane = new BorderPane();
pane.setRight(btns);
pane.setCenter(canvas);
Scene scene = new Scene(pane, 1200, 800);
primaryStage.setTitle("Paint");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Focusing on just drawing a line interactively, you need to at least do the following:
Record the initial point at which the mouse was pressed and then
Render the line when you know where the mouse was released:
private double startX;
private double startY;
…
canvas.setOnMousePressed(e -> {
startX = e.getX();
startY = e.getY();
});
canvas.setOnMouseReleased(e -> {
gc.strokeLine(startX, startY, e.getX(), e.getY());
});
This works as shown above, but the problem then becomes how to draw the line while dragging—without damaging previous work. One solution is to add each new line to a List<Line> and render the accumulated lines with each update:
private final List<Line> lines = new ArrayList<>();
…
canvas.setOnMouseReleased(e -> {
lines.add(new Line(startX, startY, e.getX(), e.getY()));
});
canvas.setOnMouseDragged(e -> {
if (lineButton.isSelected()) {
…
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
lines.forEach(l -> {
gc.strokeLine(l.getStartX(), l.getStartY(), l.getEndX(), l.getEndY());
});
gc.strokeLine(startX, startY, e.getX(), e.getY());
}
});
A more general solution, which illustrates undo() and redo(), is offered here.

Related

Implementing Fluent Design's reveal highlight effect in JavaFX

I'd like to implement the reveal highlight effect for JavaFX that can be seen in various parts of Windows 10, particularly the Settings and Calculator apps.
The effect seems to be composed for two parts, a border highlight (seen here) and a background highlight (seen here, though admittedly looks better in person due to compression).
My first instinct was to see if this could be done in some sort of pixel shader but after googling around for that it seems JavaFX does provide a public API for anything like that?
Would it be possible to create this effect without resorting to a canvas and drawing the whole UI by hand?
First I'd like to say I have no idea how Windows implements that style. But one idea I had is to have multiple layers:
A black background.
A circle with a radial gradient going from white to transparent that moves with the mouse.
A region with a black background and a shape that has holes wherever the option nodes are.
The option nodes with a layered background.
When the mouse is not hovering:
Transparent background with no insets.
Black background with a slight inset.
When the mouse is hovering:
Low opacity white background with no insets.
Black background with a slight inset.
White-to-transparent radial gradient background that's centered on the mouse.
Unfortunately that means a lot of the styling has to be done in the code even though I'd prefer to put most of it in CSS. Here's a proof-of-concept I quickly mocked up. It's not fully functional but shows the look you want is possible.
OptionsPane.java
import javafx.beans.InvalidationListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.TilePane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.text.Font;
public class OptionsPane extends Region {
public static class Option {
private final String title;
private final String subtitle;
private final Node graphic;
public Option(String title, String subtitle, Node graphic) {
this.title = title;
this.subtitle = subtitle;
this.graphic = graphic;
}
public String getTitle() {
return title;
}
public String getSubtitle() {
return subtitle;
}
public Node getGraphic() {
return graphic;
}
}
private final ObservableList<Option> options = FXCollections.observableArrayList();
private final TilePane topTiles = new TilePane();
private final Region midCover = new Region();
private final Circle underGlow = new Circle();
public OptionsPane() {
setBackground(new Background(new BackgroundFill(Color.BLACK, null, null)));
underGlow.setManaged(false);
underGlow.setRadius(75);
underGlow.visibleProperty().bind(hoverProperty());
underGlow.setFill(
new RadialGradient(
0, 0,
0.5, 0.5,
1.0,
true,
null,
new Stop(0.0, Color.WHITE),
new Stop(0.35, Color.TRANSPARENT)));
addEventFilter(
MouseEvent.MOUSE_MOVED,
e -> {
underGlow.setCenterX(e.getX());
underGlow.setCenterY(e.getY());
});
midCover.setBackground(new Background(new BackgroundFill(Color.BLACK, null, null)));
topTiles.setMinSize(0, 0);
topTiles.setVgap(20);
topTiles.setHgap(20);
topTiles.setPadding(new Insets(20));
topTiles.setPrefTileWidth(250);
topTiles.setPrefTileHeight(100);
topTiles.setPrefColumns(3);
options.addListener(
(InvalidationListener)
obs -> {
topTiles.getChildren().clear();
options.forEach(opt -> topTiles.getChildren().add(createOptionRegion(opt)));
});
getChildren().addAll(underGlow, midCover, topTiles);
}
public final ObservableList<Option> getOptions() {
return options;
}
#Override
protected void layoutChildren() {
double x = getInsets().getLeft();
double y = getInsets().getTop();
double w = getWidth() - getInsets().getRight() - x;
double h = getHeight() - getInsets().getBottom() - y;
layoutInArea(midCover, x, y, w, h, -1, HPos.CENTER, VPos.CENTER);
layoutInArea(topTiles, x, y, w, h, -1, HPos.CENTER, VPos.CENTER);
Shape coverShape = new Rectangle(x, y, w, h);
for (Node optionNode : topTiles.getChildren()) {
Bounds b = optionNode.getBoundsInParent();
Rectangle rect = new Rectangle(b.getMinX(), b.getMinY(), b.getWidth(), b.getHeight());
coverShape = Shape.subtract(coverShape, rect);
}
midCover.setShape(coverShape);
}
private Region createOptionRegion(Option option) {
Label titleLabel = new Label(option.getTitle());
titleLabel.setTextFill(Color.WHITE);
titleLabel.setFont(Font.font("System", 13));
Label subtitleLabel = new Label(option.getSubtitle());
subtitleLabel.setTextFill(Color.DARKGRAY);
subtitleLabel.setFont(Font.font("System", 10));
VBox textBox = new VBox(5, titleLabel, subtitleLabel);
HBox.setHgrow(textBox, Priority.ALWAYS);
HBox container = new HBox(10, textBox);
container.setPadding(new Insets(10));
if (option.getGraphic() != null) {
container.getChildren().add(0, option.getGraphic());
}
setNonHoverBackground(container);
container
.hoverProperty()
.addListener(
(obs, ov, nv) -> {
if (!nv) {
setNonHoverBackground(container);
}
});
container.setOnMouseMoved(e -> setHoverBackground(container, e.getX(), e.getY()));
return container;
}
private void setNonHoverBackground(Region region) {
BackgroundFill fill1 = new BackgroundFill(Color.TRANSPARENT, null, null);
BackgroundFill fill2 = new BackgroundFill(Color.BLACK, null, new Insets(2));
region.setBackground(new Background(fill1, fill2));
}
private void setHoverBackground(Region region, double x, double y) {
RadialGradient gradient =
new RadialGradient(
0, 0,
x, y,
400,
false,
null,
new Stop(0.0, new Color(1, 1, 1, 0.2)),
new Stop(0.35, Color.TRANSPARENT));
BackgroundFill fill1 = new BackgroundFill(new Color(1, 1, 1, 0.3), null, null);
BackgroundFill fill2 = new BackgroundFill(Color.BLACK, null, new Insets(2));
BackgroundFill fill3 = new BackgroundFill(gradient, null, null);
region.setBackground(new Background(fill1, fill2, fill3));
}
}
Main.java
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
OptionsPane pane = new OptionsPane();
List<OptionsPane.Option> options = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Rectangle graphic = new Rectangle(20, 20, Color.DARKGRAY);
options.add(
new OptionsPane.Option("Option Title #" + (i + 1), "Description #" + (i + 1), graphic));
}
pane.getOptions().addAll(options);
primaryStage.setScene(new Scene(pane));
primaryStage.show();
}
}
And this is what it looks like:
It's not exactly the same but you can experiment yourself and change things as you want.

How to update part of BufferedImage and display it with javafx

I have an image. At the beginning I want the image to be displayed with only the first frame. On the keyboard with 'u' key pressed, drink water and load the second frame. If I understand correctly the whole image should be loaded at the beginning. And then I need to set new y.
How to complete this task? What is the right way to display this image?
My code in:
package testDesktopUi;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class DesktopUi extends Application {
private static int y = 0;
private static BufferedImage bufferedImage;
private static final ImageView imageView = new ImageView();
private static final HBox root = new HBox();
#Override
public void start(Stage primaryStage) throws IOException {
String path = "Bottle.png";
bufferedImage = ImageIO.read(new File(path)).getSubimage(0, 0, 32, 32);
Image image = SwingFXUtils.toFXImage(bufferedImage, null);
imageView.setImage(image);
root.getChildren().add(imageView);
Scene scene = new Scene(root);
scene.setOnKeyPressed(key -> {
if (key.getCode() == KeyCode.U) {
System.out.println("u pressed");
updateImage(bufferedImage);
System.out.println(y);
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private static void updateImage(BufferedImage bufferedImage) {
int maxHeight = 352;
if (y + 32 >= maxHeight) {
y = 0;
} else {
y += 32;
}
//?? bufferedImage.getSubimage(0, y, 32, 32);
}
}
If you're using JavaFX, stick just to the JavaFX image API: there is no need to first load an AWT BufferedImage and convert it to a JavaFX image.
To display portions of an image, you can create an ImageView from the image and set the ImageView's viewport.
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class DesktopUi extends Application {
private int y = 0;
private final ImageView imageView = new ImageView();
private final HBox root = new HBox();
#Override
public void start(Stage primaryStage) {
String path = "Bottle.png";
// Assumes Bottle.png is in the same package as the current class:
Image image = new Image(getClass().getResource("Bottle.png").toExternalForm());
imageView.setImage(image);
// display only a portion of the image:
imageView.setViewport(new Rectangle2D(0, y, 32, 32));
root.getChildren().add(imageView);
Scene scene = new Scene(root);
scene.setOnKeyPressed(key -> {
if (key.getCode() == KeyCode.U) {
System.out.println("u pressed");
System.out.println(y);
updateImage();
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private void updateImage() {
// update y
int maxHeight = 352;
if (y + 32 >= maxHeight) {
y = 0;
} else {
y += 32;
}
// update portion of image displayed
imageView.setViewport(new Rectangle2D(0, y, 32, 32));
}
public static void main(String[] args) {
Application.launch(args);
}
}
Note this also lends itself nicely to animations:
#Override
public void start(Stage primaryStage) {
int numSprites = 11 ;
Image image = new Image(getClass().getResource("Bottle.png").toExternalForm());
imageView.setImage(image);
IntegerProperty spriteIndex = new SimpleIntegerProperty();
spriteIndex.addListener((obs, oldIndex, newIndex) -> System.out.println(newIndex));
imageView.viewportProperty().bind(Bindings.createObjectBinding(
() -> new Rectangle2D(0, spriteIndex.get() * 32 , 32, 32),
spriteIndex
));
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(5),
new KeyValue(spriteIndex, numSprites - 1)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
root.getChildren().add(imageView);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

Implementing drawing areas in tabs in JavaFX

I would want to add a drawing area to my tabs in JavaFX. I am new to the field, and tried adding a Canvas to each tab I create. However, this does not seem to be working. Relevant code included.
#FXML
void fileNewTabHandler(ActionEvent event) {
++indexTab;
Tab tab = new Tab("Untitled " + indexTab);
Canvas canvas = new Canvas(500, 285);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.BLUE);
gc.fillRect(250, 856, 50, 60);
tab.setContent(canvas);
tabPane.getTabs().add(tab);
}
Here tabPane and indexTab are defined and work as long as I do not use the canvas. Where am I going wrong. Should I use a different method to implement what I want to?
Quick Sample
There is no real trick to this, you just set the canvas as the content of the tab.
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.canvas.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.Random;
public class TabbedCanvas extends Application {
private int tabId = 0;
private double W = 200, H = 150;
private Random random = new Random(42);
#Override
public void start(Stage stage) {
TabPane tabPane = new TabPane();
Button newTabButton = new Button("New Tab");
newTabButton.setOnAction(
event -> addTab(tabPane)
);
newTabButton.fire();
ToolBar toolBar = new ToolBar(newTabButton);
toolBar.setMinHeight(ToolBar.USE_PREF_SIZE);
VBox layout = new VBox(toolBar, tabPane);
VBox.setVgrow(tabPane, Priority.ALWAYS);
stage.setScene(new Scene(layout));
stage.show();
}
private void addTab(TabPane tabPane) {
Tab tab = new Tab("Tab: " + tabId++);
tab.setContent(createTabContent());
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
}
private Node createTabContent() {
Canvas canvas = new Canvas(W, H);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(randomColor());
gc.fillRect(0, 0, W, H);
return canvas;
}
private Color randomColor() {
return Color.rgb(
random.nextInt(256),
random.nextInt(256),
random.nextInt(256)
);
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX - Clickable line on canvas

I have this JavaFX application that lets you plot locations on a map and connect them.
I do this by drawing a map as a background image on a canvas and then drawing circles and lines on it. I have made the circles clickable by using the contains() method in the Circle class, but how can I make the lines clickable?
edit: Look at this example where I just draw a line and set an event handler:
Canvas canvas = new Canvas();
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setLineWidth(5);
gc.strokeLine(100, 100, 200, 200);
canvas.setOnMouseClicked(event -> {
double x = event.getX(), y = event.getY();
});
My question is simply this: how do I finish the event handler so that it detects if the click is inside the line I just drew?
You should create a canvas and add the nodes (Circle, Line, etc) to it. Then you add mouse listeners to the nodes.
Example:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class DragNodes extends Application {
public static List<Circle> circles = new ArrayList<Circle>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Canvas canvas = new Canvas(300, 300);
GraphicsContext gc = canvas.getGraphicsContext2D();
drawShapes(gc);
Circle circle1 = new Circle(50);
circle1.setStroke(Color.GREEN);
circle1.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.7));
circle1.relocate(100, 100);
Circle circle2 = new Circle(50);
circle2.setStroke(Color.BLUE);
circle2.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.7));
circle2.relocate(200, 200);
Line line = new Line(circle1.getLayoutX(), circle1.getLayoutY(), circle2.getLayoutX(), circle2.getLayoutY());
line.setStrokeWidth(20);
Pane overlay = new Pane();
overlay.getChildren().addAll(circle1, circle2, line);
MouseGestures mg = new MouseGestures();
mg.makeDraggable(circle1);
mg.makeDraggable(circle2);
mg.makeDraggable(line);
root.getChildren().addAll(canvas, overlay);
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
private void drawShapes(GraphicsContext gc) {
gc.setStroke(Color.RED);
gc.strokeRoundRect(10, 10, 230, 230, 10, 10);
}
public static class MouseGestures {
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;
public void makeDraggable(Node node) {
node.setOnMousePressed(circleOnMousePressedEventHandler);
node.setOnMouseDragged(circleOnMouseDraggedEventHandler);
}
EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
if (t.getSource() instanceof Circle) {
Circle p = ((Circle) (t.getSource()));
orgTranslateX = p.getCenterX();
orgTranslateY = p.getCenterY();
} else {
Node p = ((Node) (t.getSource()));
orgTranslateX = p.getTranslateX();
orgTranslateY = p.getTranslateY();
}
}
};
EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
double newTranslateX = orgTranslateX + offsetX;
double newTranslateY = orgTranslateY + offsetY;
if (t.getSource() instanceof Circle) {
Circle p = ((Circle) (t.getSource()));
p.setCenterX(newTranslateX);
p.setCenterY(newTranslateY);
} else {
Node p = ((Node) (t.getSource()));
p.setTranslateX(newTranslateX);
p.setTranslateY(newTranslateY);
}
}
};
}
}

java fx creating balls when create button is clicked

I am trying to create balls whenever create button is clicked. I am able to create a single ball but for some reason not able to create multiple balls when the 'Create' button is clicked repeatedly.
Any help is appreciated.
package week3;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.TilePane;
import javafx.geometry.Orientation;
import javafx.geometry.Insets;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.DoubleProperty;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
public class BounceBallControl1 extends Application {
public final double radius = 10;
private double x = radius, y = radius;
private double dx = 1, dy = 1;
private Circle circle = new Circle(x, y, radius);
private Timeline animation;
#SuppressWarnings("restriction")
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
//BallPane ballPane = new BallPane();
Button btnCreate = new Button("Create");
Button btnDelete = new Button("Delete");
btnCreate.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btnDelete.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
TilePane tileButtons = new TilePane(Orientation.HORIZONTAL);
tileButtons.setPadding(new Insets(5, 5, 5, 70));
tileButtons.setHgap(20.0);
tileButtons.getChildren().addAll(btnCreate, btnDelete);
Slider slSpeed = new Slider();
slSpeed.setMax(20);
//rateProperty().bind(slSpeed.valueProperty());
BorderPane pane = new BorderPane();
//pane.setCenter(ballPane);
pane.setTop(slSpeed);
pane.setBottom(tileButtons);
btnCreate.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
for(int i=0;i<=100;i++)
circle.setFill(Color.TURQUOISE); // Set ball color
pane.getChildren().add(circle); // Place a ball into this pane
// Create an animation for moving the ball
animation = new Timeline(
new KeyFrame(Duration.millis(50), (e -> {
// Check boundaries
if (x < radius || x > pane.getWidth() - radius) {
dx *= -1; // Change ball move direction
}
if (y < radius || y > pane.getHeight() - radius) {
dy *= -1; // Change ball move direction
}
// Adjust ball position
x += dx;
y += dy;
circle.setCenterX(x);
circle.setCenterY(y);
})));
animation.setCycleCount(Timeline.INDEFINITE);
animation.play(); // Start animation
}
});
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("BounceBallSlider"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
/*public DoubleProperty rateProperty() {
return animation.rateProperty();
}*/
}
You use the same instance of circle each time you click add button. So every time the same circle is added to the scene. Try by creating new circle each time, it will be ok.

Categories

Resources