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