Use TimeLine to trigger a void method every certain seconds JavaFX - java

Im trying to update a label every certain seconds, I tried using a normal Timer but since its in another thread it cannot make changes to the label, this is the Timer:
public void setTimer(Timer timer, int seconds, String userName, String content, VBox tabContent,ArrayList<Integer> countTweetsArray, Label statusLabel) {
TabContent tabContentObj = new TabContent();
timer.schedule(new TimerTask() {
#Override
public void run() {
setTweet(userName, content);
//tabContentObj.createStatusScreen(tabContent, countTweetsArray, remainingTweets);
System.out.println(content+" after "+seconds);
System.out.println("countTweetsArray: "+countTweetsArray.get(0));
statusLabel.setText(countTweetsArray.get(0).toString());
countTweetsArray.set(0, (countTweetsArray.get(0)+1));
tabContentObj.timersMap.put(userName, timer);
}
}, (seconds*1000));
}
I read that I can make periodic changes to a label using TimeLine but I cant understand how it works the keyvalues and the keyframes, Is there a way to just trigger a void method without any animation involved?

You can use the KeyFrame constructor that takes a Duration and an event handler:
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(seconds), e -> {
// code to execute here...
})
);
timeline.play();
Update: if you need a button to stop it, you can do that with
Button button = new Button("Stop");
button.setOnAction(e -> timeline.stop());

Related

JavaFX Displaying Time and Refresh in Every Second

Hello I would like to ask for any advice on this problem.
I would like to display current time in HH:MM:SS format (refreshing every second) in label or whatever component that is good for it.
Any advice?
EDIT: Someone asked for a code.. so I put it here for better description of the problem. "I have no code for that time What I'm trying to achieve is simple GUI diary and in one of the labels I would like to display time remaining until the closest event and in the other label I want to display like clocks that refreshes every second. I need it to get remaining time working. All I can think of is creating new thread that will do it and refreshes the clock, but I am not that advanced to use multithreading in JavaFX . So I was wondering if anyone can advice me with something less complicated than multithreading (I dont know how to implement that thread into JavaFX components)"
Version with Timeline:
long endTime = ...;
Label timeLabel = new Label();
DateFormat timeFormat = new SimpleDateFormat( "HH:mm:ss" );
final Timeline timeline = new Timeline(
new KeyFrame(
Duration.millis( 500 ),
event -> {
final long diff = endTime - System.currentTimeMillis();
if ( diff < 0 ) {
// timeLabel.setText( "00:00:00" );
timeLabel.setText( timeFormat.format( 0 ) );
} else {
timeLabel.setText( timeFormat.format( diff ) );
}
}
)
);
timeline.setCycleCount( Animation.INDEFINITE );
timeline.play();
Label main_clock_lb = new Label();
Thread timerThread = new Thread(() -> {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
while (true) {
try {
Thread.sleep(1000); //1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
final String time = simpleDateFormat.format(new Date());
Platform.runLater(() -> {
main_clock_lb.setText(time);
});
}
}); timerThread.start();//start the thread and its ok
One might find helpful how to print date and time for javaFx.
final Label clock = new Label();
final DateFormat format = DateFormat.getInstance();
final Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1),
new EventHandler()
{
#Override
public void handle(ActionEvent event)
{
final Calendar cal = Calendar.getInstance();
clock.setText(format.format(cal.getTime());
}
});
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
To solve your task using Timer you need to implement TimerTask with your code and use Timer#scheduleAtFixedRate method to run that code repeatedly:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
System.out.print("I would be called every 2 seconds");
}
}, 0, 2000);
Also note that calling any UI operations must be done on Swing UI thread (or FX UI thread if you are using JavaFX):
private int i = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jTextField1.setText(Integer.toString(i++));
}
});
}
}, 0, 2000);
}
In case of JavaFX you need to update FX controls on "FX UI thread" instead of Swing one. To achieve that use javafx.application.Platform#runLater method instead of SwingUtilities
final Label clock = new Label();
final DateFormat format = DateFormat.getInstance();
final Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1),
new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
final Calendar cal = Calendar.getInstance();
clock.setText(format.format(cal.getTime()));
}
}));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

How to pause javafx class

