JavaFX - refreshing a chart - java

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.

Related

JavaFX draw Multi shape using multiple points

I have an arraylist of Point. I want to draw lines out the points. Here is what I have done.
for (int i = 0; i < arrPoint.size(); i++) {
Point startPoint = arrPoint.get(i);
Point endPoint = null;
if (i == arrPoint.size()) {
endPoint = arrPoint.get(0);
} else {
endPoint = arrPoint.get(i + 1);
}
Line line = new Line();
line.setStartX(startPoint.getCoordinateX());
line.setEndX(endPoint.getCoordinateX());
line.setStartY(startPoint.getCoordinateY());
line.setEndY(endPoint.getCoordinateY());
box.getChildren().add(line);
}
My Point cass is like
public class Point {
private double coordinateX;
private double coordinateY;
public Point(double coordinateX, double coordinateY) {
this.coordinateX = coordinateX;
this.coordinateY = coordinateY;
}
public void setCoordinateX(double coordinateX) {
this.coordinateX = coordinateX;
}
public void setCoordinateY(double coordinateY) {
this.coordinateY = coordinateY;
}
public double getCoordinateX() {
return coordinateX;
}
public double getCoordinateY() {
return coordinateY;
}
}
My code is displayed blank. I am new to JavaFx. Can I get any help?
You need to have the points before you can loop over the points to draw.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Draw line");
Group g = new Group();
Scene scene = new Scene(g, 550, 550,Color.web("0x0000FF",1.0));
ObservableList<Point> arrPoint = FXCollections.observableArrayList();
Point point1 = new Point(100, 200);
Point point2 = new Point(300, 400);
arrPoint.addAll(point1, point2);
for (int i = 0; i < arrPoint.size()-1; i++) {
Point startPoint = arrPoint.get(i);
Point endPoint = null;
if (i == arrPoint.size()) {
endPoint = arrPoint.get(0);
} else {
endPoint = arrPoint.get(i + 1);
}
Line line = new Line();
line.setStartX(startPoint.getCoordinateX());
line.setEndX(endPoint.getCoordinateX());
line.setStartY(startPoint.getCoordinateY());
line.setEndY(endPoint.getCoordinateY());
g.getChildren().add(line);
}
primaryStage.setScene(scene);
primaryStage.show();
}
}
I hope it can help you some.

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

How to use jfxtra Magnifier and draw Rectangle on ImageView at the same time?

I'm trying to use the Magnifier from jfxtras-labs 2.2 to see more details on an image. At the same time, I want to draw a rectangle on top of this image. The problem is, that the Magnifier blocks all other events.
Here is my sample code:
package magnifiertest;
import java.io.File;
import javax.imageio.ImageIO;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.Magnifier;
public class TestMagnifier extends Application {
Group groupForRectangles;
ImageView pageImageView;
private boolean new_rectangle_is_being_drawn;
private Rectangle new_rectangle;
private double starting_point_x;
private double starting_point_y;
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
groupForRectangles = new Group();
groupForRectangles = new Group();
pageImageView = new ImageView();
pageImageView.setPreserveRatio(true);
pageImageView.setFitHeight(800);
pageImageView.setFitWidth(600);
pageImageView.setImage(SwingFXUtils.toFXImage(ImageIO.read(new File("/sample/Penguins.jpg")), null));
groupForRectangles.setOnMouseDragged(event -> {
setOnMouseDragged(event);
});
groupForRectangles.setOnMousePressed(event -> {
setOnMousePressed(event);
});
groupForRectangles.setOnMouseReleased(event -> {
setOnMouseReleased(event);
});
//If you outcomment the following lines, the rectangle drawing works
Magnifier m = new Magnifier(pageImageView);
groupForRectangles.getChildren().add(pageImageView);
groupForRectangles.getChildren().add(m);
root.getChildren().add(groupForRectangles);
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
public void setOnMousePressed(MouseEvent event) {
System.out.println("mouse pressed");
if (new_rectangle_is_being_drawn == false) {
starting_point_x = event.getX();
starting_point_y = event.getY();
System.out.println(starting_point_x + " ; " + starting_point_y);
groupForRectangles.getChildren().remove(new_rectangle);
new_rectangle = new Rectangle();
new_rectangle.setFill(Color.TRANSPARENT);
new_rectangle.setStroke(Color.BLACK);
groupForRectangles.getChildren().add(new_rectangle);
new_rectangle_is_being_drawn = true;
}
}
public void setOnMouseDragged(MouseEvent event) {
if (new_rectangle_is_being_drawn == true) {
double current_ending_point_x = event.getX();// - sub.getLayoutX();
double current_ending_point_y = event.getY();// - sub.getLayoutY();
adjust_rectangle_properties(starting_point_x, starting_point_y, current_ending_point_x,
current_ending_point_y, new_rectangle);
}
}
public void setOnMouseReleased(MouseEvent event) {
if (new_rectangle_is_being_drawn == true) {
new_rectangle.setFill(Color.TRANSPARENT);
new_rectangle_is_being_drawn = false;
}
}
void adjust_rectangle_properties(double starting_point_x, double starting_point_y, double ending_point_x,
double ending_point_y, Rectangle given_rectangle) {
given_rectangle.setX(starting_point_x);
given_rectangle.setY(starting_point_y);
given_rectangle.setWidth((ending_point_x - starting_point_x));
given_rectangle.setHeight((ending_point_y - starting_point_y));
if (given_rectangle.getWidth() < 0) {
given_rectangle.setWidth(-given_rectangle.getWidth());
given_rectangle.setX(given_rectangle.getX() - given_rectangle.getWidth());
}
if (given_rectangle.getHeight() < 0) {
given_rectangle.setHeight(-given_rectangle.getHeight());
given_rectangle.setY(given_rectangle.getY() -
given_rectangle.getHeight());
}
}
}
Thanks.

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(){...}

