JavaFX - how refresh scene in every two seconds [duplicate] - java

This question already has answers here:
How to update the label box every 2 seconds in java fx?
(3 answers)
Closed 8 years ago.
Hi I want to create a simple game in JavaFx but I have problem. I create the scene with backgorund and images of people.
This source places 3 images of persons on background in random place.
Unfortunately I can't make that images moves.
Now i want refresh scene in every 2 seconds that persons will be places in new place.
package Game;
import java.util.Random;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.BoxBlur;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Game extends Application {
final static int h = 775;
final static int w = 523;
#Override
public void start(Stage primaryStage) throws InterruptedException {
Game x = new Game();
Group root = new Group(x.background, x.persons);
x.pokaz_tlo.setEffect(new BoxBlur());
x.pokaz_tlo.setOpacity(0.9);
primaryStage.setTitle("Good game");
primaryStage.setScene(new Scene(root, h, w));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Game{
final static Image background = new Image(Game.class.getResource("background.jpg").toString());
final static Image person1 = new Image(Game.class.getResource("person1.jpg").toString());
final static Image person2 = new Image(Game.class.getResource("person2.jpg").toString());
final static Image person3 = new Image(Game.class.getResource("person3.jpg").toString());
ImageView show_background = new ImageView(background);
ImageView show_person1 = new ImageView(person1);
ImageView show_person2 = new ImageView(person2);
ImageView show_person3 = new ImageView(person3);
Group persons = pokaz_ukrywaj_ludzi(show_person1, show_person2, show_person3);
public int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
public Group pokaz_ukrywaj_ludzi(ImageView person1, ImageView person2, ImageView person3) {
final int[] x = {164, 320, 475};
final int[] y = {75, 270};
person1.setTranslateX(x[randInt(0,2)]);
person1.setTranslateY(y[randInt(0,1)]);
person2.setTranslateX(x[randInt(0,2)]);
person2.setTranslateY(y[randInt(0,1)]);
person3.setTranslateX(x[randInt(0,2)]);
person3.setTranslateY(y[randInt(0,1)]);
Group l = new Group(person1, person2, person3);
return l;
}
}
Any idea?

Now here's the problem:
In JavaFX there is no void to like repaint() or validate() like in Swing.
But you can write your own void to refresh the whole window.
Every 2 sec:
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
// Here comes your void to refresh the whole application.
}
}, 2000, 2000);

You need to use a JavaFX Animation Timer
http://blog.netopyr.com/2012/06/14/using-the-javafx-animationtimer/

Related

change BackGround color of specific elements in a listView (JavaFx)

