Reputation: 187
I'm trying to update a Label object, which is a child of a Pane in a scene. The label is supposed to display a count-down from a set amount of time, I used the bind function, and the StringProperty is updating, but the node itself is not updating.
Here's a sample. Might seem long but you can literally just copy and paste it into the IDE and it will show the problem.
import javafx.application.*;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.beans.property.*;
import java.util.Timer;
import java.util.TimerTask;
public class LabelUpdateExample extends Application{
private StringProperty timeRemainingText = new SimpleStringProperty();
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Stage stage = new Stage();
Pane canvas = new Pane();
TimerField timerField = new TimerField(1);
timeRemainingText = timerField.getTimeText();
Label timeLabel = new Label("Start");
timeLabel.textProperty().bind(timeRemainingText);
// Adds the progress bar to the canvas, setting pref sizes
canvas.setPrefSize(800, 600);
canvas.getChildren().add(timeLabel);
Scene scene = new Scene(canvas, 800, 600);
stage.setScene(scene);
stage.show();
}
/**
* Updates the text to show the new remaining time
*
* @param timeText The text containing the new remaining time
*/
public void setTimeText( StringProperty timeText ) {
this.timeRemainingText = timeText;
System.out.println("timeText: " + timeText.getValue()); // Debugging line
}
/**
* A thingy that manipulates the timer and updates it in the toDoList
*/
class TimerField extends Thread {
private String timeText;
// Variables related to time
private int remTimeInSec;
private int remMin;
private int remSec;
private Timer timer;
/**
* Default constructor of a TimerField object
*
* @throws InterruptedException
*/
public TimerField(int timeInMinutes) throws InterruptedException {
// Sets up the variables related to time
this.remMin = timeInMinutes;
this.remSec = 0;
this.remTimeInSec = timeInMinutes * 60;
// Starts the timer that executes the time update task
timer = new Timer();
timer.scheduleAtFixedRate(new TimeUpdateTask(), 0, 1000);
}
class TimeUpdateTask extends TimerTask{
/**
* Updates the time remaining, or stop everything when time is up
*/
@Override
public void run(){
// TLDR: change the variables to represent one less second
if(remSec > 0){ remSec--; }
else{
remMin--;
remSec = 59;
}
remTimeInSec--;
getTimeText();
// Check for time up
if( remTimeInSec <= 0 ){timer.cancel();}
}
}
/**
* Gives a StringProperty object describing time left
*/
public StringProperty getTimeText( ){
// Creates a new string indicating the remaining time
this.timeText = "Time remaining: " + this.remMin +
"mins " + this.remSec + "secs";
StringProperty timeText = new SimpleStringProperty(this.timeText);
// Update it on the TimedToDoList
setTimeText(timeText);
return timeText;
}
public boolean timeUp(){
return this.remTimeInSec <= 0;
}
}
// end of class TimerField
}
As the program runs, the debugging line does show that the StringProperty object is being updated, which makes me confused because I thought if I bound the Label's textProperty, the Label in the Scene would update with as the StringProperty updates. Any insight helps, thanks!
Upvotes: 0
Views: 612
Reputation: 4209
The issue is that you are resetting your reference to timeRemainingText - so it is no longer bound. You need to change the value within it, not the object itself. Since you are using timer, you need to change the thread back to the FX thread - there are better ways to do that, but beyond the scope of this question.
Change the one method as noted below, and you will see this work
public void setTimeText( StringProperty timeText ) {
Platform.runLater(() ->
this.timeRemainingText.set(timeText.getValue()));
System.out.println("timeText: " + timeText.getValue()); // Debugging line
}
Upvotes: 4