Is there a way to animate elements in GridPane - java

I'm trying to animate elements in GridPane. I have a class Unit that represents the things that I'm trying to move.
public class Unit {
private Text text;
private Rectangle rectangle;
private StackPane stackPane;
public Unit(Text text, Rectangle rectangle) {
this.text = text;
this.rectangle = rectangle;
text.setFill(Color.WHITE);
stackPane = new StackPane(rectangle, text);
}
public Text getText() {
return text;
}
public void setText(Text text) {
this.text = text;
}
public Rectangle getRectangle() {
return rectangle;
}
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
public StackPane getStackPane() {
return stackPane;
}
public void setStackPane(StackPane stackPane) {
this.stackPane = stackPane;
}
}
This is how i'm moving things now
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
GridPane gridPane = new GridPane();
gridPane.setVgap(5);
gridPane.setHgap(5);
Unit unit = new Unit(new Text("1"), new Rectangle(50, 50));
gridPane.add(unit.getStackPane(), 0, 0);
TranslateTransition translateTransition = new TranslateTransition();
translateTransition.setDuration(Duration.seconds(6));
translateTransition.setToX(200);
translateTransition.setToY(200);
translateTransition.setNode(unit.getStackPane());
translateTransition.play();
Scene scene = new Scene(gridPane, 300, 275);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Is there a way to move the unit to a specific row - column location. I assume that gridpane might not be suitable for my purpose but it's easy way to layout things the way i want.

Here is an example based upon the layout animator at Animation upon layout changes (also in the gist https://gist.github.com/jewelsea/5683558). I don't really know if it is really what you are looking for (it might be pretty close). But in any case it is pretty neat ;-)
I won't explain it too much here as the main explanation on what it is and how it works is at the previously linked question.
The referenced Unit class is the one from your question.
AnimatedSparseGrid.java
import javafx.animation.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.Point2D;
import javafx.scene.*;
import javafx.scene.layout.GridPane;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.*;
public class AnimatedSparseGrid extends Application {
private static final int NUM_UNITS = 10;
private static final int UNIT_SIZE = 30;
private static final int GRID_SIZE = 5;
private static final int GAP = 5;
private static final Duration PAUSE_DURATION = Duration.seconds(3);
private Random random = new Random(42);
private ObservableList<Unit> units = FXCollections.observableArrayList();
private GridPane gridPane = new GridPane();
#Override
public void start(Stage stage) throws Exception {
configureGrid();
LayoutAnimator animator = new LayoutAnimator();
animator.observe(gridPane.getChildren());
generateUnits();
relocateUnits();
continuouslyAnimateGrid();
stage.setScene(new Scene(gridPane));
stage.setResizable(false);
stage.show();
}
private void configureGrid() {
gridPane.setVgap(GAP);
gridPane.setHgap(GAP);
int size = GRID_SIZE * UNIT_SIZE + GAP * (GRID_SIZE - 1);
gridPane.setMinSize(size, size);
gridPane.setMaxSize(size, size);
}
private void generateUnits() {
for (int i = 0; i < NUM_UNITS; i++) {
Unit unit = new Unit(
new Text((i + 1) + ""),
new Rectangle(UNIT_SIZE, UNIT_SIZE)
);
units.add(unit);
}
}
private void relocateUnits() {
Set<Point2D> usedLocations = new HashSet<>();
for (Unit unit : units) {
Node node = unit.getStackPane();
int col;
int row;
do {
col = random.nextInt(GRID_SIZE);
row = random.nextInt(GRID_SIZE);
} while (usedLocations.contains(new Point2D(col, row)));
usedLocations.add(new Point2D(col, row));
GridPane.setConstraints(unit.getStackPane(), col, row);
if (!gridPane.getChildren().contains(node)) {
gridPane.add(node, col, row);
}
}
}
private void continuouslyAnimateGrid() {
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, event -> relocateUnits()),
new KeyFrame(PAUSE_DURATION)
);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
public static void main(String[] args) {
launch(args);
}
}

