Я использую JavaFX с Gluon Mobile.Очень хорошая основа для создания мобильных приложений.Но у меня есть линейная диаграмма JavaFX, которая зависает после ошибки.
Exception in thread "JavaFX Application Thread"
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1042)
at javafx.scene.chart.LineChart.layoutPlotChildren(LineChart.java:468)
at javafx.scene.chart.XYChart.layoutChartChildren(XYChart.java:731)
at javafx.scene.chart.Chart$1.layoutChildren(Chart.java:94)
at javafx.scene.Parent.layout(Parent.java:1087)
at javafx.scene.Parent.layout(Parent.java:1093)
at javafx.scene.Parent.layout(Parent.java:1093)
at javafx.scene.Parent.layout(Parent.java:1093)
at javafx.scene.Scene.doLayoutPass(Scene.java:552)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:398)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:498)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:491)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:319)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$5(GtkApplication.java:139)
at java.lang.Thread.run(Thread.java:748)
Линейная диаграмма выглядит следующим образом.
введите описание изображения здесь
Но через некоторое время я вижу, как точки медленно исчезают, а затем ничего не появляется.Это похоже на то, что линейный график Java FX перестал обновляться.Я разместил некоторые комментарии, где это ломается и что действительно происходит.
введите описание изображения здесь
Я использую линейный график для регистрации в реальном времени.Вот код Java.
/*
* Get the time format in HH:mm:ss
*/
LocalDateTime now = LocalDateTime.now();
String time = dtf.format(now);
if (countMeasurements < MEASUREMENTS) {
time_output.getData().add(new XYChart.Data<String, Number>(time, output));
time_input.getData().add(new XYChart.Data<String, Number>(time, input));
countMeasurements++;
} else {
/*
* Now insert
*/
time_output.getData().add(new XYChart.Data<String, Number>(time, output)); // <-- No update after a while
time_input.getData().add(new XYChart.Data<String, Number>(time, input)); // <-- No update after a while
/*
* Delete the first object
*/
time_output.getData().remove(0); // <--- This works
time_input.getData().remove(0); // <-- This works
}
Редактировать:
Вот как это выглядит, когда я получил ошибку.Точки удаляют все больше и больше.Вы видите, что линия исчезла?
введите описание изображения здесь
Весь код
package com.gluonapplication.thread;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.gluonhq.charm.glisten.mvc.View;
import de.re.easymodbus.modbusclient.ModbusClient;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
public class ModbusConnection extends Thread{
/*
* Static
*/
private static boolean running;
private static boolean start;
/*
* Fields from Scene Builder
*/
private TextField statusTextField;
private TextField ipAddressTextField;
private ComboBox<String> startSignalComboBox;
private TextField predictHorizonTextField;
private TextField controlHorizonTextField;
private TextField sampleTimeTextField;
private TextField referencePointTextField;
private TextField portTextField;
private TextField slopeTextField;
private TextField offsetTextField;
private LineChart<String, Number> lineChart_primary;
private Series<String, Number> time_output;
private LineChart<String, Number> lineChart_third;
private Series<String, Number> time_input;
/*
* Modbus
*/
private ModbusClient modbusClient;
private int MEASUREMENTS = 20;
DateTimeFormatter dtf;
int[] writeRegisters = new int[11];
private int countMeasurements;
@SuppressWarnings("unchecked")
public ModbusConnection(View primaryView, View secondaryView, View thirdView) {
/*
* We start this thread as default
*/
start = true;
/*
* Initial modbus start
*/
writeRegisters[6] = 0;
/*
* For secondaryView
*/
statusTextField = (TextField) secondaryView.lookup("#statusTextField");
ipAddressTextField = (TextField) secondaryView.lookup("#ipAddressTextField");
startSignalComboBox = (ComboBox<String>) secondaryView.lookup("#startSignalComboBox");
predictHorizonTextField = (TextField) secondaryView.lookup("#predictHorizonTextField");
controlHorizonTextField = (TextField) secondaryView.lookup("#controlHorizonTextField");
sampleTimeTextField = (TextField) secondaryView.lookup("#sampleTimeTextField");
referencePointTextField = (TextField) secondaryView.lookup("#referencePointTextField");
portTextField = (TextField) secondaryView.lookup("#portTextField");
slopeTextField = (TextField) secondaryView.lookup("#slopeTextField");
offsetTextField = (TextField) secondaryView.lookup("#offsetTextField");
/*
* For primaryView
*/
lineChart_primary = (LineChart<String, Number>) primaryView.lookup("#lineChart");
/*
* Declare the data object inside the chart
*/
time_output = new Series<String, Number>();
time_output.setName("Output");
lineChart_primary.getData().add(time_output);
/*
* For thirdView
*/
lineChart_third = (LineChart<String, Number>) thirdView.lookup("#lineChart");
/*
* Declare the data object inside the chart
*/
time_input = new Series<String, Number>();
time_input.setName("Input");
lineChart_third.getData().add(time_input);
/*
* This will prevent so we don't get NullPointerException
*/
modbusClient = null;
/*
* For time
*/
dtf = DateTimeFormatter.ofPattern("HH:mm:ss");
/*
* Reset
*/
countMeasurements = 0;
}
@Override
public void run() {
while (start) {
while (running == true || writeRegisters[6] == 1) {
/*
* Connect to Modbus server
*/
if(modbusClient == null) {
modbusClient = new ModbusClient(ipAddressTextField.getText(),Integer.parseInt(portTextField.getText()));
try {
modbusClient.Connect();
} catch (Exception e) {
statusTextField.setText("Cannot connect");
}
}else if(modbusClient.isConnected() == false){
modbusClient = new ModbusClient(ipAddressTextField.getText(),Integer.parseInt(portTextField.getText()));
try {
modbusClient.Connect();
} catch (Exception e) {
statusTextField.setText("Cannot connect");
}
}
/*
* Write registers at address 0
*/
try {
/*
* What start signal should we use.
*/
int mode = startSignalComboBox.getSelectionModel().getSelectedIndex();
switch (mode) {
case 0:
writeRegisters[0] = 255; // PWM 100%
break;
case 1:
writeRegisters[0] = 230; // PWM 90%
break;
case 2:
writeRegisters[0] = 204; // PWM 80%
break;
case 3:
writeRegisters[0] = 179; // PWM 70%
break;
case 4:
writeRegisters[0] = 153; // PWM 60%
break;
case 5:
writeRegisters[0] = 128; // PWM 50%
break;
case 6:
writeRegisters[0] = 102; // PWM 40%
break;
case 7:
writeRegisters[0] = 77; // PWM 30%
break;
case 8:
writeRegisters[0] = 51; // PWM 20%
break;
case 9:
writeRegisters[0] = 26; // PWM 10%
break;
default:
writeRegisters[0] = 255; // PWM 100%
break;
}
/*
* Get the prediction horizon as int
*/
writeRegisters[1] = Integer.parseInt(predictHorizonTextField.getText());
/*
* Get the control horizon as int
*/
writeRegisters[2] = Integer.parseInt(controlHorizonTextField.getText());
/*
* Get the sample time in as int
*/
writeRegisters[3] = Integer.parseInt(sampleTimeTextField.getText());
/*
* Get the reference point in two ints
*/
writeRegisters[4] = (int) Float.parseFloat(referencePointTextField.getText());
writeRegisters[5] = (int) ((Float.parseFloat(referencePointTextField.getText()) - ((float) writeRegisters[4])) * 10000);
/*
* Get if the system is running
*/
writeRegisters[6] = running ? 1 : 0;
/*
* Get the slope
*/
writeRegisters[7] = (int) Float.parseFloat(slopeTextField.getText());
writeRegisters[8] = (int) ((Float.parseFloat(slopeTextField.getText()) - ((float) writeRegisters[7])) * 10000);
/*
* Get the offset
*/
writeRegisters[9] = (int) Float.parseFloat(offsetTextField.getText());
writeRegisters[10] = (int) ((Float.parseFloat(offsetTextField.getText()) - ((float) writeRegisters[9])) * 10000);
/*
* Write 11 elements from address 0
*/
modbusClient.WriteMultipleRegisters(0, writeRegisters);
} catch (Exception e) {
statusTextField.setText("Cannot write");
}
/*
* Read 3 registers at the beginning from address 12
*/
try {
int[] registersRead = modbusClient.ReadHoldingRegisters(12, 3); // two first are output (float) and the last is the input (int)
/*
* Get the output value
*/
System.out.println("registersRead[0] = " + registersRead[0] + " registersRead[1] = " + registersRead[1] );
double output = ((double) registersRead[0]) + ((double) registersRead[1]) / 10000.0;
System.out.println("Output : " + output);
/*
* Get the input value
*/
int input = registersRead[2];
/*
* Get the time format in HH:mm:ss
*/
LocalDateTime now = LocalDateTime.now();
String time = dtf.format(now);
System.out.println("Time : " + time);
if (countMeasurements < MEASUREMENTS) {
time_output.getData().add(new XYChart.Data<String, Number>(time, output));
time_input.getData().add(new XYChart.Data<String, Number>(time, input));
countMeasurements++;
} else {
/*
* Now insert
*/
System.out.println("Add time_output");
time_output.getData().add(new XYChart.Data<String, Number>(time, output));
System.out.println("Add time_input");
time_input.getData().add(new XYChart.Data<String, Number>(time, input));
/*
* Delete the first object
*/
System.out.println("Delete");
time_output.getData().remove(0);
time_input.getData().remove(0);
}
} catch (Exception e) {
statusTextField.setText("Cannot read");
}
try {
Thread.sleep((long) (1000 * Double.parseDouble(sampleTimeTextField.getText())));
} catch (Exception e) {
statusTextField.setText("Cannot delay");
}
statusTextField.setText("Running");
}
/*
* This is because we don't want update so fast
*/
try {
Thread.sleep(100);
} catch (InterruptedException e) {
statusTextField.setText("Cannot delay");
}
/*
* Disconnect if we have been using modbusClient object before
*/
if(modbusClient != null) {
try {
if(modbusClient.isConnected()) {
modbusClient.Disconnect();
statusTextField.setText("Stopped");
}
} catch (Exception e) {
statusTextField.setText("Cannot disconnect");
}
}
}
}
public static boolean isRunning() {
return running;
}
public static void setRunning(boolean running) {
ModbusConnection.running = running;
}
public static boolean isStart() {
return start;
}
public static void setStart(boolean start) {
ModbusConnection.start = start;
}
}
Редактировать 2: введите описание изображения здесь