Amol.Shaligram
Amol.Shaligram

Reputation: 793

How do i update a textfield in javafx in loop ?

I have a small javafx application using scene builder which on a button click should read a string from COM port at regular intervals and update in a text field.

But now it only shows the last string if I use a for loop, and nothing if i put the code in infinite loop (That's my temporary requirement).

Can anyone help me so that at each read from COM port the new string is updated in the text field.

enter image description here

Here is the code I used for both the cases :

Note : In both cases in controller class, I'm getting perfect output on console.

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

Here is the Controller class :

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

Here is the method with infinite loop :

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

Upvotes: 0

Views: 2391

Answers (1)

Zephyr
Zephyr

Reputation: 10253

There are a couple things happening here. In your first example, you state that the console output is correct but the TextField only shows the last result.

This is expected if the loop executes quickly. The TextField is being updated, but it happens so quickly that you can't see it until the loop ends and the last result is still being displayed. Even if you have a delay built into the loop, this could still block the UI from being updated until the loop is completed.

With your infinite loop, the issue is that the loop is being run on the JavaFX Application Thread (JFXAT). This blocks any updates to the GUI until the loop is finished, which is never is.

You will need to move the infinite loop to a new background thread. From there, you can update the GUI using the Platform.runLater() method.

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

This allows your UI to continually update as the background thread sends it new information.

Upvotes: 2

Related Questions