Some what hackish, but you can move the unit to the desired row - column, measure the new X,Y and use it for the translation.
The following code demonstrates animating from 0,0 to 20,20 :
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private Button move;
private Pane unitPane, root;
private GridPane gridPane;
#Override
public void start(Stage primaryStage) throws Exception{
gridPane = new GridPane();
gridPane.setVgap(5);
gridPane.setHgap(5);
unitPane = new Unit(new Text("1"), new Rectangle(50, 50)).getStackPane();
gridPane.add(unitPane, 0, 0);
move = new Button("Move");
move.setOnAction(e->animate());
root = new BorderPane(gridPane, null, null, move, null);
Scene scene = new Scene(root, 300, 275);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
private void animate() {
//remove unit, make it invisible, and add it to desired location
gridPane.getChildren().remove(unitPane);
unitPane.setVisible(false);
gridPane.add(unitPane, 20, 20);
root.layout(); //apply top down layout pass
//get x y of new location
double x = unitPane.getLayoutX(); double y = unitPane.getLayoutY(); //measure new location
//return to original location
gridPane.getChildren().remove(unitPane);
gridPane.add(unitPane, 0, 0);
unitPane.setVisible(true);
//apply translation to x,y of new location
TranslateTransition translateTransition = new TranslateTransition();
translateTransition.setDuration(Duration.seconds(3));
translateTransition.setToX(x);
translateTransition.setToY(y);
translateTransition.setNode(unitPane);
translateTransition.play();
//when translation is finished remove from original location
//add to desired location and set translation to 0
translateTransition.setOnFinished(e->{
gridPane.getChildren().remove(unitPane);
unitPane.setTranslateX(0);unitPane.setTranslateY(0);
gridPane.add(unitPane, 20, 20);
});
}
public static void main(String[] args) {
launch(args);
}
}
class Unit {
private Text text;
private Rectangle rectangle;
private StackPane stackPane;
Unit(Text text, Rectangle rectangle) {
this.text = text;
this.rectangle = rectangle;
text.setFill(Color.WHITE);
stackPane = new StackPane(rectangle, text);
}
public Text getText() {
return text;
}
public void setText(Text text) {
this.text = text;
}
public Rectangle getRectangle() {
return rectangle;
}
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
public StackPane getStackPane() {
return stackPane;
}
public void setStackPane(StackPane stackPane) {
this.stackPane = stackPane;
}
}

Related

JavaFX - refreshing a chart

