I am working on a college course project, a JavaFX application that is simulating a garage with vehicles moving around. Following on this answer, I created a mechanism for constantnly refreshing GUI without flooding the JavaFX thread.
The entire code can be found here.
Observer
is a daemon thread whose task is computing a String
value for output and sending it it to a TextArea
, which is constantly being updated.
Observer run method:
@Override
public void run() {
while (true) {
synchronized (Garage.getLock()) {
try {
// buffer = new StringBuffer("");
buffer.append('\n');
garage.print(buffer);
buffer.append('\n');
garage.outputText.set(buffer.toString());
System.out.println(buffer.toString());
Garage.getLock().wait(3000);
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
Garage.getLock().notifyAll();
}
}
}
}
Observer
object has a reference to the model class - garage
. print()
method of the Garage
class basically appends stuff to the buffer.
The complete output is printed to the console, which works fine. The output is also used to set outputText
, a SimpleStringProperty
, which has a listener attached in the MainControllerClass
.
outputText member:
public class Garage implements Externalizable {
...
public SimpleStringProperty outputText = new SimpleStringProperty();
...
}
Refreshing the GUI is initiated with a button click.
MainController class:
package garage.controller;
import java.util.concurrent.atomic.AtomicInteger;
import garage.model.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
public class MainController {
@FXML
private TextArea output;
@FXML
private Button startButton;
private Garage model;
public MainController() {
}
private AtomicInteger control = new AtomicInteger(-1);
@FXML
public void initialize() {
}
@FXML
private void handleStartButton() {
model.outputText.addListener(new ChangeListener<String>() {
@Override
public void changed(final ObservableValue<? extends String> observable, final String oldValue,
final String newValue) {
if (control.getAndSet(1) == -1) {
javafx.application.Platform.runLater(new Runnable() {
@Override
public void run() {
control.set(-1);
output.setText(newValue);
}
});
}
}
});
}
public void setModel(Garage model) {
this.model = model;
}
}
When I run the application and click the button, everything is going well. TextArea
is updated in real time. Since the output is constantly being appended to the StringBuffer
, I wanted to refresh it in every cycle and get something like a simulation.
This is where the problems start.
When I uncomment the line in the Observer run
method
// buffer = new StringBuffer("");
nothing is being printed to the TextArea
. The console output is working well.
I also tried with other StringBuffer
methods like delete
and setLenght
but nothing seems to work. However I try to clean the buffer, TextArea
is no longer updated.
I cannot seem to reset the StringBuffer
.
What am I missing here?
EDIT: print()
methods
Garage print method
public void print(StringBuffer buffer) {
synchronized (Garage.lock) {
synchronized (lock) {
for (int i = 0; i < platformCount; i++)
platforms.get(i).print(buffer);
}
}
}
GarageItem print method
package garage.model;
import java.io.*;
public interface GarageItem extends Serializable {
public void print(StringBuffer buffer);
}
Lane print method
package garage.model;
public class Lane implements GarageItem {
private static final long serialVersionUID = 5L;
@Override
public void print(StringBuffer buffer) {
synchronized (Garage.getLock()) {
buffer.append('.');
}
}
}
ParkingSpot print method
package garage.model;
public class ParkingSpot implements GarageItem {
private static final long serialVersionUID = 4L;
@Override
public void print(StringBuffer buffer) {
synchronized (Garage.getLock()) {
buffer.append('*');
}
}
}
Vehicle print method
@Override
public void print(StringBuffer buffer) {
synchronized (Garage.getLock()) {
buffer.append(symbol);
}
}
where symbol
is 'V'.