如何在循环中更新 javafx 中的文本字段?
How do i update a textfield in javafx in loop ?
我有一个使用场景生成器的小型 javafx 应用程序,单击按钮应该定期从 COM 端口读取字符串并在文本字段中更新。
但是现在如果我使用 for 循环它只显示最后一个字符串,如果我把代码放在无限循环中则什么也不会显示(这是我的临时要求)。
任何人都可以帮助我,以便在每次从 COM 端口读取时,文本字段中的新字符串都会更新。
这是我在这两种情况下使用的代码:
注意:在控制器 class 的两种情况下,我都在控制台上获得了完美的输出。
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);
}
}
这是控制器 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());
}
}
}
}
}
这里是无限循环的方法:
//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
仅显示最后一个结果。
如果循环执行得很快,这是意料之中的。 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 在后台线程向它发送新信息时不断更新。
我有一个使用场景生成器的小型 javafx 应用程序,单击按钮应该定期从 COM 端口读取字符串并在文本字段中更新。
但是现在如果我使用 for 循环它只显示最后一个字符串,如果我把代码放在无限循环中则什么也不会显示(这是我的临时要求)。
任何人都可以帮助我,以便在每次从 COM 端口读取时,文本字段中的新字符串都会更新。
这是我在这两种情况下使用的代码:
注意:在控制器 class 的两种情况下,我都在控制台上获得了完美的输出。
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);
}
}
这是控制器 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());
}
}
}
}
}
这里是无限循环的方法:
//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
仅显示最后一个结果。
如果循环执行得很快,这是意料之中的。 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 在后台线程向它发送新信息时不断更新。