Я работаю над проектом курса для колледжа, приложением JavaFX, имитирующим гараж с движущимися транспортными средствами. Следуя этому ответу , я создал механизм для постоянного обновления графического интерфейса без переполнения потока JavaFX.
Весь код можно найти здесь .
Observer
- это поток демона, задачей которого является вычисление значения String
для вывода и отправка его в TextArea
, который постоянно обновляется.
Метод запуска наблюдателя:
@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
объект имеет ссылку на класс модели - garage
. print()
метод класса Garage
в основном добавляет вещи в буфер.
Полный вывод выводится на консоль, которая работает нормально. Выход также используется для установки outputText
, SimpleStringProperty
, к которому подключен прослушиватель в MainControllerClass
.
элемент outputText:
public class Garage implements Externalizable {
...
public SimpleStringProperty outputText = new SimpleStringProperty();
...
}
Обновление GUI запускается нажатием кнопки.
Класс MainController:
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;
}
}
Когда я запускаю приложение и нажимаю кнопку, все идет хорошо. TextArea
обновляется в режиме реального времени. Поскольку вывод постоянно добавляется к StringBuffer
, я хотел обновлять его в каждом цикле и получать что-то вроде симуляции.
Здесь начинаются проблемы.
Когда я раскомментирую строку в методе Observer run
// buffer = new StringBuffer("");
ничего не печатается на TextArea
. Консольный вывод работает хорошо.
Я также пытался с другими StringBuffer
методами, такими как delete
и setLenght
, но ничего не работает. Однако я пытаюсь очистить буфер, TextArea
больше не обновляется.
Не получается сбросить StringBuffer
.
Что мне здесь не хватает?
РЕДАКТИРОВАТЬ: print()
методы
Метод печати в гараже
public void print(StringBuffer buffer) {
synchronized (Garage.lock) {
synchronized (lock) {
for (int i = 0; i < platformCount; i++)
platforms.get(i).print(buffer);
}
}
}
Метод печати GarageItem
package garage.model;
import java.io.*;
public interface GarageItem extends Serializable {
public void print(StringBuffer buffer);
}
Метод печати на полосе
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
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('*');
}
}
}
Способ печати автомобиля
@Override
public void print(StringBuffer buffer) {
synchronized (Garage.getLock()) {
buffer.append(symbol);
}
}
, где symbol
- это V.