I have two classes ViewTaskTest and ControllerTaskTest. The view has two buttons, one to create a random point and the other to start the controller. After the start, the controller will place 10 random points to the chart inside the view. But the points are visible only at the end. I want to see the points being placed one by one. I know, that I have to use somehow the Task-functions and I am struggling to understand this concept.
This is the ViewTaskTest-class:
package View;
import Controller.ControllerTaskTest;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.Axis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ViewTaskTest{
ScatterChart<Number, Number> scatterChart;
XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
Axis<Number> xAxis = new NumberAxis(0, 10, 2); ;
Axis<Number> yAxis = new NumberAxis(0, 10, 2); ;
Button buttonAddRandomPoint = new Button("Add random point");
Button buttonStartControllerTest = new Button("Start controller");
private final int MAIN_WINDOW_HEIGHT = 800;
private final int MAIN_WINDOW_WIDTH = 800;
ControllerTaskTest controller;
public ViewTaskTest() {
}
public void setController(ControllerTaskTest controller) {
this.controller = controller;
}
public void fillStage(Stage stage) {
stage.setTitle("QuickPID");
stage.setMinHeight(MAIN_WINDOW_HEIGHT);
stage.setMinWidth(MAIN_WINDOW_WIDTH);
stage.setMaxHeight(MAIN_WINDOW_HEIGHT);
stage.setMaxWidth(MAIN_WINDOW_WIDTH);
Scene sceneOne = new Scene(new Group());
scatterChart = new ScatterChart<Number, Number>(xAxis, yAxis);
scatterChart.getData().add(series);
// add a random point
buttonAddRandomPoint.setOnAction(e -> {
Double x = new Double(0.0);
Double y = new Double(0.0);
try{
x = Math.random() * 10;
y = Math.random() * 10;
series.getData().add(new XYChart.Data<Number, Number>(x, y));
} catch (Exception ex) {
System.out.println("Error");
}
});
buttonStartControllerTest.setOnAction(e -> {
controller.startAddingPoints();
});
VBox vboxButtons = new VBox(5);
HBox hboxMain = new HBox(5);
vboxButtons.getChildren().addAll(buttonAddRandomPoint, buttonStartControllerTest);
vboxButtons.setAlignment(Pos.BOTTOM_LEFT);
vboxButtons.setPadding(new Insets(10));
hboxMain.getChildren().addAll(scatterChart, vboxButtons);
sceneOne.setRoot(hboxMain);
stage.setScene(sceneOne);
}
public void addRandomPointFromController(Double x, Double y) {
System.out.println("starting view task");
Task<Integer> task = new Task<Integer>() {
#Override protected Integer call() throws Exception {
series.getData().add(new XYChart.Data<Number, Number>(x, y));
return 0;
}
};
task.run();
}
}
Here is the ControllerTestTask-Class:
package Controller;
import View.ViewTaskTest;
import javafx.concurrent.Task;
public class ControllerTaskTest {
ViewTaskTest view;
public ControllerTaskTest() {
}
public void setView(ViewTaskTest view) {
this.view = view;
}
public void startAddingPoints() {
System.out.println("starting controller task");
Task<Integer> task = new Task<Integer>() {
#Override protected Integer call() throws Exception {
for(int i = 0; i < 10; i++) {
Double x = Math.random() * 10;
Double y = Math.random() * 10;
view.addRandomPointFromController(x, y);
System.out.println("Adding point x = " + x + " and y = " + y);
Thread.sleep(100);
}
return 0;
}
};
task.run();
}
}
Here is the main-class:
package Test;
import Controller.ControllerTaskTest;
import View.ViewTaskTest;
import javafx.application.Application;
import javafx.stage.Stage;
public class Test extends Application{
private ViewTaskTest view= new ViewTaskTest();
private ControllerTaskTest controller = new ControllerTaskTest();
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage stage) throws Exception {
view.setController(controller);
controller.setView(view);
stage.show();
view.fillStage(stage);
}
}
Some please explain me what I am doing wrong. I am experimenting with the Thread-funcitons but I cant solve my problem.

Opening java file with button (javafx) [duplicate]

