Как я могу обновить текстовое поле в javafx в цикле? - PullRequest
0 голосов
/ 24 июня 2018

У меня есть небольшое приложение 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 голосов
/ 24 июня 2018

Здесь происходит пара вещей. В первом примере вы утверждаете, что вывод на консоль правильный, но TextField показывает только последний результат.

Это ожидается, если цикл выполняется быстро. TextField обновляется , но это происходит так быстро, что вы не можете видеть его до тех пор, пока цикл не закончится, а последний результат все еще отображается. Даже если в цикл встроена задержка, это может помешать обновлению пользовательского интерфейса до завершения цикла.

С вашим бесконечным циклом проблема заключается в том, что цикл запускается в потоке приложений JavaFX (JFXAT). Это блокирует любые обновления GUI до тех пор, пока цикл не закончится, чего никогда не было.

Вам нужно будет переместить бесконечный цикл в новый фоновый поток. Оттуда вы можете обновить графический интерфейс, используя метод Platform.runLater().

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

Это позволяет вашему пользовательскому интерфейсу постоянно обновляться, когда фоновый поток отправляет ему новую информацию.

...