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

时间:2018-06-24 11:57:12

标签: javafx scenebuilder

我有一个使用场景生成器的小型Javafx应用程序,单击该按钮后,应定期从COM端口读取一个字符串并在文本字段中进行更新。

但是现在,如果我使用for循环,它仅显示最后一个字符串,如果将代码置于无限循环中,则仅显示最后一个字符串(这是我的临时要求)。

任何人都可以帮助我,以便每次从COM端口读取时,都会在文本字段中更新新字符串。

enter image description here

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

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

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

这是Controller类:

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

这里是无限循环的方法:

//this shows nothing in the text field
    @FXML
    public void printHello(ActionEvent event)
    {   
        if(event.getSource() == sayHelloButton)
        {
            SerialPort serialPort = new SerialPort("COM22");
            while(true)
            {
                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());
                }
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

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

如果循环快速执行,这是预期的。 TextField 正在被更新,但是它是如此之快,以至于在循环结束并且仍显示最后的结果之前,您无法看到它。即使您在循环中内置了延迟,这仍然可能阻止UI更新,直到循环完成。

在您的无限循环中,问题在于该循环正在 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();

这允许您的UI在后台线程向其发送新信息时不断更新。