i'm working on a project and i'd like to find a way to change the background color of some elements in a listView. i've find a way to add css style class to the listView in general but not to specific elements .
Also , i've heard about cell factory but I dont know if cell factory can adapt during the programme or just set up things at the begging
(i have a listView of an object that I call player , and I want that , when the player in the listView get enough points , his name becomes red)
is there a way to do something like this ?
ListView<Players> listview = ...;
for(Player p : listView){
p.addListener(//change color to red)
}
Thanks
I would use ObservableList and addListener to the given List.
Sample code:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class App extends Application {
private StackPane main;
private ListView<Player> players;
#Override
public void start(Stage stage) {
main = new StackPane();
var scene = new Scene(main, 640, 480);
players = new ListView<Player>();
ObservableList<Player> playerObjs = FXCollections.observableArrayList (
new Player("A", 50),
new Player("B", 30),
new Player("C", 60),
new Player("D", 5),
new Player("E", 0)
);
players.setItems(playerObjs);
playerObjs.addListener(new ListChangeListener<Player>() {
#Override
public void onChanged(Change<? extends Player> change) {
updateView();
}
});
main.getChildren().add(players);
stage.setScene(scene);
stage.show();
}
public void updateView() {
for(int i = 0; i < players.getItems().size(); i++) {
if(players.getItems().get(i).getHp() < 10) {
players.getItems().get(i).setBackground(...);
}
}
}
public static void main(String[] args) {
launch();
}
}
Now, everytime the list changes, it calls updateView(), which if some condition holds, will set the given item Background to some value.
Let me know if that helped.

dynamic animation of object line with JAVAFX and SceneBuilder

i'm looking for a system to render this animation of the line dynamic with variable change:
public class FXMLDocumentController implements Initializable {
private long batt = 0;
#FXML
private Line lancettaBatteria;
public long mappa(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
#Override
public void initialize(URL url, ResourceBundle rb) {
Random random = new Random();
batt = random.nextInt(100);
long valMappatoBatteria = this.mappa(batt, 0, 100, -40, 135);
Rotate rotazioneBatteria = new Rotate();
lancettaBatteria.getTransforms().add(rotazioneBatteria);
Timeline timelineBatteria = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rotazioneBatteria.angleProperty(), -40)),
new KeyFrame(Duration.seconds(3), new KeyValue(rotazioneBatteria.angleProperty(), valMappatoBatteria)));
timelineBatteria.play();
}
with this code it show only the first random number, my target is to move the line for infinite time with the relative random number generated(i need the random number for display the line in particular position), is this possible? i try to sorround all with a while(true)
public void initialize(URL url, ResourceBundle rb) {
while(true){
Random random = new Random();
batt = random.nextInt(100);
long valMappatoBatteria = this.mappa(batt, 0, 100, -40, 135);
Rotate rotazioneBatteria = new Rotate();
lancettaBatteria.getTransforms().add(rotazioneBatteria);
Timeline timelineBatteria = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rotazioneBatteria.angleProperty(), -40)),
new KeyFrame(Duration.seconds(3), new KeyValue(rotazioneBatteria.angleProperty(), valMappatoBatteria)));
timelineBatteria.play();
}
}
but the app stop to work.
General Approaches
In general, an infinite animation in Java can be achieved multiple ways.
Here are a few:
Set the cycle count to indefinite to have an animation play forever:
Timeline.setCycleCount(Timeline.INDEFINITE);
Also setAutoReverse to true if you want it to go back and forth.
Use an AnimationTimer.
Use a Timeline and add an onFinished handler to the timeline which updates some relevant Keyframes within the timeline as necessary and then plays the timeline from start again.
The third approach of using an onFinishedHandler is the approach followed in the specific example below.
Specific Example
This example is based upon the requirements of your question as I understand them. I have no idea what why you are trying to do this. But as far as I understand what you are trying to do, the following app will do it.
Start position of each rotation:
Random max position of a rotation:
What it does is create a timeline which will update a value in a rotation transform for a line continuously. The line starts from a starting rotation angle, animates to a random maximum value and then animates back. Once the line reaches its starting position, a new random maximum value for the rotation is generated and the line animates to this new maximum value and back again. The process continues indefinitely. The setOnFinishedHandler of the timeline animation is the point which calculates the new random maximum value and updates the keyframe for the maximum animation value appropriately.
So that may or may not be exactly what you are trying to do, but perhaps it is enough for you to implement what you need.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.Random;
public class VariableLine extends Application {
private static final double S = 100;
#Override
public void start(Stage stage) throws Exception {
RandomRotator randomRotator = new RandomRotator();
Line line = new Line(0, S, S, S);
randomRotator.getRotate().setPivotY(S);
line.getTransforms().add(randomRotator.getRotate());
Label maxValueText = new Label(randomRotator.getMaxAngle() + "");
maxValueText.textProperty().bind(randomRotator.maxAngleProperty().asString());
stage.setScene(new Scene(new Pane(maxValueText, line), S, S * 2));
stage.show();
randomRotator.getTimeline().play();
}
public static void main(String[] args) {
launch(args);
}
}
class RandomRotator {
private static final Random random = new Random(42);
private static final double INIT_ANGLE = -40;
private static final double MAX_ANGLE = 90;
private static final Duration ROTATION_DURATION = Duration.seconds(3);
private final ReadOnlyDoubleWrapper maxAngle = new ReadOnlyDoubleWrapper(INIT_ANGLE);
private final Timeline timeline = new Timeline();
private final Rotate rotate = new Rotate(INIT_ANGLE);
RandomRotator() {
timeline.getKeyFrames().addAll(
new KeyFrame(
Duration.seconds(0),
new KeyValue(rotate.angleProperty(), INIT_ANGLE)
),
new KeyFrame(
ROTATION_DURATION.divide(2),
new KeyValue(rotate.angleProperty(), maxAngle.get())
),
new KeyFrame(
ROTATION_DURATION,
new KeyValue(rotate.angleProperty(), INIT_ANGLE)
)
);
timeline.setOnFinished(event -> {
maxAngle.set(random.nextInt((int) MAX_ANGLE));
timeline.getKeyFrames().set(
1,
new KeyFrame(
ROTATION_DURATION.divide(2),
new KeyValue(rotate.angleProperty(), maxAngle.get())
)
);
timeline.playFromStart();
});
}
Rotate getRotate() {
return rotate;
}
public double getMaxAngle() {
return maxAngle.get();
}
public ReadOnlyDoubleProperty maxAngleProperty() {
return maxAngle.getReadOnlyProperty();
}
public Timeline getTimeline() {
return timeline;
}
}

