I am trying to make an application where an object moves across the screen, only changing its x value. I am not getting any errors but it is not working when I run it. the objects are showing but the rectangle is not animating. I am not sure what to do
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private BorderPane root;
private Stage stage;
private Scene scene;
private AnchorPane anchorPane;
private Rectangle player;
private Circle circles;
private Button up, down;
private Timeline timer;
#Override
public void start(Stage primaryStage) {
stage = primaryStage;
root = new BorderPane();
scene = new Scene(root, 600, 500); //width and height of application
stage.setScene(scene);
stage.setTitle("Hoop runner"); //text for the title bar of the window
scene.getStylesheets().add("hoop.css");
anchorPane = new AnchorPane();
anchorPane.setMaxHeight(500);
anchorPane.setMinHeight(500);
anchorPane.setMinWidth(600);
anchorPane.setMaxWidth(600);
player = new Rectangle();
circles = new Circle();
up = new Button("˄");
down = new Button("˅");
root.setCenter(new VBox(new VBox(circles),
new HBox(player)));
root.setCenter(anchorPane);
player.setX(5);
player.setY(380);
player.setHeight(80);
player.setWidth(120);
anchorPane.getChildren().add(player);
timer = new Timeline(Animation.INDEFINITE);
timer.setCycleCount(Animation.INDEFINITE);
timer.getKeyFrames().add(new KeyFrame(Duration.INDEFINITE, event -> maverick()));
timer.play();
stage.show();
}
private void maverick() {
timer.play();
System.out.println("hi");
player.setX(player.getX() + 2);
timer.play();
}
public static void main(String[] args) {
launch(args);
}
}
Use setTranslateX instead of setX if you want to position or animate Nodes.
Change timer = new Timeline(Animation.INDEFINITE) to timer = new Timeline().
Change new KeyFrame(Duration.INDEFINITE, event -> maverick()) to new KeyFrame(Duration.millis(500), event -> maverick()) (for example).
A KeyFrame has to have a point in time. If, like the example, you use 500ms, then the KeyFrame's EventHandler will get called after 500ms. Since your TimeLine has a cycleCount of INDEFINITE, it will loop and execute the KeyFrame every 500ms.
Related
I am creating a Solitaire game using JavaFX. I want a Restart button to start a new game, but also a Reset button that will restart the same game i.e. the same scene to its original state.
Restart works seamlessly as I was able to call the start method but I am unable to get Reset working.
package guisolitaire;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
public class GUISolitaire extends Application {
Game game;
Pane root;
ScoreTimer timer = new ScoreTimer();
#Override
public void start(Stage primaryStage) {
Canvas canvas = new Canvas(1000, 800);
root = new Pane(canvas);
root.setStyle("-fx-background-color: green");
game = new Game(canvas.getGraphicsContext2D());
canvas.setOnMouseClicked(game::handleMouseClicked);
timer.restart();
timer.start();
Scene scene = new Scene(root, Color.GREEN);
primaryStage.setScene(scene);
primaryStage.setTitle("Solitaire");
primaryStage.show();
Label l = new Label(); // Timer label
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, ae -> l.setText("Time elapsed: " + timer.s)),
new KeyFrame(Duration.seconds(1))
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
l.setTranslateX(800);
l.setTranslateY(765);
root.getChildren().add(l);
Button newGameButton = new Button();
newGameButton.setText("New Game");
newGameButton.setTranslateX(10);
newGameButton.setTranslateY(765);
root.getChildren().add(newGameButton);
EventHandler<ActionEvent> newGameEvent = ae -> {
timer.stop();
timer.restart();
start(primaryStage);
};
newGameButton.setOnAction(newGameEvent);
Button restart = new Button();
restart.setText("Restart");
restart.setTranslateX(100);
restart.setTranslateY(765);
root.getChildren().add(restart);
EventHandler<ActionEvent> resetGameEvent = ae -> {
primaryStage.setScene(scene);
primaryStage.show();
timer.stop();
timer.restart();
};
restart.setOnAction(resetGameEvent);
}
public static void main(String[] args) {
launch(args);
}
}
I have tried to reset primaryStage with the same scene and call the show method but that does not restart the game, it does not do anything.
Any ideas on how this may be able to be implemented?
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.shape.ArcType;
import javafx.stage.Stage;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Arc;
import javafx.scene.paint.Color;
import javafx.scene.control.Button;
import javafx.scene.Group;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.animation.PathTransition;
import javafx.util.Duration;
import javafx.scene.shape.Ellipse;
public class MovingFourFans extends Application
{
private Button btPause = new Button("Pause");
private Button btResume = new Button("Resume");
private Button btReverse = new Button("Reverse");
private Circle fanPanel;
private Ellipse fanPath;
private Arc fan1;
private Arc fan2;
private Arc fan3;
private Arc fan4;
private BorderPane uiContainer;
private HBox buttonContainer;
private PathTransition pt = new PathTransition();
#Override
public void start(Stage primaryStage)
{
BorderPane pane = new BorderPane();
Scene scene = new Scene(pane, 400, 500);
buttonContainer = new HBox(btPause, btResume, btReverse);
buttonContainer.setAlignment(Pos.CENTER);
Group group = new Group();
pane.setCenter(group);
pane.setBottom(buttonContainer);
// include a path transition with a circle inside instead
fanPanel = new Circle(Math.min(pane.getWidth(), pane.getHeight()) / 4);
fanPanel.setFill(Color.WHITE);
fanPanel.setStroke(Color.BLACK);
fanPath = new Ellipse(fanPanel.getRadius() / 100, fanPanel.getRadius() / 100);
fanPath.setVisible(true);
fanPath.setFill(Color.WHITE);
fanPath.setStroke(Color.BLACK);
fan1 = new Arc();
fan1.setType(ArcType.ROUND);
fan1.setRadiusX(fanPanel.getRadius() - 10);
fan1.setRadiusY(fanPanel.getRadius() - 10);
fan1.setStartAngle(80);
fan1.setLength(-10);
fan1.setFill(Color.RED);
group.getChildren().addAll(fanPanel, fanPath, fan1);
pt.setPath(fanPath);
pt.setNode(fan1);
pt.setCycleCount(Timeline.INDEFINITE);
pt.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
pt.setDuration(Duration.seconds(3));
pt.setAutoReverse(false);
pt.play();
btPause.setOnAction(e -> pt.pause());
btResume.setOnAction(e -> pt.play());
primaryStage.setTitle("Control Moving Fan");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
Application.launch(args);
}
}
I'm having a problem trying to create an animation of a fan with four wings with Javafx. I know how to make the buttons work but for the animation every time I start it, the fans moving along the circle path that I created with its middle section not the tip of the section. Because of this the animation doesn't look correct. Does anyone know a fix to this or what method I can use to create the correct animation for this? In this code I only made one wing for test and there are 3 wings left. The screenshot for what I currently have is below.
New to java and JavaFX so please bear with me
I need to do a presentation of 5 3d fruit models that show in a continuous loop, 15 seconds apart: fruit1 for 15 seconds then fruit2 for 15 seconds ad so on and so forth.. until fruit5 for 15 seconds and then back to fruit1 and continues until I hit the ESC key which should close the window.
I also understand that it's ideal to change the root group object that makes up the scene instead of changing the scene, so I changed that in my code
I understand that a timeline is needed in order to change something in the scene as it plays out, but I've tried with something similar to what this answer says but I don't get the logic of how to switch the root of the scene every 15seconds
UPDATE:
I gave up on the timeline option and I found the platform.run option as seen on this article which seems to work as I see the window updates iterating from the first fruit in the scenes array to second one but I'm not sure why it only runs once when I need it to run every 15 seconds which means that my scene switcher: nextSceneIndex() should go back and forth between 1 and 0.
UPDATE2:
I went back to the timeline suggestion and I implemented Sedrick's solution and it worked... I can't be happier :)
Here's my working code!
public void start(Stage stage) throws Exception {
BorderPane[] scenes = new BorderPane[]{createSceneApple(),createSceneCarrot(),createSceneTomato()};
Timeline tl = new Timeline();
tl.setCycleCount(Animation.INDEFINITE);
KeyFrame kf_fruit = new KeyFrame(Duration.seconds(10),
new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
if (index==0){
root.getChildren().setAll(scenes[0]);
index = 1;
}else if(index==1){
root.getChildren().setAll(scenes[1]);
index = 2;
}else if(index==2){
root.getChildren().setAll(scenes[2]);
index = 0;
}
}
});
tl.getKeyFrames().add(kf_fruit);
tl.play();
Scene scene = new Scene(root, windowWidth, windowHeight);
stage.setScene(scene);
stage.show();
}
Maybe you can get some ideas from here. This uses the code from the link I posted above. Timeline is used to loop through a list of Shape and info about that shape.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
* JavaFX App
*/
public class App extends Application {
#Override
public void start(Stage stage) {
List<MyShape> shapes = new ArrayList();
shapes.add(new MyShape("Circle", "Shape.Circle", "More Circle Info", new Circle(25, Color.BLUE)));
shapes.add(new MyShape("Rectangle", "Shape.Rectangle", "More Rectangle Info", new Rectangle(100, 50, Color.RED)));
shapes.add(new MyShape("Line", "Shape.Line", "More Line Info", new Line(0, 0, 100, 100)));
TextField tf1 = new TextField();
TextField tf2 = new TextField();
TextArea ta1 = new TextArea();
VBox leftWindow = new VBox(tf1, tf2, ta1);
StackPane rightWindow = new StackPane(shapes.get(1).getShape());
AtomicInteger counter = new AtomicInteger();
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(counter.get() % shapes.size());
MyShape currentShape = shapes.get(counter.getAndIncrement() % shapes.size());
tf1.setText(currentShape.getName());
tf2.setText(currentShape.getType());
ta1.setText(currentShape.getMoreInfo());
rightWindow.getChildren().set(0, currentShape.getShape());
}
}));
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
BorderPane root = new BorderPane();
root.setLeft(new StackPane(leftWindow));
root.setRight(rightWindow);
var scene = new Scene(root, 640, 480);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Update:
If you only have two scenes, that simplifies some things. You basically need to set the initial view. You then need to switch out the view currently showing every two seconds. (I used two seconds so that you can see the views before they are switched out). I created my own version of createSceneCarrot and createSceneApple since I don't know your implementation.
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
* JavaFX App
*/
public class App extends Application {
#Override
public void start(Stage stage) {
BorderPane[] scenes = new BorderPane[]{createSceneApple(),createSceneCarrot()};
StackPane root = new StackPane(scenes[0]);//Set initial view;
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(2), (ActionEvent event) -> {
if(root.getChildren().get(0).equals(scenes[0]))//If the first scene is loaded, load the second scene.
{
root.getChildren().set(0, scenes[1]);
}
else
{
root.getChildren().set(0, scenes[0]);
}
}));
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
var scene = new Scene(root, 640, 640);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
public BorderPane createSceneApple()
{
BorderPane borderPane = new BorderPane();
TextField tf1 = new TextField("Rectangle 1");
TextField tf2 = new TextField("Rectangle Color: Blue");
TextArea ta1 = new TextArea("20x40");
VBox leftWindow = new VBox(tf1, tf2, ta1);
borderPane.setLeft(leftWindow);
StackPane rightWindow = new StackPane(new Rectangle(20, 40, Color.BLUE));
borderPane.setRight(rightWindow);
return borderPane;
}
public BorderPane createSceneCarrot()
{
BorderPane borderPane = new BorderPane();
TextField tf1 = new TextField("Circle 1");
TextField tf2 = new TextField("Circle Color: Blue");
TextArea ta1 = new TextArea("Radius: 50");
VBox leftWindow = new VBox(tf1, tf2, ta1);
borderPane.setLeft(leftWindow);
StackPane rightWindow = new StackPane(new Circle(50, Color.RED));
borderPane.setRight(rightWindow);
return borderPane;
}
}
I have to create a program using JavaFX that creates a pane with a ball in it. There are four buttons that move the ball either left, right, up, or down. I don't understand why when I go to define each method (like .left() shown) the method call above remains an error that tells me it is undefined.
Main class:
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.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class MoveTheBall extends Application {
#Override
public void start(Stage primaryStage) {
StackPane pane = new StackPane();
Circle circle = new Circle(20);
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
pane.getChildren().add(circle);
HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.setAlignment(Pos.CENTER);
Button btLeft = new Button("Left");
Button btRight = new Button("Right");
Button btUp = new Button("Up");
Button btDown = new Button("Down");
hBox.getChildren().add(btLeft);
hBox.getChildren().add(btRight);
hBox.getChildren().add(btUp);
hBox.getChildren().add(btDown);
BorderPane borderPane = new BorderPane();
borderPane.setCenter(pane);
borderPane.setBottom(hBox);
BorderPane.setAlignment(hBox, Pos.CENTER);
Scene scene = new Scene(borderPane, 300, 200);
primaryStage.setTitle("Move The Ball");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Buttons class:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ControlBall extends Application {
private MoveTheBall moveTheBall = new MoveTheBall();
#Override
public void start(Stage primaryStage) {
HBox hBox = new HBox();
hBox.setSpacing(5);
hBox.setAlignment(Pos.CENTER);
Button btLeft = new Button("Left");
Button btRight = new Button("Right");
Button btUp = new Button("Up");
Button btDown = new Button("Down");
hBox.getChildren().add(btLeft);
hBox.getChildren().add(btRight);
hBox.getChildren().add(btUp);
hBox.getChildren().add(btDown);
btLeft.setOnAction(new LeftHandler());
btRight.setOnAction(new RightHandler());
btUp.setOnAction(new UpHandler());
btDown.setOnAction(new DownHandler());
BorderPane borderPane = new BorderPane();
borderPane.setCenter(moveTheBall);
borderPane.setBottom(hBox);
BorderPane.setAlignment(hBox, Pos.CENTER);
Scene scene = new Scene(borderPane, 200, 150);
primaryStage.setTitle("Move The Ball");
primaryStage.setScene(scene);
primaryStage.show();
}
class LeftHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent e) {
moveTheBall.left(); // error because no class yet
}
}
class RightHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent e) {
moveTheBall.right(); // error because no class yet
}
}
class UpHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent e) {
moveTheBall.up(); // error because no class yet
}
}
class DownHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent e) {
moveTheBall.down(); // error because no class yet
}
}
}
class moveTheBall extends StackPane {
private Circle ball = new Circle(20);
public moveTheBall() {
getChildren().add(ball);
ball.setStroke(Color.BLACK);
ball.setFill(Color.WHITE);
}
public void left() {
ball.setCenterX(-2.0);
ball.setCenterY(-2.0);
}
}
The line borderPane.setCenter(moveTheBall); is giving me problems as well. "The method setCenter(Node) in the type BorderPane is not applicable for the arguments (MoveTheBall)"
I'm pretty new to JavaFX, but I'm gonna do the best I can here.
I would suggest instead of doing totally separate classes for controlling the ball, moving the ball, and handling each button, look into using lambda expressions to simplify the code and reduce your room for error. For example, you can set what the btRight button does by writing a line like this:
btRight.setOnAction(e -> {
//if the ball is inside the right limit
//Move the ball to the right
});
You can write these expressions directly into your start() method, and avoid defining inner classes, as well as a separate class for the control.
As far as why you are getting an error, my best guess (as i said, I'm new to this) is that moveTheBall() is a constructor for the MoveTheBall class, but it is being called as a method.
Hope this helps.
Is there any way to translate somethings like pop up windows(that are not Node) in java FX ?
for example fade transition , translate transition or any timeline transition .... .
Thank's
Create a property and use a Timeline to "animate" the property. Register a listener with the property and update the window when its value changes.
For example:
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TranslateWindowExample extends Application {
#Override
public void start(Stage primaryStage) {
Button moveButton = new Button("Move");
moveButton.setOnAction(event -> {
double currentX = primaryStage.getX() ;
DoubleProperty x = new SimpleDoubleProperty(currentX);
x.addListener((obs, oldX, newX) -> primaryStage.setX(newX.doubleValue()));
KeyFrame keyFrame = new KeyFrame(Duration.seconds(1), new KeyValue(x, currentX + 100));
Timeline animation = new Timeline(keyFrame);
animation.play();
});
StackPane root = new StackPane(moveButton);
Scene scene = new Scene(root, 250, 150);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Can you give an example of what do you call popup window ?
For instance, you can create a new stage on the top of your main stage.
You can also use some Tooltip class to add some text over the top of your window.
If you want more classical windows, you should have a look to Alert class.
Anthony