Countdown timer in javafx tableview

I am struggling to make a countdown timer in javaFX. I want the value of secondenColumn to be used as a timer. So for example when i add row with 'seconden'=200. The timer has to run for 200 seconds (until 0). I don't know how to begin with the code for the timer. This is what i have at the moment...
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 {
window = primaryStage;
window.setTitle("Runite Ore - Calculator");
//Rock column
TableColumn<Product, String> rockColumn = new TableColumn<>("Rock");
rockColumn.setMinWidth(200);
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"));
//Seconden column
//TableColumn<Product, Integer> secondenColumn = new TableColumn<>("Seconden");
//secondenColumn.setMinWidth(200);
//secondenColumn.setCellValueFactory(new PropertyValueFactory<>("seconden"));
TableView<Product> table = new TableView<>();
TableColumn<Product, Integer> secondenColumn = new TableColumn<>("Seconden");
table.getColumns().add(secondenColumn);
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 = new TableView<>();
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()));
//TESTBEREKENING seconden=(Integer.parseInt(aantalSpelers.getText())*10);
seconden=(Integer.parseInt(aantalSpelers.getText())*10);
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);
}
}
and this is the code from 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 ;
}
}
Just create a Timeline and decrease the value once per second every time a new row is added to the table:
public void start(Stage primaryStage) throws Exception {
// existing code...
// this just needs to be executed before any rows are added to the table:
table.getItems().addListener((Change<? extends Product> c) -> {
while (c.next()) {
if (c.wasAdded()) {
for (Product p : c.getAddedSubList()) {
int startValue = p.getSeconden();
Timeline countdown = new Timeline(new KeyFrame(Duration.seconds(1),
e -> p.setSeconden(p.getSeconden() - 1)));
countdown.setCycleCount(startValue);
countdown.play();
}
}
}
});
}
This assumes your Product class follows the JavaFX properties pattern, i.e. it has a public IntegerProperty secondenProperty() { ... } method.
Here is a SSCCE:
import java.util.regex.Pattern;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CountdownTable extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TableView<Item> table = new TableView<>();
TableColumn<Item, Integer> secondsCol = new TableColumn<>("Seconds");
table.getColumns().add(secondsCol);
secondsCol.setCellValueFactory(cellData -> cellData.getValue().secondsProperty().asObject());
table.getItems().addListener((Change<? extends Item> c) -> {
while (c.next()) {
if (c.wasAdded()) {
for (Item item : c.getAddedSubList()) {
int startValue = item.getSeconds() ;
Timeline countdown = new Timeline(new KeyFrame(Duration.seconds(1), e ->
item.setSeconds(item.getSeconds() - 1)
));
countdown.setCycleCount(startValue);
countdown.play();
}
}
}
});
TextField textField = new TextField();
textField.setPromptText("Type a time in seconds and press enter");
Pattern integerPattern = Pattern.compile("\\d*");
TextFormatter<Integer> formatter = new TextFormatter<Integer>( (TextFormatter.Change c) -> {
String newText = c.getControlNewText();
if (integerPattern.matcher(newText).matches()) {
return c ;
} else {
return null ;
}
});
textField.setTextFormatter(formatter);
textField.setOnAction(e -> {
if (! textField.getText().isEmpty())
table.getItems().add(new Item(Integer.parseInt(textField.getText())));
textField.clear();
});
BorderPane root = new BorderPane(table, null, null, textField, null);
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.show();
}
public static class Item {
private final IntegerProperty seconds = new SimpleIntegerProperty() ;
public Item(int seconds) {
setSeconds(seconds);
}
public IntegerProperty secondsProperty() {
return seconds ;
}
public final int getSeconds() {
return secondsProperty().get();
}
public final void setSeconds(int seconds) {
secondsProperty().set(seconds);
}
}
public static void main(String[] args) { launch(args); }
}

Categories