Can I set the label text in JavaFX using threads? - java

I want to constantly display the current mileage of the car without clicking on any button, etc.
Thread class
package threads;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import static controller.GameWindowController.*;
public class MileageThread implements Runnable {
#FXML
Label mileageLabel;
#Override
public void run() {
{
double time = 1;
while (true) {
try {
Thread.sleep(1000);
} catch (NullPointerException | InterruptedException e) {
e.printStackTrace();
}
getCar().setDistancePerSec((time * getCar().getCurrentCarSpeed()) / 3600);
getCar().setCarMileage(getCar().getCarMileage() + getCar().getDistancePerSec());
System.out.format("dziala %.3f km przebiegu %n", getCar().getCarMileage());
mileageLabel.setText(String.valueOf(getCar().getCarMileage()));
}
}
}
}
With this record I receive:
Exception in thread "Thread-5" java.lang.NullPointerException
at threads.MileageThread.run(MileageThread.java:27)
and here is the class in which I make the thread:
package controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import model.VehicleStatus;
import threads.MileageThread;
import vehicles.Car;
import java.net.URL;
import java.util.ResourceBundle;
public class GameWindowController extends Thread implements Initializable, Runnable {
#FXML
ImageView smoke;
#FXML
private Label speedLabel, mileageLabel;
static Car car;
static {
car = new Car() {
};
}
public void accelerationButtonPushed(ActionEvent event) throws InterruptedException {
car.accelerate();
speedLabel.setText(String.valueOf(car.getCurrentCarSpeed()));
smoke.setFitHeight(smoke.getX() + car.getCurrentCarSpeed());
smoke.setFitWidth(smoke.getY() + car.getCurrentCarSpeed());
System.out.println(car.getCurrentCarSpeed());
System.out.println(car.getCarMileage());
System.out.println(car.getFuel());
System.out.println(car.getStatus());
}
public void stopCarButtonPushed(ActionEvent event) throws InterruptedException {
if (car.getCurrentCarSpeed() == 0) {
System.out.println("Silnik zgasl!");
}
car.stop();
speedLabel.setText(String.valueOf(car.getCurrentCarSpeed()));
smoke.setFitHeight(smoke.getX() + car.getCurrentCarSpeed());
smoke.setFitWidth(smoke.getY() + car.getCurrentCarSpeed());
System.out.println(car.getCurrentCarSpeed());
System.out.println(car.getCarMileage());
System.out.println(car.getFuel());
System.out.println(car.getStatus());
}
public void startButtonPushed(ActionEvent event) throws InterruptedException {
if (car.getStatus() != VehicleStatus.MOVING) {
car.start();
} else System.out.println("Samochod juz jest na chodzie!");
System.out.println("Status pojazdu: " + car.getStatus());
}
#FXML
public void initialize(URL location, ResourceBundle resources) {
smoke.setFitHeight(1);
smoke.setFitWidth(1);
MileageThread mileageThread = new MileageThread();
Thread mt = new Thread(mileageThread);
mt.start();
}
public static Car getCar() {
return car;
}
}
I apologize if you find here some basic mistakes or if I misunderstood you.
I'm using a scene builder and I just want to put the text in one of the labels using MileageThread.

If you want to modify the user interface from a thread other than the JavaFX Application thread you must wrap it in a call to Platform.runLater()
Platform.runLater(() -> {
userInterfaceControl.setText("New Text");
});
JavaFX nodes/controls/etc. can only be modified from the JavaFX Application thread.

The solution that worked for me:
#FXML
public void initialize(URL location, ResourceBundle resources) {
PauseTransition wait = new PauseTransition(Duration.seconds(1));
wait.setOnFinished((e) -> {
mileageLabel.setText(String.valueOf(getCar().getCarMileage()));
wait.playFromStart();
});
wait.play();
}
I hope that someone will help :)

Related

