简体   繁体   中英

Java: SetText inside a thread

Can anyone please help me with this:

I have some TextFields that i want to use as a timer (or a clock) so i set the text in a thread that i call inside my controller class.

package application;

import java.net.URL;
import java.util.ResourceBundle;

import org.joda.time.DateTime;

import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import jdk.nashorn.internal.runtime.FindProperty;

public class MainWindowController extends Thread implements Initializable{

@FXML
private TextField dayText;

@FXML
private TextField monthText;

@FXML
private TextField yearText;

@FXML
private TextField hoursText;

@FXML
private TextField minutesText;

@FXML
private TextField secondsText;

@FXML
private TextField julianDayText;

@Override
public void initialize(URL arg0, ResourceBundle arg1) {

    this.start();

}

@Override
public void run() {

        while(true){

            DateTime d = new DateTime(System.currentTimeMillis());

            dayText.setText(String.valueOf(d.getDayOfMonth()));
            monthText.setText(String.valueOf(d.getMonthOfYear()));
            yearText.setText(String.valueOf(d.getYear()));

            hoursText.setText(String.valueOf(d.getHourOfDay()));
            minutesText.setText(String.valueOf(d.getMinuteOfHour()));
            secondsText.setText(String.valueOf(d.getSecondOfMinute()));
        }
    }   
}

I don't know why i get a NullPointerException after running my code (it works for a little bit then it crashes) :

Exception in thread "Thread-4" java.lang.NullPointerException
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:339)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
at javafx.scene.control.TextInputControl$TextProperty.fireValueChangedEvent(TextInputControl.java:1116)
at javafx.scene.control.TextInputControl$TextProperty.markInvalid(TextInputControl.java:1120)
at javafx.scene.control.TextInputControl$TextProperty.set(TextInputControl.java:1056)
at javafx.scene.control.TextInputControl.setText(TextInputControl.java:279)
at application.MainWindowController.run(MainWindowController.java:208)

Please Help and thanks in advance

You can use TimeLine And KeyFrames. Just replace showTime() with your own code. and do not extend thread.

public class FXMLTimeController implements Initializable {

    @FXML
    private TextField txtTime;

    //timeline
    private Timeline timeline;

    private void showTime() {
        txtTime.setText((new Date()).toString());
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        timeline = new Timeline();
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.setAutoReverse(false);

        timeline.getKeyFrames().add(
                new KeyFrame(Duration.seconds(1),
                        new EventHandler<ActionEvent>() {
                            @Override public void handle(ActionEvent event) {
                                showTime();
                            }
                        }));
        timeline.play();
    }

}

I would suggest calling Platform.runLater(Runnable runnable) in initialize() while passing in JavaFX's TextField fields, instead of making your controller extend Thread, since JavaFX uses the controller for itself.

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        Platform.runLater(
            new someThread(dayText, monthText, yearText,
            hoursText, minutesText, secondsText));
    }

    public class someThread implements Runnable {

        public someThread(TextField... textFields) {
            // Create local variables
        }

        @Override
        public void run() {
            // while (true) loop goes here
        }

    }

You could also use this to pass in your controller as a parameter for someThread and make your TextField s public so they can be accessed by someThread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM