0

First let me thank you for any guidance you might be able to provide on this. I have been racking my brains to get this to work, and have been looking at many threads here, with no luck. I am new to Java and JavaFX, but have a C# background, primarily on MSFT visual Studio. I am currently using IntelliJ as my IDE platform.

What I am trying to do is (I thought) simple enough: I am reading and successfully parsing data coming in from an Arduino controller, which is reading a sensor, that provides readings for a power meter. I have my data in a comma delimited form, and with a buffered reader and serial port event, I am able to parse a line, string.split it, and then place in into an array (after transforming to Double). This part works well, and as you can see from the code, I am also printing this to the console with no issues:

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();
    }
}

Now the HARD part: Has me completely frustrated!!

I am trying to now drive a gauge from the jfxtras gauges. I have all the proper libraries imported, and I create a very simple GUI in scenebuilder. Here is the XML file created:

<?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>

and this is the Controller: (nothing in it at the moment, since I do not want to have any buttons or anything like that...just display of data:

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 {

 }

I have tried different combinations, but the guage refuses to show the data read from the serialPort. I think this might have to do with the GUI being on a different thread from main (have been searching and reading) but for the life of me I cant figure out how I might change my code to make this seemingly simple task work. All I want is for the gauge to display the data....I know I might be doing something completely stupid.....but cant figure this out.

Any ides as to how I might be able to achieve this?

PS: If I create an event handler in controller, with say a button, I am able to make the gauge move with an arbitrary value upon button press. Why cant I do the same when the serial event fires????

HELP PLEASE!!!!

CYBORGCNC
  • 45
  • 2
  • 7
  • The library you are using in not JFXtras but Enzo. Gerrit's old gauge library was part of JFXtras 2.x, but he decided to move the gauges to a library of his own; Enzo. That said, setting the value like you do should work. You can try to wrap it in Platform.runLater( () -> fwdpower.setValue(5) ); to make sure it runs on the graphical thread. Also try and divide by 5.0 instead of 5 (I'm always uncertain how doubles and int behavior when mixed). – tbeernot Apr 09 '16 at 16:58
  • Thank you tbeernot...Yeah, thanks for pointing out the Library difference, however, the Gauges and library on Enzo's build seem to be working just fine. I have been trying combinations of Platform.runLater, after doing some digging, however when I add it to the serial event I get this: "Overrides method in java.lang.Runnable....and executing produces a java.lang.NullPointerException....any ideas? – CYBORGCNC Apr 09 '16 at 17:17
  • That is not enough info – tbeernot Apr 11 '16 at 09:13

1 Answers1

0

@FXML-annotated fields are only initialized in the controller created by the FXMLLoader; you can't simply annotate a field in an arbitrary object and expect it to be initialized by the loader.

Create the annotated field in the controller and define a method to set it:

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);
    }
}

Then just get a reference to the controller and invoke the method on it. Note that since your serialEvent method is invoked from a background thread, you should wrap the call to the controller in 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();
        }
    }

}
James_D
  • 201,275
  • 16
  • 291
  • 322