TableView items not refreshing, but are correctly added, after adding them from a different controller

First I want to say that I already checked various similar solutions to this problem here, but the code design of the other users that posted this question is so different than mine that I don't understand how to fix the same problem using the solutions posted.
That said, I'm using javafx with gluon scene builder to create my first app. I'll post the code below. This (https://i.imgur.com/lO2mHZI.png) is how the app looks so far. The New button opens this window (https://i.imgur.com/kVZ5tjt.png).
I have a main class called WeightApp:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class WeightApp extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("foodTab.fxml"));
Scene main = new Scene(root);
primaryStage.setScene(main);
primaryStage.setTitle("App");
primaryStage.setMinWidth(root.minWidth(-1));
primaryStage.setMinHeight(root.minHeight(-1));
primaryStage.show();
}
public static void main(String[] args) {
launch(WeightApp.class);
}
}
A FoodTabController class which loads what's shown in the first picture without the window created by pressing New:
package application;
import application.domain.Aliment;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import java.io.*;
import java.util.Objects;
public class FoodTabController {
#FXML
protected AnchorPane app, foodTab, foodButtonBar;
#FXML
protected TabPane mainWindow;
#FXML
protected Tab summaryTabLabel, foodTabLabel;
#FXML
protected Label alimentsLabel;
#FXML
protected Button deleteButton, refreshButton, newButton, newMealWindow;
#FXML
protected TableView<Aliment> alimentsTableView;
#FXML
protected TableColumn<Aliment, String> alimentsNameCol;
#FXML
protected TableColumn<Aliment, Double> alimentsKcalCol, alimentsFatCol, alimentsCarbsCol, alimentsProteinCol, alimentsFiberCol;
protected ObservableList<Aliment> aliments = FXCollections.observableArrayList();
public void initialize() {
alimentsNameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
alimentsKcalCol.setCellValueFactory(new PropertyValueFactory<>("calories"));
alimentsFatCol.setCellValueFactory(new PropertyValueFactory<>("fat"));
alimentsCarbsCol.setCellValueFactory(new PropertyValueFactory<>("carbohydrate"));
alimentsProteinCol.setCellValueFactory(new PropertyValueFactory<>("protein"));
alimentsFiberCol.setCellValueFactory(new PropertyValueFactory<>("fiber"));
loadAliments();
alimentsTableView.setItems(aliments);
}
// Aliments //
public void newAlimentWindow() throws IOException {
Parent newAlimentWindow = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("newAlimentWindow.fxml")));
Stage stage = new Stage();
stage.setScene(new Scene(newAlimentWindow));
stage.show();
}
public void updateTableView() {
aliments.clear();
loadAliments();
}
public ObservableList<Aliment> alimentObservableList() {
return aliments;
}
public void deleteAliment() {
aliments.remove(alimentsTableView.getSelectionModel().getSelectedItem());
saveAliments();
}
public void saveAliments() {
String COMMA_DELIMITER = ",";
String NEW_LINE_SEPARATOR = "\n";
String FILE_HEADER = "aliment,calories,fat,carbs,protein,fiber";
FileWriter fw = null;
try {
fw = new FileWriter("aliments.csv");
fw.append(FILE_HEADER);
fw.append(NEW_LINE_SEPARATOR);
for (Aliment aliment : aliments) {
fw.append(String.valueOf(aliment.getName()));
fw.append(COMMA_DELIMITER);
fw.append(String.valueOf(aliment.getCalories()));
fw.append(COMMA_DELIMITER);
fw.append(String.valueOf(aliment.getFat()));
fw.append(COMMA_DELIMITER);
fw.append(String.valueOf(aliment.getCarbohydrate()));
fw.append(COMMA_DELIMITER);
fw.append(String.valueOf(aliment.getProtein()));
fw.append(COMMA_DELIMITER);
fw.append(String.valueOf(aliment.getFiber()));
fw.append(NEW_LINE_SEPARATOR);
}
} catch (Exception e) {
System.out.println("Error writing to file");
e.printStackTrace();
} finally {
try {
assert fw != null;
fw.flush();
fw.close();
} catch (IOException e) {
System.out.println("Error while flushing/closing FileWriter.");
e.printStackTrace();
}
}
}
public void loadAliments() {
String COMMA_DELIMITER = ",";
int ALIMENT_NAME = 0;
int ALIMENT_CALORIES = 1;
int ALIMENT_FAT = 2;
int ALIMENT_CARBS = 3;
int ALIMENT_PROTEIN = 4;
int ALIMENT_FIBER = 5;
BufferedReader fileReader = null;
try {
fileReader = new BufferedReader(new FileReader("aliments.csv"));
fileReader.readLine();
String line = "";
while ((line = fileReader.readLine()) != null) {
String[] tokens = line.split(COMMA_DELIMITER);
aliments.add(new Aliment(String.valueOf(tokens[ALIMENT_NAME]), Double.parseDouble(tokens[ALIMENT_CALORIES]), Double.parseDouble(tokens[ALIMENT_FAT]), Double.parseDouble(tokens[ALIMENT_CARBS]), Double.parseDouble(tokens[ALIMENT_PROTEIN]), Double.parseDouble(tokens[ALIMENT_FIBER])));
}
} catch (Exception e) {
System.out.println("Error reading aliments from CSV file");
e.printStackTrace();
} finally {
try {
assert fileReader != null;
fileReader.close();
} catch (IOException e) {
System.out.println("Error while trying to close FileReader");
e.printStackTrace();
}
}
}
// Aliments //
}
Finally, I have the newAlimentWindowController class that is the window the New button opens:
package application;
import application.domain.Aliment;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
public class newAlimentWindowController extends FoodTabController {
#FXML
protected Pane newAlimentPane;
#FXML
protected TextField newAlimentSetName, newAlimentSetCal, newAlimentSetFat, newAlimentSetCarbs, newAlimentSetProtein, newAlimentSetFiber;
#FXML
protected Button addButton;
public void initialize() {
loadAliments();
}
public void addAliment() {
aliments.add(new Aliment(newAlimentSetName.getText(), Double.parseDouble(newAlimentSetCal.getText()), Double.parseDouble(newAlimentSetFat.getText()), Double.parseDouble(newAlimentSetCarbs.getText()), Double.parseDouble(newAlimentSetProtein.getText()), Double.parseDouble(newAlimentSetFiber.getText())));
saveAliments();
updateTableView();
}
}
Also, the Aliment object:
package application.domain;
import java.util.Objects;
public class Aliment {
private String name;
private double weight;
private double calories, fat, carbohydrate, protein, fiber;
public Aliment(String name, double weight, double calories, double fat, double carbohydrate, double protein, double fiber) {
this(name, calories, fat, carbohydrate, protein, fiber);
this.weight = weight;
}
public Aliment(String name, double calories, double fat, double carbohydrate, double protein, double fiber) {
this.name = name;
this.weight = 100;
this.calories = calories;
this.fat = fat;
this.carbohydrate = carbohydrate;
this.protein = protein;
this.fiber = fiber;
}
Everything works fine, except after I type in the textfields in the New window and I press the Add button, the updateTableView method inside the addAliment method doesn't trigger (the Aliment item is added correctly, the observable list just doesn't refresh on the Add button press). However, the updateTableView method does work if I trigger it from inside the FoodTabController class that I linked to the Refresh button.
I don't understand what's happening: I can interact with the aliments observable list in FoodTabController from newAlimentWindowController since aliments.add works and at the same time, the saveAliments method also works, but updateTableView method, that is in the same method as saveAliments and aliments.add, does not work. I'm very confused.
I feel like I'm missing something basic about java programming and as such I'd like to learn what's going on. Any help will be appreciated, thank you very much!