This question already has answers here:
JavaFX launch another application
(3 answers)
Closed 4 years ago.
I've got an app made in javafx and another class with menu in this project. In this menu I've got two buttons and one works (exit buuton) and I want buttonStart to open my Main class. How to launch it?
Button buttonStart = new Button("START GAME");
Button buttonExit = new Button("EXIT");
buttonExit.setOnMouseClicked(event -> System.exit(0));
My menu:
package pl.main;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Menu extends Application {
private BorderPane layout;
private Scene scene;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage window) throws Exception {
layout = new BorderPane();
scene = new Scene(layout, 720, 480);
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10);
hbox.setStyle("-fx-background-color: #F9A825;");
Button buttonStart = new Button("START GAME");
buttonStart.setPrefSize(100, 20);
buttonStart.setStyle("-fx-background-color: #E65100;");
Button buttonExit = new Button("EXIT");
buttonExit.setPrefSize(100, 20);
buttonExit.setStyle("-fx-background-color: #E65100;");
buttonExit.setOnMouseClicked(event -> System.exit(0));
hbox.getChildren().addAll(buttonStart, buttonExit);
layout.setCenter(hbox);
window.setScene(scene);
window.show();
}
}
Class which I wanna launch:
package pl.main;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
public class Main extends Application {
private HashMap<KeyCode, Boolean> keys = new HashMap<KeyCode, Boolean>();
private ArrayList<Node> blocks = new ArrayList<Node>();
private Pane appRoot = new Pane();
private Pane gameRoot = new Pane();
private Pane uiRoot = new Pane();
private Node player;
private Point2D playerGoDown = new Point2D(0, 0);
private Point2D playerGoRight = new Point2D(0, 0);
private boolean canJump = true;
private int levelWidth;
private void initContent() {
Rectangle background = new Rectangle(720, 480);
// BackgroundFill(Color.WHITE);
levelWidth = LevelData.LEVEL1[0].length();
for (int i = 0; i < LevelData.LEVEL1.length; i++) {
String map = LevelData.LEVEL1[i] + LevelData.LEVEL2[i]+ LevelData.LEVEL1[i]+ LevelData.LEVEL2[i]+ LevelData.LEVEL1[i]+ LevelData.LEVEL2[i];
String line = map;
for (int j = 0; j < line.length(); j++) {
switch (line.charAt(j)) {
case '0':
break;
case '1':
Node block = createEntity(j * 30, i * 30, 30, 30, Color.ORANGE);
blocks.add(block);
break;
}
}
}
player = createEntity(0, 350, 40, 40, Color.YELLOW);
// a ????????????
player.translateXProperty().addListener((a, old, newValue) -> {
int offset = newValue.intValue();
//if (offset > 360 && offset < levelWidth - 360) {
gameRoot.setLayoutX(-(offset - 360));
//}
});
appRoot.getChildren().addAll(background, gameRoot, uiRoot);
}
private void update() {
if (isPressed(KeyCode.W) && player.getTranslateY() >= 0) {
jumpPlayer();
}
if (playerGoDown.getY() < 10) {
playerGoDown = playerGoDown.add(0, 1);
}
movePlayerY((int) playerGoDown.getY());
if (player.getTranslateX() <= levelWidth - 5) {
// movePlayerX(5);
movePlayerRight();
}
if (playerGoRight.getX() < 0) {
playerGoRight = playerGoRight.add(0, 1);
}
movePlayerX((int) playerGoRight.getX());
}
private void movePlayerX(int value) {
boolean movingRight = value > 0;
for (int i = 0; i < Math.abs(value); i++) {
for (Node block : blocks) {
if (player.getBoundsInParent().intersects(block.getBoundsInParent())) {
if (movingRight) {
if (player.getTranslateX() + 40 == block.getTranslateX()) {
return;
}
} else {
if (player.getTranslateX() == block.getTranslateX() + 60) {
return;
}
}
}
}
player.setTranslateX(player.getTranslateX() + (movingRight ? 1 : -1));
}
}
private void movePlayerY(int value) {
boolean movingDown = value > 0;
for (int i = 0; i < Math.abs(value); i++) {
for (Node block : blocks) {
if (player.getBoundsInParent().intersects(block.getBoundsInParent())) {
if (movingDown) {
if (player.getTranslateY() + 40 == block.getTranslateY()) {
canJump = true;
return;
}
} else {
if (player.getTranslateY() == block.getTranslateY() + 60) {
return;
}
}
}
}
player.setTranslateY(player.getTranslateY() + (movingDown ? 1 : -1));
}
}
private void jumpPlayer() {
if (canJump) {
playerGoDown = playerGoDown.add(0, -10);
canJump = false;
}
}
private void movePlayerRight() {
playerGoRight = playerGoRight.add(10, 0);
}
private Node createEntity(int x, int y, int w, int h, Color color) {
Rectangle entity = new Rectangle(w, h);
entity.setTranslateX(x);
entity.setTranslateY(y);
entity.setFill(color);
gameRoot.getChildren().add(entity);
return entity;
}
private boolean isPressed(KeyCode key) {
return keys.getOrDefault(key, false);
}
#Override
public void start(Stage primaryStage) throws Exception {
initContent();
Scene scene = new Scene(appRoot);
scene.setOnKeyPressed(event -> keys.put(event.getCode(), true));
scene.setOnKeyReleased(event -> keys.put(event.getCode(), false));
primaryStage.setTitle("Jetpack gameplay");
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setResizable(false);
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
update();
}
};
timer.start();
}
public static void main(String[] args) {
launch(args);
}
}
In future I wanna change current Main.java into ordinary class because now I have two classes which works independently.
If you want to go on another page, you have to load the game scene.
Look at Scene class in JavaDoc.
Once you have your scene, you just have to add an ActionEvent to your button that will display your page.

Memory leak in JavaFX indefinite Timeline