How to change the keyvalue's target value constantly in a javafx Timeline?

Instead of giving a fixed value as a target is there any way to continuously change the keyvalues's target value while the animation is running.
To achieve this goal I have bound the target value with a node's width property which changes continuously.But bind is not working at all when the animation starts the target value doesn't update and stuck.
This is the code for the animation
public void setGlowAnimation(){
System.out.println("WIDTH "+width.getValue());
KeyValue value = new KeyValue(glowshape.centerXProperty(),width.getValue(),Interpolator.EASE_OUT);
KeyFrame keyframe1 = new KeyFrame(Duration.millis(2000),value);
glow_timeline = new Timeline();
glow_timeline.setCycleCount(Timeline.INDEFINITE);
glow_timeline.setAutoReverse(true);
glow_timeline.getKeyFrames().add(keyframe1);
}
public void init(){
indetermination();
setStartAnimation();
createEllipse();
width = new SimpleDoubleProperty();
width.bind(this.widthProperty());
setGlowAnimation();
}
I don't think you can modify a Timeline while it is active like that. Consider using a Transition instead:
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class AdaptiveAnimation extends Application {
#Override
public void start(Stage primaryStage) {
Circle circle = new Circle(0, 100, 25, Color.CORNFLOWERBLUE);
Pane pane = new Pane(circle);
Interpolator interp = Interpolator.EASE_BOTH ;
Transition transition = new Transition() {
{
setCycleDuration(Duration.millis(2000));
}
#Override
protected void interpolate(double frac) {
double x = interp.interpolate(0, pane.getWidth(), frac);
circle.setCenterX(x);
}
};
transition.setCycleCount(Animation.INDEFINITE);
transition.setAutoReverse(true);
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
transition.play();
}
public static void main(String[] args) {
launch(args);
}
}
This is a little jumpy while you're resizing the window, but it provides the basic idea.

Animate images from array in javafx pane to scroll seamless in clip window

I am creating slot machine application with javafx. Desired behavior: separated pictures have to appear in pane as real slot machine drum during animation (pictures of cherry, lemon, number sever and etc should look like one whole peace for user) like showing on picture.
slot machine
My problem is I can't put together separate images to scrolling in slot machine window seamless.
I have made a lot of search about this problem but didn't find any working solutions. I have tried to add all images in ArrayList and then set them as node to TranslateTransition reference during animation process. But initial image stack in windows.
import javafx.animation.Interpolator;
import javafx.animation.ParallelTransition;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TestClass extends Application {
private BorderPane borderPane = new BorderPane();
private GridPane gridPane = new GridPane();
#Override
public void start(Stage primaryStage) throws Exception {
ImageView image1 = new ImageView(createImage(Color.RED));
ImageView image2 = new ImageView(createImage(Color.GREEN));
ImageView image3 = new ImageView(createImage(Color.BLUE));
gridPane.setLayoutX(50);
gridPane.setLayoutY(50);
gridPane.setPadding(new Insets(5, 5, 5, 5));
gridPane.setAlignment(Pos.CENTER);
gridPane.setVgap(5);
gridPane.add(image1, 0, 0);
gridPane.add(image2, 1, 0);
gridPane.add(image3, 2, 0);
gridPane.setMaxWidth(image1.getFitWidth() * 3);
gridPane.setMaxHeight(image1.getFitHeight());
Rectangle clip = new Rectangle(732, 230);
clip.setLayoutX(30);
clip.setLayoutY(10);
clip.setStroke(Color.BLACK);
// clip.setFill(null);
gridPane.setClip(clip);
borderPane.setCenter(gridPane);
Scene scene = new Scene(borderPane, 900, 500);
primaryStage.setScene(scene);
primaryStage.setTitle("SlotMachine");
primaryStage.show();
ImageView[] images = { image1, image2, image3 };
TranslateTransition t1 = new TranslateTransition();
for (ImageView i : images) {
t1.setDuration(Duration.millis(2000));
t1.setNode(i);
t1.setFromX(image1.getX());
t1.setFromY(image1.getY() - gridPane.getHeight());
t1.setToX(image1.getX());
t1.setToY(image1.getY() - image1.getFitHeight() / 2 + gridPane.getHeight());
t1.setCycleCount(2);
t1.setAutoReverse(false);
t1.setInterpolator(Interpolator.LINEAR);
}
TranslateTransition t2 = new TranslateTransition();
for (ImageView i : images) {
t2.setDuration(Duration.millis(2000));
t2.setNode(i);
t2.setFromX(image2.getX());
t2.setFromY(image2.getY() - gridPane.getHeight());
t2.setToX(image2.getX());
t2.setToY(image2.getY() - image2.getFitHeight() / 2 + gridPane.getHeight());
t2.setCycleCount(2);
t2.setAutoReverse(false);
t2.setInterpolator(Interpolator.LINEAR);
}
TranslateTransition t3 = new TranslateTransition();
for (ImageView i : images) {
t3.setDuration(Duration.millis(2000));
t3.setNode(i);
t3.setFromX(image3.getX());
t3.setFromY(image3.getY() - gridPane.getHeight());
t3.setToX(image3.getX());
t3.setToY(image3.getY() - image3.getFitHeight() / 2 + gridPane.getHeight());
t3.setCycleCount(2);
t3.setAutoReverse(false);
t3.setInterpolator(Interpolator.LINEAR);
}
ParallelTransition pt = new ParallelTransition(t2, t3, t1);
pt.play();
}
private final Image createImage(Color color) {
Rectangle rect = new Rectangle(32, 32);
rect.setFill(color);
return rect.snapshot(null, null);
}
public static void main(String[] args) {
launch(args);
}
}
Please help. Thank you in advance
From what I can tell, it doesn't look like you are using Model/View/Controller architecture; using this architecture is the easiest way (in my opinion) to implement a gui like this. In your case, you could model your logic from the following psuedo-code:
In Controller:
//changes x or y coordinate (depending on direction of movement) of top left corner
//the controller should change the values of x or y that are stored in your model
moveImageMethod(image);
In View:
//Number of ms between timer events, play with this number to make it smooth
private static final int TIMER_INTERVAL = 1000/30;
//constructor
public View(){
<your other stuff, event handlers, etc.>
this.timer = new Timer(TIMER_INTERVAL, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
handleTimerTick();
}
});
}
// Start the animation timer.
public void startTimer() {
timer.start();
}
protected void handleTimerTick(){
controller.moveImageMethod(image);
<other stuff you might need/want>
repaint();
}
<your graphics methods>

