JavaFX передает данные в датчик jfxtras из Arduino
Прежде всего позвольте мне поблагодарить вас за любые рекомендации, которые вы могли бы дать по этому вопросу. Я ломал голову над тем, чтобы заставить это работать, и смотрел на многие темы здесь, без удачи. Я новичок в Java и JavaFX, но у меня есть опыт работы с C#, прежде всего в MSFT visual Studio. В настоящее время я использую IntelliJ в качестве своей платформы IDE.
То, что я пытаюсь сделать, это (я думал) достаточно просто: я читаю и успешно анализирую данные, поступающие с контроллера Arduino, который читает датчик, который обеспечивает показания для измерителя мощности. У меня есть данные в форме запятой, и с буферизованным считывателем и событием последовательного порта, я могу проанализировать строку, разбить ее на string.split, а затем поместить в массив (после преобразования в Double). Эта часть работает хорошо, и, как вы можете видеть из кода, я также печатаю это на консоль без проблем:
package sample;
import eu.hansolo.enzo.gauge.RectangularGauge;
import gnu.io.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.fxml.FXML;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.*;
public class Main extends Application implements SerialPortEventListener {
SerialPort serialPort = null;
private BufferedReader serialIn;
private OutputStream serialOut;
public Double power;
@FXML
private RectangularGauge fwdpower;
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Power Meter");
primaryStage.setScene(new Scene(root, 380, 320));
primaryStage.show();
//
CommPortIdentifier port = CommPortIdentifier.getPortIdentifier("COM60");
CommPort commPort = port.open(this.getClass().getName(), 2000);
serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
serialIn = new BufferedReader(new InputStreamReader((serialPort.getInputStream())));
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
//
}
public static void main(String[] args) {
launch(args);
}
@Override
public void serialEvent(SerialPortEvent e) {
try {
String line = serialIn.readLine();
String[] Values = line.split(",");
power = Double.parseDouble(Values[1]);
System.out.println(power / 5);
} //This works as expected and shows values on console
fwdpower.setValue(power/5); //Shows NOTHING! UGHHHH!
catch (IOException ex) {ex.printStackTrace();
}
}
Теперь трудная часть: я полностью расстроен!!
Я пытаюсь теперь управлять датчиком от датчиков jfxtras. У меня импортированы все нужные библиотеки, и я создаю очень простой графический интерфейс в scenebuilder. Вот созданный файл XML:
<?xml version="1.0" encoding="UTF-8"?>
<?import eu.hansolo.enzo.gauge.RectangularGauge?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:controller="sample.Controller">
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
<children>
<Pane prefHeight="342.0" prefWidth="377.0">
<children>
<RectangularGauge fx:id="fwdpower" layoutX="25.0" layoutY="22.0" minValue="1.0" />
</children>
</Pane>
</children>
</GridPane>
и это Контроллер: (в данный момент в нем ничего нет, так как я не хочу иметь никаких кнопок или чего-то в этом роде... просто отображение данных:
package sample;
import eu.hansolo.enzo.gauge.RectangularGauge;
import gnu.io.SerialPortEvent;
import javafx.fxml.FXML;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Controller {
}
Я пробовал разные комбинации, но гаджет отказывается показывать данные, прочитанные из serialPort. Я думаю, что это может быть связано с тем, что GUI находится в потоке, отличном от основного (находился в поиске и чтении), но я не могу понять, как изменить свой код, чтобы сделать эту, казалось бы, простую задачу работающей. Все, что я хочу, это чтобы датчик отображал данные.... Я знаю, что могу делать что-то совершенно глупое... но не могу понять это.
Любые идеи о том, как я мог бы достичь этого?
PS: если я создаю обработчик событий в контроллере, скажем, с помощью кнопки, я могу заставить датчик двигаться с произвольным значением при нажатии кнопки. Почему я не могу сделать то же самое, когда запускается серийное событие????
ПОМОГИТЕ, ПОЖАЛУЙСТА!!!!
1 ответ
@FXML
-аннотированные поля инициализируются только в контроллере, созданном FXMLLoader
; Вы не можете просто аннотировать поле в произвольном объекте и ожидать, что оно будет инициализировано загрузчиком.
Создайте аннотированное поле в контроллере и определите метод для его установки:
package sample;
import eu.hansolo.enzo.gauge.RectangularGauge;
import gnu.io.SerialPortEvent;
import javafx.fxml.FXML;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Controller {
@FXML
private RectangularGauge fwdpower ;
public void setFwdPower(double power) {
fwdpower.setValue(power);
}
}
Затем просто получите ссылку на контроллер и вызовите метод для него. Обратите внимание, что так как ваш serialEvent
метод вызывается из фонового потока, вы должны заключить вызов в контроллер Platform.runLater(...)
:
package sample;
import eu.hansolo.enzo.gauge.RectangularGauge;
import gnu.io.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.fxml.FXML;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.*;
public class Main extends Application implements SerialPortEventListener {
SerialPort serialPort = null;
private BufferedReader serialIn;
private OutputStream serialOut;
private Controller controller ;
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
controller = loader.getController();
primaryStage.setTitle("Power Meter");
primaryStage.setScene(new Scene(root, 380, 320));
primaryStage.show();
//
CommPortIdentifier port = CommPortIdentifier.getPortIdentifier("COM60");
CommPort commPort = port.open(this.getClass().getName(), 2000);
serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
serialIn = new BufferedReader(new InputStreamReader((serialPort.getInputStream())));
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
//
}
public static void main(String[] args) {
launch(args);
}
@Override
public void serialEvent(SerialPortEvent e) {
try {
String line = serialIn.readLine();
String[] values = line.split(",");
final double power = Double.parseDouble(values[1]);
System.out.println(power / 5);
Platform.runLater(() -> controller.setFwdpower(power/5));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}