I'm designing a stopwatch using JavaFX. The code runs well. Except for enormous cumulative memory leaks over time. The leak increases whenever I increase the Timeline's framerate. I'm currently on Ubuntu 16.04 with 4gigs of RAM, and the leak is happening at a speed of 300MB/min at 30fps. That's 5MBps. I can understand that this may happen due to the repetitive drawing over the Scene, but why would it be cumulative? Shouldn't the JVM take care of this?
Main.java :
package UI;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("StopWatch");
primaryStage.setScene(new Scene(getPane(), 400, 400));
primaryStage.show();
}
private BorderPane getPane(){
BorderPane pane = new BorderPane();
ClockUI clockUI = new ClockUI();
clockUI.setMinSize(200,200);
pane.setCenter(clockUI);
ButtonBar buttonBar = new ButtonBar();
Button startButton = new Button("Start");
startButton.setOnAction(e->clockUI.startClock());
Button pauseButton = new Button("Stop");
pauseButton.setOnAction(e->clockUI.stopClock());
Button resetButton = new Button("Reset");
resetButton.setOnAction(e->clockUI.resetClock());
buttonBar.getButtons().addAll(startButton, pauseButton, resetButton);
pane.setBottom(buttonBar);
return pane;
}
public static void main(String[] args) {
System.setProperty("prism.lcdtext","false");
launch(args);
}
}
ClockUI.java :
package UI;
import javafx.animation.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
/**
* Created by subhranil on 23/6/17.
*/
public class ClockUI extends StackPane {
private final Rotate hourRotate;
private final Rotate minuteRotate;
private final Rotate secondRotate;
private final Timeline hourTimeline;
private final Timeline minuteTimeline;
private final Timeline secondTimeline;
private final ParallelTransition clockTransition;
public ClockUI() {
super();
Line hourHand = getHand(80, Color.WHITE);
hourRotate = getRotate(hourHand);
hourTimeline = createRotateTimeline(Duration.hours(12), hourRotate);
Line minuteHand = getHand(100, Color.WHITE);
minuteRotate = getRotate(minuteHand);
minuteTimeline = createRotateTimeline(Duration.minutes(60), minuteRotate);
Line secondHand = getHand(90, Color.WHITE);
secondRotate = getRotate(secondHand);
secondTimeline = createRotateTimeline(Duration.seconds(60), secondRotate);
clockTransition = new ParallelTransition(hourTimeline, minuteTimeline, secondTimeline);
Circle back = new Circle(120);
back.centerXProperty().bind(widthProperty().divide(2));
back.centerYProperty().bind(heightProperty().divide(2));
back.setStyle("-fx-fill: #555555");
setStyle("-fx-background-color: #333333;");
getChildren().addAll(back, hourHand, minuteHand, secondHand);
}
private Timeline createRotateTimeline(Duration duration, Rotate rotate) {
Timeline timeline = new Timeline(30);
timeline.getKeyFrames().add(new KeyFrame(duration, new KeyValue(rotate.angleProperty(), 360)));
timeline.setCycleCount(Animation.INDEFINITE);
return timeline;
}
public void startClock() {
if (clockTransition.getStatus() != Animation.Status.RUNNING) {
clockTransition.play();
}
}
public void stopClock() {
if (clockTransition.getStatus() == Animation.Status.RUNNING) {
clockTransition.pause();
}
}
public void resetClock() {
stopClock();
clockTransition.stop();
}
private Rotate getRotate(Line line){
Rotate r = new Rotate(0);
r.pivotXProperty().bind(line.startXProperty());
r.pivotYProperty().bind(line.startYProperty());
line.getTransforms().add(r);
return r;
}
private Line getHand(int size, Paint color) {
Line hand = new Line();
hand.startXProperty().bind(widthProperty().divide(2));
hand.startYProperty().bind(heightProperty().divide(2));
hand.endXProperty().bind(widthProperty().divide(2));
hand.endYProperty().bind(heightProperty().divide(2).subtract(size));
hand.setStroke(color);
hand.setStrokeWidth(3);
return hand;
}
}
INFO : I've tried various other methods, like running an ExecutorService, using Task and Thread, but all yield same results.
Try this and see if you are having the same problem.
ClockGUI
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.transform.*;
/**
*
* #author Sedrick
*/
public class ClockGUI {
Circle clockFace;
Line second;
Line minute;
Line hour;
Rotate secondRotation;
Rotate minuteRotation;
Rotate hourRotation;
AnchorPane currentClockFace;
public ClockGUI()
{
currentClockFace = new AnchorPane();
currentClockFace.setPrefSize(100, 100);
clockFace = new Circle(100 / 2, 100 / 2, 100 / 2);
clockFace.setStroke(Color.BLACK);
clockFace.setFill(Color.TRANSPARENT);
second = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 40);
secondRotation = new Rotate();
secondRotation.pivotXProperty().bind(second.startXProperty());
secondRotation.pivotYProperty().bind(second.startYProperty());
second.getTransforms().add(secondRotation);
minute = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 30);
minuteRotation = new Rotate();
minuteRotation.pivotXProperty().bind(minute.startXProperty());
minuteRotation.pivotYProperty().bind(minute.startYProperty());
minute.getTransforms().add(minuteRotation);
hour = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 20);
hourRotation = new Rotate();
hourRotation.pivotXProperty().bind(hour.startXProperty());
hourRotation.pivotYProperty().bind(hour.startYProperty());
hour.getTransforms().add(hourRotation);
currentClockFace.getChildren().addAll(clockFace, second, minute, hour);
}
public AnchorPane getCurrentClock()
{
return currentClockFace;
}
public void rotateSecondLine()
{
secondRotation.setAngle(secondRotation.getAngle() + 6);
}
public double getRotateSecondLine()
{
return secondRotation.getAngle();
}
public void setRotateSecond(double degree)
{
secondRotation.setAngle(degree);
}
public void rotateMinuteLine()
{
minuteRotation.setAngle(minuteRotation.getAngle() + 6);
}
public double getRotateMinuteLine()
{
return minuteRotation.getAngle();
}
public void setRotateMinute(double degree)
{
minuteRotation.setAngle(degree);
}
public void rotateHourLine()
{
hourRotation.setAngle(hourRotation.getAngle() + 6);
}
public double getRotateHourLine()
{
return hourRotation.getAngle();
}
public void setRotateHour(double degree)
{
hourRotation.setAngle(degree);
}
}
Main
import javafx.animation.*;
import javafx.application.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import javafx.util.*;
/**
*
* #author Sedrick
*/
public class JavaFXApplication54 extends Application {
#Override
public void start(Stage primaryStage)
{
VBox root = new VBox();
ClockGUI cgui = new ClockGUI();
StackPane stackpane = new StackPane();
stackpane.getChildren().add(cgui.getCurrentClock());
root.getChildren().add(stackpane);
Button btn = new Button("Rotate seconds");
btn.setOnAction((event) -> {
cgui.rotateSecondLine();
});
Button btn2 = new Button("Rotate minutes");
btn2.setOnAction((event) -> {
cgui.rotateMinuteLine();
});
Button btn3 = new Button("Rotate hours");
btn3.setOnAction((event) -> {
cgui.rotateHourLine();
});
root.getChildren().addAll(btn, btn2, btn3);
Scene scene = new Scene(root, 300, 250);
Timeline timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1),
new EventHandler() {
// KeyFrame event handler
#Override
public void handle(Event event)
{
System.out.println(cgui.getRotateSecondLine());
cgui.rotateSecondLine();
if (cgui.getRotateSecondLine() >= 360) {
cgui.setRotateSecond(0);
cgui.rotateMinuteLine();
}
if (cgui.getRotateMinuteLine() >= 360) {
cgui.setRotateMinute(0);
cgui.rotateHourLine();
}
if (cgui.getRotateHourLine() >= 360) {
cgui.setRotateHour(0);
}
}
}
));
timeline.playFromStart();
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}

