【问题标题】:How do i update a textfield in javafx in loop ?如何在循环中更新 javafx 中的文本字段?
【发布时间】:2018-06-24 11:57:12
【问题描述】:

我有一个使用场景构建器的小型 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());
                }
            }
        }
    }
}

这里是无限循环的方法:

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

【问题讨论】:

  • 应用程序的运行速度有多快?如果它执行得很快,你可能永远不会看到更新的TextField,直到最后一个循环......
  • 如果我没听错的话,情况并非如此,因为,是的,应用程序会立即运行,但我已将 COM 端口编程为以 1.5 秒的间隔发送数据,并将超时设置为读取为 3 秒。所以我认为我不会错过文本字段中的任何更新。我还做了 sysout 字符串,它以 1.5 秒的定期间隔在 Eclipse 控制台上打印。
  • 在下面查看我的答案;在循环完成之前,循环可能仍在阻止对 JavaFX 应用程序线程的更新,因此只显示最后一个结果。
  • 是的,循环阻塞了对应用程序线程的更新。所以我只能看到for 循环的最后一个值。在while 循环中,它甚至没有显示最后一个,因为它是无限的,所以最后一个永远不会出现。我会尝试解决方案并通知您

标签: javafx scenebuilder


【解决方案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 在后台线程向其发送新信息时不断更新。

【讨论】:

  • 当我点击窗口的关闭按钮(右上角的 X 按钮)时,你能告诉我一些方法来停止这个线程吗?
  • 您可以更改 while(true) 来检查不同的条件,而不是 true。然后只需确保程序终止时条件不再为真。
猜你喜欢
  • 2018-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多