从另一个实现 SerialPortEventListener(Java FX、FXML)的 class 更新 GUI

Updating GUI from another class which implements SerialPortEventListener (Java FX, FXML)

我正在制作一个使用串行通信的应用程序。在那个 class 的 SerialEvent 方法中,我正在等待来自 COM 端口的输入,然后我想将它传递给 .fxml 屏幕的控制器 class。
输入将始终为 8 个字节,并且它在该线程内正常工作(我读取输入并将其打印到输出,我看到 String 是正确的)。但是,当我尝试将它 "in real time" 传递给控制器​​ class 时,我遇到了问题。

如果我直接传递它,它确实会收到它,但我以后不能调用任何东西(不是在 FX 应用程序线程异常上),我知道我不能那样做,我需要使用Platform.runLater 或 similair 解决方案,但如果我那样使用它,我的控制器 class 永远不会收到该输入,我尝试更新的 textField 保持空白。

我将部分代码复制到这里,希望有人告诉我我做错了什么。

另一个CLASS

的串行事件方法
@Override
public void serialEvent(SerialPortEvent spe) {

    if (spe.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
        try {
            byte singleData = (byte) input.read();

            logText = new String(new byte[]{singleData});
            bytes.add(logText);
            if(bytes.size() == 8) {

                for (int i = 0; i < bytes.size(); i++) {
                    inputText += bytes.get(i);
                }

                if(inputText.length() == 8) {

                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            controller.getInputString(inputText);
                        }
                    });
                }                           

                bytes.clear();
                inputText = "";
            }
        } catch (Exception e) {
            logText = "Failed to read data. (" + e.toString() + ")";
            controller.getInputString(logText);
        }
    }
}

控制器的输入方法CLASS

@Override
public void getInputString(String input) {

    firstSerialNumberField.setText(input);
}

以这种方式使用时,我的 firstSerialNumberField 永远不会得到该输入。

---编辑---

SERIALPORTLISTENER的SETCONTROLLER方法CLASS

    public void setController(SerialController controller) {

        this.controller = controller;
}

在屏幕处理程序中初始化屏幕CLASS

    serialCommunication = new SerialCommunication(this);

loader = new FXMLLoader();
loader.setLocation(getClass().getResource(path));
pane = loader.load(getClass().getResource(path).openStream());
serialController = (SerialController) loader.getController();
serialController.setScreenHandler(this);
serialController.setSerialCommunication(serialCommunication); 
serialCommunication.setController(serialController);
parent = loader.getRoot();
stage = new Stage();
stage.setScene(new Scene(parent));
stage.setTitle(title);
stage.setResizable(false);
stage.sizeToScene();
stage.centerOnScreen();
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();

您正在将对 inputText 的引用传递给控制器​​中的(命名不当的)getInputText() 方法。 inputText 大概是 class 中实现端口侦听器的一个字段。然而,一旦你传递它,你就将它设置回一个空字符串:

        if(inputText.length() == 8) {

            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    controller.getInputString(inputText);
                }
            });
        }                           

        bytes.clear();
        inputText = "";

由于 inputText 是从多个线程访问的,因此无法保证事情发生的顺序:controller.getInputText(inputText) 是否先执行,或者 inputText = ""; 是否先执行.因此,您最终可能会将文本字段设置为空字符串。

我认为你打算做的是:

        if(inputText.length() == 8) {

            final String numberFieldText = inputText ;

            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    controller.getInputString(numberFieldText);
                }
            });
        }   

或更简洁:

        if(inputText.length() == 8) {

            final String numberFieldText = inputText ;

            Platform.runLater(() -> controller.getInputString(numberFieldText));
        }