Converting integer to double - in a tableview

I created a program with a column that calculate the seconds (seconden). Now i want to convert the type into a double instead of integer, because it gets me the wrong answer (for example (25-2000/160)*60 should give me 750 instead of 780 seconds in my countdown timer. How can i convert it ?
Class RuniteOre:
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.beans.property.IntegerProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.util.Duration;
public class RuniteOre extends Application {
Stage window;
TableView<Product> table;
TextField rockInput, worldInput, aantalSpelers;
int seconden;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
table = new TableView<>();
window = primaryStage;
window.setTitle("Runite Ore - Calculator");
//Rock column
TableColumn<Product, String> rockColumn = new TableColumn<>("Rock");
rockColumn.setMinWidth(100);
rockColumn.setCellValueFactory(new PropertyValueFactory<>("rock"));
//World column
TableColumn<Product, Integer> worldColumn = new TableColumn<>("World");
worldColumn.setMinWidth(100);
worldColumn.setCellValueFactory(new PropertyValueFactory<>("world"));
//Aantal spelers column
TableColumn<Product, Integer> aantalSpelersColumn = new TableColumn<>("Aantal Spelers");
aantalSpelersColumn.setMinWidth(100);
aantalSpelersColumn.setCellValueFactory(new PropertyValueFactory<>("aantalSpelers"));
TableColumn<Product, Integer> secondenColumn = new TableColumn<>("Seconden");
secondenColumn.setCellValueFactory(cellData -> cellData.getValue().secondsProperty().asObject());
table.getItems().addListener((Change<? extends Product> c) -> {
while (c.next()) {
if (c.wasAdded()) {
for (Product item : c.getAddedSubList()) {
int startValue = item.getSeconden() ;
Timeline countdown = new Timeline(new KeyFrame(Duration.seconds(1), e ->
item.setSeconden(item.getSeconden() - 1)
));
countdown.setCycleCount(startValue);
countdown.play();
}
}
}
});
//Rock input
rockInput = new TextField();
rockInput.setPromptText("Rocks");
rockInput.setMinWidth(100);
//World input
worldInput= new TextField();
worldInput.setPromptText("World");
//Aantal spelers input
aantalSpelers = new TextField();
aantalSpelers.setPromptText("Aantal Spelers");
//Button
Button addButton = new Button("Add");
addButton.setOnAction(e -> addButtonClicked());
Button deleteButton = new Button("Delete");
deleteButton.setOnAction(e -> deleteButtonClicked());
HBox hBox = new HBox();
hBox.setPadding(new Insets(10,10,10,10));
hBox.setSpacing(10);
hBox.getChildren().addAll(rockInput, worldInput, aantalSpelers, addButton, deleteButton);
table.getColumns().addAll(rockColumn, worldColumn, aantalSpelersColumn,secondenColumn);
VBox vBox = new VBox();
vBox.getChildren().addAll(table, hBox);
Scene scene = new Scene(vBox);
window.setScene(scene);
window.show();
}
//Add button clicked
public void addButtonClicked(){
Product product = new Product();
product.setRock(rockInput.getText());
product.setWorld(Integer.parseInt(worldInput.getText()));
product.setAantalSpelers(Integer.parseInt(aantalSpelers.getText()));
seconden=(25-((Integer.parseInt(aantalSpelers.getText()))/160))*60;
//seconden=(Integer.parseInt(aantalSpelers.getText()));
product.setSeconden(seconden);
table.getItems().add(product);
rockInput.clear();
worldInput.clear();
aantalSpelers.clear();
}
//Delete button clicked
public void deleteButtonClicked(){
ObservableList<Product> productSelected, allProducts;
allProducts = table.getItems();
productSelected = table.getSelectionModel().getSelectedItems();
productSelected.forEach(allProducts::remove);
}
}
Class Product:
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
public class Product {
private String rock;
private int world;
private int aantalSpelers;
//private int seconden;
private int timer;
private final IntegerProperty seconden = new SimpleIntegerProperty() ;
public Product(){
this.rock = "";
this.world = 0;
this.aantalSpelers = 0;
}
public Product(String rock, int world, int aantalSpelers){
this.rock = rock;
this.world = world;
this.aantalSpelers = aantalSpelers;
}
public String getRock() {
return rock;
}
public void setRock(String rock) {
this.rock = rock;
}
public int getWorld() {
return world;
}
public void setWorld(int world) {
this.world = world;
}
public int getAantalSpelers() {
return aantalSpelers;
}
public void setAantalSpelers(int aantalSpelers) {
this.aantalSpelers = aantalSpelers;
}
public final int getSeconden() {
return secondsProperty().get();
}
public final void setSeconden(int seconden) {
secondsProperty().set(seconden);
}
// public int getTimer() {
// return timer;
//}
//public void setTimer(int timer) {
// this.timer = timer;
// }
public Product(int seconden) {
setSeconden(seconden);
}
public IntegerProperty secondsProperty() {
return seconden ;
}
}
I might be missing something. Why don't you just change the type to double?
double seconden=(25-((Double.parseDouble(aantalSpelers.getText()))/160))*60;
Update: If you don't want to change your seconden attribute to double, then you need to cast
int seconden= (int)((25-((Double.parseDouble(aantalSpelers.getText()))/160))*60);
The key here is that your keep your data to double during the division (aantalSpelers.getText()))/160) , otherwise it would truncate your result. Later you could safely cast back to integer
Try this
double seconden=(25-((Double.parseDouble(aantalSpelers.getText()))/160))*(double)60;
Also
Change the parameters of your setSeconden(int seconden){...} method in order to accept double data types setSeconden(double seconden){...}
,
`public final int getSeconden() {....}` to `public final double getSeconden() {...}`
And
public IntegerProperty secondsProperty(){.....} to public DoubleProperty secondsProperty(){...}

