场景中的JavaFX更新节点无法正常工作

时间:2019-12-30 17:13:51

标签: javafx

我正在尝试更新Label对象,它是场景中Pane的子级。 标签应该显示从设置的时间开始倒数,我使用了bind函数,StringProperty正在更新,但是节点本身未更新。

这是一个样本。可能看起来很长,但您可以直接将其复制并粘贴到IDE中,这将显示问题

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
}

在程序运行时,调试行确实显示StringProperty对象正在更新,这使我感到困惑,因为我认为如果绑定Label的textProperty,则场景中的Label将随着StringProperty更新而更新。任何见识都会有所帮助,谢谢!

1 个答案:

答案 0 :(得分:3)

问题是您正在重置对timeRemainingText的引用-因此不再绑定。您需要更改其中的值,而不是对象本身。由于您使用的是计时器,因此需要将线程改回FX线程-有更好的方法来执行此操作,但这不在此问题的范围内。

按如下所述更改一种方法,您将看到这项工作

 public void setTimeText( StringProperty timeText ) {
        Platform.runLater(() -> 
        this.timeRemainingText.set(timeText.getValue()));
        System.out.println("timeText: " + timeText.getValue());  // Debugging line
    }