PaginationSample Javafx cannot assign a value to final variable pagination

I'm trying to reproduce a Pagination Sample from oracle samples, but when I imported the project something strange happened that I can not build and run the project:
The complete code is:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
public class PaginationSample extends Application {
private final Pagination pagination;
private Image[] images = new Image[7];
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
VBox outerBox = new VBox();
outerBox.setAlignment(Pos.CENTER);
//Images for our pages
for (int i = 0; i < 7; i++) {
images[i] = new Image(PaginationSample.class.getResource("animal" + (i + 1) + ".jpg").toExternalForm(), false);
}
pagination = PaginationBuilder.create().pageCount(7).pageFactory(new Callback<Integer, Node>() {
#Override public Node call(Integer pageIndex) {
return createAnimalPage(pageIndex);
}
}).build();
//Style can be numeric page indicators or bullet indicators
Button styleButton = ButtonBuilder.create().text("Toggle pagination style").onAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent me) {
if (!pagination.getStyleClass().contains(Pagination.STYLE_CLASS_BULLET)) {
pagination.getStyleClass().add(Pagination.STYLE_CLASS_BULLET);
} else {
pagination.getStyleClass().remove(Pagination.STYLE_CLASS_BULLET);
}
}
}).build();
outerBox.getChildren().addAll(pagination, styleButton);
root.getChildren().add(outerBox);
}
//Creates the page content
private VBox createAnimalPage(int pageIndex) {
VBox box = new VBox();
ImageView iv = new ImageView(images[pageIndex]);
box.setAlignment(Pos.CENTER);
Label desc = new Label("PAGE " + (pageIndex + 1));
box.getChildren().addAll(iv, desc);
return box;
}
#Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
}
But netbeans show me the error "cannot assign a value to final variable pagination" for the following line:
pagination = PaginationBuilder.create().pageCount(7).pageFactory(new Callback<Integer, Node>() {
Someone can explain me what is going wrong??
A final field can be initialized only once. So the best place to initialize it is when its declared
private final Pagination pagination = new Pagination(...);
or it can be done in the constructor, since the constructor is assured to be called once per instance
private final Pagination pagination;
public PaginationSample() {
pagination = new Pagination(...);
}
final field cannot be initialized in a method because a method can be called multiple times once an instance of that class gets created

Categories