Creating a Task with JavaFX with a 'wait()' inside

I use javafx, I have a TextField and a Button, when the button is pressed, it saves what is written in the TextField in a String. What I want to create is a method to mark a pause, while waiting for the Button to get pressed.
I have a class named pause.java, where I tried to put a obj.wait(); and a notifyAll(); in the event where the button is pressed, but the window isn't accessible during this time, I can't press the button or enter anything in the TextField.
So what I found was to put the obj.wait(); in a task, then I don't know why but it directly breaks out of the wait.
Here is my pause.java
package net.jpajavafx;
import java.util.logging.*;
import javafx.concurrent.Task;
public class pause {
Logger logger = Logger.getLogger(pause.class.getName());
MainController obj = new MainController();
public void waitinput() {
Task<Void> sleeper = new Task<Void>() {
#Override
protected Void call() throws Exception {
synchronized (obj) {
try {
String write = "Waiting for input...";
logger.log(Level.INFO, write);
obj.wait();
logger.log(Level.INFO, "Done");
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
};
new Thread(sleeper).start();
}
}
How do I have to modify it to make it wait, while still having access to the GUI?
Here's my code simplified for the problem:
AlbumManager.java, where my main is.
package net.jpajavafx;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.*;
import javafx.application.*;
import javafx.fxml.FXMLLoader;
public class AlbumManager extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Album Manager");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MainController.java:
package net.jpajavafx;
import javafx.event.ActionEvent;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.fxml.FXML;
import java.util.logging.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
public class MainController {
#FXML
private TextArea textarea;
#FXML
private TextField textfield;
Variablesstoring stock = new Variablesstoring();
public void ok(ActionEvent event) {
String getValue = textfield.getText();
stock.setEntrystr(getValue); //here i have something to put in an Int, I put it aside to reduce the length
textfield.setText("");
notifyAll();
}
public void startprogram() {
int etat = 0;
int run = 1;
while (run == 1) {
textarea.setText("1: launch method");
pause.waitinput(); // here I want to wait for an input
etat = stock.getEntrystr();
switch (etat) {
case 1:
//runs a method
break;
default:
break;
}
}
}
}
It's really not clear what you're trying to achieve here that needs a separate thread: all the separate thread seems to try to do is wait until the button is pressed, and then execute some code. That functionality is already provided by the event management system in JavaFX (and the same is true for any UI toolkit): just execute the code in the event handler.
(As an aside, your use of wait() is incorrect, and if you fix that, the thread will never wake up because you are not calling notifyAll() on the same object on which you are calling wait().)
You can achieve what you seem to be trying to do simply with
package net.jpajavafx;
import javafx.event.ActionEvent;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.fxml.FXML;
import java.util.logging.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
public class MainController {
#FXML
private TextArea textarea;
#FXML
private TextField textfield;
Variablesstoring stock = new Variablesstoring();
public void ok(ActionEvent event) {
String getValue = textfield.getText();
stock.setEntrystr(getValue); //here i have something to put in an Int, I put it aside to reduce the length
textfield.setText("");
processInput();
}
public void processInput() {
int etat = stock.getEntrystr();
switch (etat) {
case 1:
//runs a method
break;
default:
break;
}
}
}
You have to start another thread using a Runnable, so your UI thread does not get blocked while the save-operation completes.
You can do this by placing a listener on the button that will start the save-operation on a new thread when the button is clicked.
The code for adding a listener to a button that starts a new thread would look something like this:
//Creating the mouse event handler
EventHandler<MouseEvent> eventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
MainController controller = new MainController();
controller.start();
}
};
//Registering the event filter
button.addEventFilter(MouseEvent.MOUSE_CLICKED, eventHandler);
The code you posted doesn't really do anything. Your call to waitinput() only logs and calls wait(). wait() is not what you want, since this operation is intended for putting a thread on hold until it is notified, not for executing a task in a seperate thread. Remove the obj.wait(), and add a listener that calls your logging method when the button is clicked. Also, get rid of the while-loop. The EventHandler will take care of events in the background.

How to open popup window from an other class without button click in javaFX?

So I've got a method called 'popup' in a javaFX controller class which opens a small popup window on top of the actual application window. This method runs without problem if it's assigned to a button in fxml and the button is clicked, but this is not the way I want to use it.
I've got an other class called 'Timer' with a new task (new thread) which is counting down from a certain number, and at a point it will open a popup window with a message. My purpose is to call and run the 'popup' method from this 'Timer' class. When I call the 'popup' method from here, it starts executing, but the popup window doesn't appear at all. (The method call happens as I get the message "in popup" on console from 'popup' method. )
So why does it work when a button click calls 'popup' method from the fxml file and why not when I call it from an other class? Thanks.
Please see the controller class with 'popup' method and the Timer class below (using Gradle in project):
"SceneController" controller class:
package GradleFX;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
//import java.awt.event.ActionEvent;
public class SceneController implements Initializable {
public static String password = "";
protected static int timercount = 20;
#FXML
private Label PWLabel;
#FXML
private Label bottomLabel;
#FXML
private PasswordField PWField;
#FXML
private Label showPWLabel;
protected static Label myBottomLabel;
private static PasswordField myPWField;
private static Label myShowPWLabel;
private static int tries;
#Override
public void initialize(URL location, ResourceBundle resources) {
Timer timerTask = new Timer();
myBottomLabel = bottomLabel;
myPWField = PWField;
myShowPWLabel = showPWLabel;
new Thread(timerTask).start();
}
**/***********************************************************************
/*This method runs if button is pressed in main application,
but can't make it work by calling it from Timer Class */
public void popup() {
System.out.println("in popup");
Stage dialogStage = new Stage();
dialogStage.initModality(Modality.WINDOW_MODAL);
VBox vbox = new VBox(new Text("Hi"), new Button("Ok."));
vbox.setAlignment(Pos.CENTER);
vbox.setPadding(new Insets(15));
dialogStage.setScene(new Scene(vbox));
dialogStage.show();
}
//****************************************************************************
public void showPW() {
myShowPWLabel.setText(myPWField.getText());
}
public void hidePW() {
myShowPWLabel.setText("");
}
public void exit() {
System.exit(0);
}
public void write() {
PWLabel.setText("Mukodik");
}
public void writeInput(String in) {
password = in;
System.out.println("final password text text: " + password);
writeFinally();
}
public void writeFinally() {
System.out.println("This is 'password' : " + password);
//bottomLabel.setText(password);
}
public void bottomLabelWrite() {
bottomLabel.setText(myPWField.getText());
}
public static void setLabel() throws InterruptedException {
myBottomLabel.setText("");
myBottomLabel.setText("Database has been permanently erased.");
//Thread.sleep(3000);
//System.exit(0);
}
public static void noKeyEnteredNote() {
myBottomLabel.setTextFill(Color.BLACK);
myBottomLabel.setText("No key entered. Type Main Key.");
}
public static void rightKey() {
myBottomLabel.setText("Yes, this is the right key.");
}
public static void wrongKey() throws InterruptedException {
tries = MasterKey.numOfTryLeft;
if (tries > 0) {
myBottomLabel.setTextFill(Color.RED);
myBottomLabel.setText("!!!Wrong key!!! You've got " + tries + " tries left!");
}
}
public void simpleTest(String in) {
System.out.println("in simpleTest and in is: " + in);
}
public void getMainKey() throws IOException, InterruptedException {
MasterKey masterKey = new MasterKey();
System.out.println("Inside SceneController");
masterKey.requestKey(myPWField.getText());
}
public void changeScreen(ActionEvent event) throws IOException, InterruptedException {
getMainKey();
if (MasterKey.isRightKey) {
Parent tableViewParent = FXMLLoader.load(getClass().getResource("Menu.fxml"));
Scene tableViewScene = new Scene(tableViewParent);
Stage window = (Stage) ((Node) event.getSource()).getScene().getWindow();
window.setScene(tableViewScene);
window.show();
}
}
}
This is Timer class:
package GradleFX;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
public class Timer extends Task {
private ActionEvent actionEvent;
#Override
protected Integer call() throws Exception {
boolean notCalled = true;
while (SceneController.timercount > 0) {
SceneController sceneController = new SceneController();
System.out.println(SceneController.timercount);
Thread.sleep(1000);
SceneController.timercount--;
if (SceneController.timercount < 19) {
System.out.println("Less than 5");
if(notCalled) {
sceneController.popup();
notCalled = false;
}
}
}
System.exit(0);
return null;
}
}
Add this to your code:
#Override
public void initialize(URL location, ResourceBundle resources) {
Timer timerTask = new Timer();
myBottomLabel = bottomLabel;
myPWField = PWField;
myShowPWLabel = showPWLabel;
new Thread(timerTask).start();
timerTask.setOnFinished(e->{
popup();
});
}

Clock isn't starting

I wrote a little Clock in JavaFX8. On my GUI, I have 2 Buttons. One button should start the timer and the other button should pause the timer. But whenever I press start, nothing is happening. When I delete the whole if() clause, I am able to start the timer via thread.start and it's updating my GUI. I think my call if(isRunning) isn't working how I want.
I appreciate any kind of help!
My Window.java (Main Application)
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package gui;
import java.util.Observable;
import java.util.Observer;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import logic.Clock;
import logic.ClockObserver;
/**
*
* #author
*/
public class Window extends Application implements Observer {
private Button b_start = new Button("Start");
private Button b_stop = new Button("Stop");
private Label l_time = new Label("gdfgdf");
private HBox buttonbox = new HBox();
private Clock clock = new Clock();
private Thread thread = new Thread(clock);
#Override
public void start(Stage primaryStage) throws Exception {
thread.start();
buttonbox.setSpacing(5.0);
clock.addObserver(this);
buttonbox.setAlignment(Pos.CENTER);
buttonbox.getChildren().addAll(b_start, b_stop);
BorderPane bp = new BorderPane();
bp.setPadding(new Insets(10.0));
bp.setCenter(l_time);
bp.setBottom(buttonbox);
Scene scene = new Scene(bp);
primaryStage.setMinHeight(150);
primaryStage.setMinWidth(250);
primaryStage.setScene(scene);
primaryStage.setTitle("Uhr");
primaryStage.show();
b_start.setOnAction((ActionEvent e) ->{
clock.setRunning(true);
});
b_stop.setOnAction((ActionEvent e) ->{
clock.setRunning(false);
});
}
public static void main(String args[]) {
launch(args);
}
#Override
public void update(Observable o, Object o1) {
Platform.runLater(new Runnable(){
#Override
public void run() {
l_time.setText(clock.getZeit());
}
});
}
}
My Clock.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package logic;
import gui.Window;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
/**
*
* #author
*/
public class Clock extends Observable implements Runnable {
private String zeit = "";
private int sek;
private boolean isRunning = false;
public Clock() {
}
public void setZeit() {
zeit = "" + sek;
}
public String getZeit() {
return zeit;
}
public void setRunning(boolean running){
this.isRunning = running;
}
public boolean isRunning(){
return isRunning;
}
public int getSek() {
return sek;
}
#Override
public void run() {
while (true) {
if (isRunning()) {
try {
sek++;
setZeit();
System.out.println(zeit);
this.setChanged();
this.notifyObservers();
Thread.sleep(1000);
} catch (InterruptedException ex) {
//TODO
}
}
}
}
}
Thanks in advance!

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 TextFields public so they can be accessed by someThread.

Categories