How to get the Cell (of a ListView) under the mouse pointer?

I wrote a thread that checks constantly if the mouse is over a ListView, because I want to show a Popup containing info about the cell I point with the mouse.
So no problem to check if the mouse is over the ListView.
But how do I check if the mouse is over a certain cell since I cannot use ListCell.localToScreen(ListCell.getBoundsInLocal()); to get the cell coordinates on screen?
I prefer not to use ListCell event such as onMouseEntered.
Either register handlers for mouseEntered and mouseExited events on each ListCell, or observe the ListCell's hoverProperty. Here's an example using the second method:
import java.util.stream.IntStream;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PopupOnListCellHover extends Application {
private Popup popup ;
private Node popupContent ;
private Label titleLabel ;
private Label detailsLabel ;
private FadeTransition fadeOut ;
#Override
public void start(Stage primaryStage) {
ListView<Item> listView = new ListView<>();
popup = new Popup();
titleLabel = new Label();
titleLabel.setStyle("-fx-font-size: 1.5em ; -fx-font-weight: bold;");
detailsLabel = new Label();
popupContent = new VBox(10, titleLabel, detailsLabel);
popupContent.setStyle("-fx-background-color: -fx-background; "+
"-fx-background: lightskyblue; -fx-padding:12px;");
popup.getContent().add(popupContent);
fadeOut = new FadeTransition(Duration.millis(500), popupContent);
fadeOut.setFromValue(1.0);
fadeOut.setToValue(0.0);
fadeOut.setOnFinished(e -> popup.hide());
listView.setCellFactory(lv -> {
ListCell<Item> cell = new ListCell<Item>() {
#Override
public void updateItem(Item item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
setText(item.getName());
}
}
};
cell.hoverProperty().addListener((obs, wasHovered, isNowHovered) -> {
if (isNowHovered && ! cell.isEmpty()) {
showPopup(cell);
} else {
hidePopup();
}
});
return cell ;
});
IntStream.rangeClosed(1, 100).mapToObj(i -> new Item("Item "+i, i))
.forEach(listView.getItems()::add);
BorderPane root = new BorderPane(listView);
Scene scene = new Scene(root, 250, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showPopup(ListCell<Item> cell) {
fadeOut.stop();
popupContent.setOpacity(1.0);
Bounds bounds = cell.localToScreen(cell.getBoundsInLocal());
popup.show(cell, bounds.getMaxX(), bounds.getMinY());
Item item = cell.getItem() ;
titleLabel.setText(item.getName());
detailsLabel.setText(String.format("This is %s.%nIt has value %d.",
item.getName(), item.getValue()));
}
private void hidePopup() {
fadeOut.playFromStart();
}
public static class Item {
private final int value ;
private final String name ;
public Item(String name, int value) {
this.name = name ;
this.value = value ;
}
public int getValue() {
return value ;
}
public String getName() {
return name ;
}
}
public static void main(String[] args) {
launch(args);
}
}
To use handlers for mouseEntered and mouseExited, replace
cell.hoverProperty().addListener((obs, wasHovered, isNowHovered) -> {
if (isNowHovered && ! cell.isEmpty()) {
showPopup(cell);
} else {
hidePopup();
}
});
with
cell.setOnMouseEntered(e -> showPopup(cell));
cell.setOnMouseExited(e -> hidePopup());

Categories