这个问题有很多方面没有意义。
一般来说,JavaFX 中的 GUI 旨在实现自包含和非线性执行。对外部方法进行编程以假设GUI 的某些状态,然后根据该假设直接操作 GUI,这不是正确的方法。因此,任何通过调用调用来了解GUI 状态的尝试Thread.sleep()本质上都是不正确的。
new JFXPanel()不需要调用,因为将Application.launch()初始化 JavaFX。据推测,这是在sleep(500)放入之前添加的,因为如果在命令changeImg()之后立即运行,调用将会失败,因为甚至还没有时间启动。Thread.start()launch()
如前所述,一旦屏幕完成初始化,就应该在方法中完成某种启动图像的替换FX_Min.start(Stage),尽管您甚至不太可能看到第一张图像。
这个问题似乎旨在设计一种应用程序,其中 GUI 只是它的一小部分,主应用程序将继续进行冗长的处理,然后触发 GUI 响应该处理的结果. 或者,主应用程序可能正在监视外部 API 并定期向 GUI 提供更新。然而,在大多数情况下,通常会初始化 GUI,以便它可以控制操作、启动后台线程以进行冗长的处理并使用 JavaFX 工具来处理触发 GUI 更新和获取结果。
在设计确实需要除 GUI 之外的其他东西作为中央控制的情况下,使用Application似乎不合适。毕竟,它旨在控制应用程序,并在 GUI 启动后监控 GUI 的状态,以便在 GUI 关闭时关闭所有内容。这就是为什么 OP 必须将Application.launch()调用放在一个单独的线程中 -launch()在 GUI 关闭之前不会返回。
如果 GUI 之外的应用程序要控制一切,那么最好使用 手动启动 JavaFX Platform.startup(),并手动处理所有监视。以下代码不进行任何监控,但它确实启动了 GUI 并更改了图像而没有任何问题:
public class Control_Min {
public static void main(String[] args) {
Platform.startup(() -> new Fx_Min().start(new Stage()));
Platform.runLater(() -> Fx_Min.changeImage());
}
}
请注意,不需要对Fx_Min. 但是,没有理由Fx_Min再扩展Application了,其start()方法中的代码可以放在任何地方。
应该进一步指出,尽管这可行,但它确实超出了 JavaFX 应用程序的规范。OP 的情况可能确实需要这种架构,但这会将其置于极少数应用程序中。通过提供的 JavaFX 工具围绕后台线程设计应用程序Application.launch()并在后台线程中启动冗长的处理几乎总是一种更好的方法。
好的,所以鉴于来自 OP 的新信息,很明显这应该基于Application并且 GUI 应该启动某种可能会阻止等待输入的套接字侦听器。
任何阻塞都不能在 FXAT 上运行,并且需要有一种方法允许套接字侦听器在接收到数据时与 GUI 进行通信。理想情况下,套接字侦听器应该是 JavaFX 不知道的,并且只是普通的 Java。
IMO,最好的方法是提供一个Consumer接受来自套接字侦听器的信息,并将其传递给它的构造函数中的套接字侦听器。这样,GUI 对套接字侦听器的性质一无所知,只是它依赖于需要消息使用者。类似地,套接字侦听器不知道是什么调用了它,只是它给了它一个消息消费者。
这限制了您的耦合,您可以自由地编写您的 GUI,而不必担心套接字侦听器的任何内部工作,反之亦然。
所以这里是 GUI,清理并简化了一点,以便更容易理解套接字侦听器的内容。基本上,GUI 只是将来自套接字侦听器的消息扔到Text屏幕上。消息消费者处理,Platform.runLater()以便套接字侦听器甚至不知道它:
public class Fx_Min extends Application {
@Override
public void start(Stage primaryStage) {
ImageView imageView = new ImageView(new Image("/images/ArrowUp.png"));
Text text = new Text("");
primaryStage.setScene(new Scene(new VBox(10, imageView, text), 800, 600));
primaryStage.setResizable(true);
primaryStage.show();
imageView.setImage(new Image("/images/Flag.png"));
new SocketListener(socketMessage -> Platform.runLater(() -> text.setText(socketMessage))).startListening();
}
public static void main(String[] args) {
launch(args);
}
}
这是套接字侦听器。显然,这不会在套接字上侦听,但它会围绕 a 循环sleep()以模拟 Pi 上发生的动作。这里的消息格式是String,只是为了让一切简单,但显然这是实际实现的更糟糕的选择。构建一个特殊的消息类:
public class SocketListener {
private Consumer<String> messageConsumer;
public SocketListener(Consumer<String> messageConsumer) {
this.messageConsumer = messageConsumer;
}
public void startListening() {
Thread listenerThread = new Thread(() -> listenForIRCommand());
listenerThread.setDaemon(true);
listenerThread.start();
}
private void listenForIRCommand() {
for (int x = 0; x < 100; x++) {
try {
Thread.sleep(5000);
messageConsumer.accept("Station " + x);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
应该非常清楚的是,由于调用listenForIRCommand()是从后台线程内部执行的,因此它完全摆脱了任何 JavaFX 约束。在 Java 中通常可以做的任何事情都可以从那里完成,而不必担心它对 GUI 的影响。