I am building an alarm and it consists of two parts
an animated button created in javafx class and the engine which is created normally
what I need is whenever user press the animated button that closes the button and fire up the engine then after the engine is closed there will be some time then animated button appears again and so on
so I used ::
notify_me.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
new engine();
Platform.exit();
}
});
and in order to repeat this process I used
Timer t = new Timer(0,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
while(true){
javafx.launch(javafx.class);
//some extra code goes here including sleep for
//some time and check for engine window state
}
}
});
t.start();
but I am facing two problems:
some extra code isn`t implemented until platform is exited,
launch() cannot be called more than once
so how can I achieve that without using threads ?? thanks
You probably won't get around using Threads. I'd recommend not shutting down the fx application thread however. Just close all windows and show (some of) them again after the delay:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Hide me 5 sec");
// prevent automatic exit of application when last window is closed
Platform.setImplicitExit(false);
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
// timer should be a daemon (-> not prevent jvm shutdown)
Timer timer = new Timer(true);
btn.setOnAction((ActionEvent event) -> {
timer.schedule(new TimerTask() {
#Override
public void run() {
// make window reappear (needs to happen on the application thread)
Platform.runLater(primaryStage::show);
}
}, 5000l);
// hide window
primaryStage.close();
});
// allow exiting the application by clicking the X
primaryStage.setOnCloseRequest(evt -> Platform.exit());
primaryStage.show();
}

JavaFX. stop everything, except one process

public void close(){
KeyValue opacity = new KeyValue(canvas
.opacityProperty(), 0);
KeyFrame end = new KeyFrame(Duration.millis(500),
opacity);
Timeline t = new Timeline(end);
t.play();
t.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
stage.close();
}
});
}
I have such a method, that changes opacity before quitting from app. It works fine, but during these 0.5 seconds Im still able to interact with UI. The question is how to stop everything except this Timeline execution before quitting?
Depends on how you set up your project. You could add a pane over the entire scene. Well, that doesn't prevent anyone from using the keyboard. So an alternative would be to consume all events like this:
root.addEventFilter(Event.ANY, e -> {
e.consume();
});
Call
stage.getScene().getRoot().setDisable(true);
before you start the timeline

Get seconds value and display to console window

I have coded a simple countdown timer in JavaFX and implements the Timer with binding so whenever the value of timeSeconds changes, the timerLabel text also changes.
How to get the value of current seconds and show it to console window?
the output should display the value of current seconds every new line like:
5
4
3
2
1
0
public class FXTimerBinding extends Application
{
// private class constant and somme variables
private static final Integer STARTTIME = 5;
private Timeline timeline;
private Label timerLabel = new Label();
private IntegerProperty timeSeconds = new SimpleIntegerProperty(STARTTIME);
#Override
public void start(Stage primaryStage)
{
// setup the Stage and the Scene(the scene graph)
primaryStage.setTitle("FX Timer binding");
Group root = new Group();
Scene scene = new Scene(root, 300, 250);
// configure the label
timerLabel.setText(timeSeconds.toString());
timerLabel.setTextFill(Color.RED);
timerLabel.setStyle("-fx-font-size: 4em;");
// Bind the timerLabel text property to the timeSeconds property
timerLabel.textProperty().bind(timeSeconds.asString());
// create and configure the Button
Button button = new Button("Start timer");
button.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event)
{
if(timeline != null)
timeline.stop();
timeSeconds.set(STARTTIME);
timeline = new Timeline();
KeyValue keyValue = new KeyValue(timeSeconds, 0);
KeyFrame keyFrame = new KeyFrame(Duration.seconds(STARTTIME + 1), keyValue);
timeline.getKeyFrames().add(keyFrame);
timeline.playFromStart();
System.out.println("get every seconds value and display to console window");
}
});
from: http://www.asgteach.com/blog/?p=334
If you want to perform some other action when the actual value of timeSeconds changes, just add a listener to it:
timeSeconds.addListener((observable, oldTimeValue, newTimeValue) -> {
// code to execute here...
// e.g.
System.out.println("Time left: "+newTimeValue);
});
If you are changing the UI in response to the countdown changing value, though, a binding of the kind of already have is preferable, imho.

Timeline is not running infinitely (JavaFx)

I used to have a simple, timed (more-or-less) infinite loop:
while (!canrun) {
do_stuff(); //simple calculation
update_gui(); //updates some labels
Thread.sleep(waittime);
}
Which, naturally freezes the JavaFX-Application until it is finished with all calculations (canrun is set to false).
I replaced it with a timeline:
event = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
do_stuff();
update_gui();
}
};
keyframe = new KeyFrame(Duration.millis(waittime), event);
timeline = new Timeline(Timeline.INDEFINITE, keyframe);
do_stuff() looks like this:
public void do_stuff() {
do_the_actual_stuff();
if (stuff_finished) timeline.stop();
}
(waittime is here a number between 1 and 1000 (ms)).
On Buttonclick I start it with timeline.play(), and in do_stuff() I stop it when the calculations are done with timeline.stop().
I also have a function to change the waittime (even when it runs):
public void changewaittime() {
if (!(timeline.getStatus() == Animation.Status.RUNNING)) {
keyframe = new KeyFrame(Duration.millis(waittime), event);
timeline = new Timeline(Timeline.INDEFINITE, keyframe);
} else {
timeline.stop();
keyframe = new KeyFrame(Duration.millis(waittime), event);
timeline = new Timeline(Timeline.INDEFINITE, keyframe);
timeline.play();
}
}
And now my problem is, the Timeline only runs once, and not continuously, it doesn't even enter do_stuff() again, only if I call timeline.play() again. Even directly calling timeline.setCycleCount(Timeline.INDEFINITE) doesn't help.
Anything I missed?
Edit: I was unable to find my mistake, so I rewrote the complete GUI and now it is working.
In the Timeline constructor you are setting the frame rate using a constant meant for cycle count.
Use http://docs.oracle.com/javafx/2/api/javafx/animation/Animation.html#setCycleCount(int).
Solved the problem by rewriting my complete GUI and Timeline. Don't know why it didn't work before, but now it is working.

Categories

Resources