如何在javafx in循环中更新文本字段?

如何在javafx in循环中更新文本字段?,javafx,scenebuilder,Javafx,Scenebuilder,我有一个使用scene builder的小型javafx应用程序,单击按钮可以定期从COM端口读取字符串,并在文本字段中更新 但是现在,如果我使用for循环,它只显示最后一个字符串,如果我将代码放入无限循环,它什么也不显示(这是我的临时要求) 有人能帮我吗?每次从COM端口读取时,文本字段中的新字符串都会更新 以下是我在这两种情况下使用的代码: 注意:在控制器类的这两种情况下,我都在控制台上获得了完美的输出 public class Main extends Application {

我有一个使用scene builder的小型javafx应用程序,单击按钮可以定期从COM端口读取字符串,并在文本字段中更新

但是现在,如果我使用for循环,它只显示最后一个字符串,如果我将代码放入无限循环,它什么也不显示(这是我的临时要求)

有人能帮我吗?每次从COM端口读取时,文本字段中的新字符串都会更新

以下是我在这两种情况下使用的代码:

注意:在控制器类的这两种情况下,我都在控制台上获得了完美的输出

public class Main extends Application 
{
    @Override
    public void start(Stage primaryStage) 
    {
        try 
        {
            Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
            Scene scene = new Scene(root);
            //scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setTitle("test");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) 
    {
        launch(args);
    }
}
以下是控制器类:

// In this case it shows only the last string in the text field.
public class Controller implements Initializable 
{   
    @FXML
    private Button sayHelloButton;
    @FXML
    private TextField helloField;
    @Override

    public void initialize(URL arg0, ResourceBundle arg1) 
    {
    }

    @FXML
    public void printHello(ActionEvent event)
    {   
        if(event.getSource() == sayHelloButton)
        {
            SerialPort serialPort = new SerialPort("COM22");
            for(int i=0;i<5;i++)
            {
                try
                {
                    if(!serialPort.isOpened())
                    {
                        serialPort.openPort();
                        serialPort.setParams(9600, 8, 1, 0);
                    }
                    String str = serialPort.readString(10,3000);
                    System.out.println(str);
                    helloField.clear();
                    helloField.setText(str);
                }
                catch(Exception e)
                {
                    helloField.setText(e.toString());
                }
            }
        }
    }
}

这里发生了几件事。在第一个示例中,您声明控制台输出是正确的,但
TextField
仅显示最后的结果

如果循环执行得很快,这是意料之中的。
TextField
正在更新,但更新速度太快,直到循环结束,最后一个结果仍在显示时,您才能看到它。即使在循环中内置了延迟,在循环完成之前,这仍然会阻止用户界面的更新

使用无限循环,问题是循环正在JavaFX应用程序线程(JFXAT)上运行。这将阻止对GUI的任何更新,直到循环完成,这永远不会发生

您需要将无限循环移动到新的背景线程。从那里,您可以使用
Platform.runLater()
方法更新GUI

    SerialPort serialPort = new SerialPort("COM22");
    new Thread(() -> {
        while(true)
        {
            try
            {
                if(!serialPort.isOpened())
                {
                    serialPort.openPort();
                    serialPort.setParams(9600, 8, 1, 0);
                }
                String str = serialPort.readString(10,3000);
                System.out.println(str);
                // Update the UI on the JavaFX Application Thread
                Platform.runLater(() -> {
                    helloField.clear();
                    helloField.setText(str);
                });
            }
            catch(Exception e)
            {
                Platform.runLater(() -> helloField.setText(e.toString()));
            }
        }
    }).start();

这允许用户界面在后台线程向其发送新信息时不断更新。

应用程序运行的速度有多快?如果它执行得很快,在最后一个循环之前,您可能永远看不到更新的
TextField
。如果我给您提供了正确的答案,情况并非如此,因为,是的,应用程序会立即运行,但我已将COM端口编程为以1.5秒的间隔发送数据,并将超时设置为3秒。所以我不认为我会错过文本字段中的任何更新。我还做了sysout-of-string,它以1.5秒的间隔定期在eclipse控制台上打印;在循环完成之前,循环可能仍在阻止对JavaFX应用程序线程的更新,因此只显示最后的结果。是的,循环正在阻止对应用程序线程的更新。所以我只能看到循环的
的最后一个值。在
循环中,
循环没有显示最后一个,因为它是无限的,所以最后一个永远不会出现。我将尝试解决方案,并让您知道当我按下窗口的关闭按钮(右上角的X按钮)时,您可以告诉我一些停止此线程的方法吗?您可以更改
while(true)
以检查不同的条件,而不是
true
。然后确保程序终止时该条件不再为真。
    SerialPort serialPort = new SerialPort("COM22");
    new Thread(() -> {
        while(true)
        {
            try
            {
                if(!serialPort.isOpened())
                {
                    serialPort.openPort();
                    serialPort.setParams(9600, 8, 1, 0);
                }
                String str = serialPort.readString(10,3000);
                System.out.println(str);
                // Update the UI on the JavaFX Application Thread
                Platform.runLater(() -> {
                    helloField.clear();
                    helloField.setText(str);
                });
            }
            catch(Exception e)
            {
                Platform.runLater(() -> helloField.setText(e.toString()));
            }
        }
    }).start();