pow*_*put 1 java javafx wait onactivityresult startactivityforresult
在我的Java程序中,我给用户一些选项,其中之一调用JavaFXProgram来显示某些内容。当被调用的JavaFX实际退出时,我只想在Java程序中运行更多代码,可能需要5秒钟,也可能需要1分钟。理想情况下,我想要的是类似于Android的设备。我们先致电startActivityForResult(),然后等待的致电onActivityResult()。我如何在自己的情况下达到类似的行为?
我写了这段代码来尝试复制遇到的问题。这是类似的想法,但是以某种方式将其称为JavaFX,开始循环并毫无问题地从用户检索输入。在我的其他程序中,我总是得到Exception in thread "main" java.util.InputMismatchException何时再次返回以扫描输入。但是正如我所说,理想情况下,我只想在JavaFX Application关闭后运行更多代码。
package JavaCallsJavaFXandWaits;
import java.util.Scanner;
import javafx.application.Application;
public class MyJavaProgram {
public static void main(String[] args) {
int input;
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("0 - exit");
System.out.println("1 - display something to me");
input = scanner.nextInt();
switch (input) {
case 0:
break;
case 1:
Application.launch(JavaCallsJavaFXandWaits.MyJavaFXProgram.class, null);
// how to get notified of MyJavaFXProgram exit? I only want to run code after it exits
break;
}
if (input == 0) break;
}
}
}
package JavaCallsJavaFXandWaits;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MyJavaFXProgram extends Application {
@Override
public void start(Stage primaryStage) {
Text oText = new Text("My JavaFXProgram");
StackPane root = new StackPane();
root.getChildren().add(oText);
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑1:
我只是注意到,如果我尝试显示两次(例如:选择1,关闭JavaFX应用程序,然后再次选择1),它将崩溃Exception in thread "main" java.lang.IllegalStateException: Application launch must not be called more than once。似乎该代码中的JavaFX Application也未正确退出。
您的代码无法正常使用,因为它不适合JavaFX Application生命周期,有关JavaFX Application的生命周期已在的API文档中进行了全面记录Application。简而言之,Application该类表示整个应用程序(或应用程序的生命周期)。
要在JavaFX中显示窗口,您必须在FX应用程序线程上执行此操作,并且必须启动FX工具包才能启动该线程(除其他外)。的Application.launch()方法启动FX工具包,启动FX应用程序线程,创建您的应用程序类的init()实例,start()在该实例上调用,然后在该实例上调用(start()对FX Application Thread 的调用)。
如 记载,Application.launch()块(不返回),直到FX工具关闭(即退出应用程序),并且必须一次调用。(因为它代表了整个应用程序,所以这很有意义,并且没有办法解决两次调用它的问题。)
从用户的角度来看,您的应用程序结构也没有任何意义。为什么要让您的用户与命令行交互以向基于GUI的应用程序显示选项?您应该在GUI中显示这些选项。只需在启动时显示一个带有选项的窗口,然后显示与所选选项相对应的窗口。如果要确保用户在选择的选项完成之前无法返回到原始窗口,只需将新窗口设置为模态。
例如,如果您重构MyJavaFXProgram它不是Application子类(应该这样做,因为它不是应用程序的起点),则应该这样做:
import javafx.scene.Parent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
public class MyJavaFXProgram {
private StackPane view ;
public MyJavaFXProgram() {
Text oText = new Text("My JavaFXProgram");
view = new StackPane();
view.getChildren().add(oText);
}
public Parent getView() {
return view ;
}
}
Run Code Online (Sandbox Code Playgroud)
那你就可以
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MyJavaProgram extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Button showMeSomethingButton = new Button("Show me something");
showMeSomethingButton.setOnAction(e -> {
MyJavaFXProgram myProgram = new MyJavaFXProgram();
showInModalWindow(myProgram.getView());
});
Button exitButton = new Button("Exit");
exitButton.setOnAction(e -> Platform.exit());
VBox root = new VBox(10, exitButton, showMeSomethingButton);
root.setPadding(new Insets(20));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showInModalWindow(Parent view) {
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(new Scene(view));
stage.show();
}
}
Run Code Online (Sandbox Code Playgroud)
如果您真的想从命令行中驱动所有这些操作(老实说,我看不出有这样做的正当理由),那么它就变得很棘手,因此您必须在某些时候管理线程之间的交互,这很麻烦。可能最简单的方法是,确保在应用程序启动时启动FX工具包,然后按照您代码中的方式进行或多或少的处理,但是MyJavaFXProgram再次进行重构,以使其不是的子类Application。可以通过创建来启动FX工具包,JFXPanel这确实有点麻烦,但是我更喜欢通过使用来明确地进行操作Application实际上不做任何事情的类,调用launch()并等待其初始化类来进行操作。完成。我在回答这个问题时展示了如何做到这一点,所以我将从那里借用该解决方案。这是Application用于启动FX工具包的类(但不是您执行的主类):
import java.util.concurrent.CountDownLatch;
import javafx.application.Application;
import javafx.stage.Stage;
public class FXStarter extends Application {
private static final CountDownLatch latch = new CountDownLatch(1);
public static void awaitFXToolkit() throws InterruptedException {
latch.await();
}
@Override
public void init() {
latch.countDown();
}
@Override
public void start(Stage primaryStage) {
// no-op
}
}
Run Code Online (Sandbox Code Playgroud)
这个想法是调用Application.launch(FXStarter.class),但是由于launch()阻塞,您需要在后台线程上执行该操作。由于这意味着您的后续代码可能会(可能会)在launch()实际完成您需要完成的工作之前执行,因此您需要等待直到它完成工作为止,您可以使用来完成FXStarter.awaitFXToolkit()。然后,您可以执行循环。剩下唯一需要担心的就是确保您在FX Application Thread上创建并显示新窗口。所以您MyJavaProgram现在看起来像:
import java.util.Scanner;
import java.util.concurrent.FutureTask;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MyJavaProgram {
public static void main(String[] args) throws Exception {
// start FX toolkit on background thread:
new Thread(() -> Application.launch(FXStarter.class)).start();
// wait for toolkit to start:
FXStarter.awaitFXToolkit();
// make sure closing first window does not exit FX toolkit:
Platform.setImplicitExit(false);
int input;
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("0 - exit");
System.out.println("1 - display something to me");
input = scanner.nextInt();
switch (input) {
case 0:
break;
case 1:
// task to show UI:
FutureTask<Void> showProgramTask = new FutureTask<>(() -> {
MyJavaFXProgram program = new MyJavaFXProgram();
Stage stage = new Stage();
stage.setScene(new Scene(program.getView(), 400, 400));
stage.setOnShown(e -> {
stage.toFront();
stage.requestFocus();
});
// showAndWait will block execution until window is hidden:
stage.showAndWait();
return null ;
});
// show UI on FX Application Thread:
Platform.runLater(showProgramTask);
// block until task completes (i.e. window is hidden):
showProgramTask.get() ;
break;
}
if (input == 0) break;
}
// all done, exit FX toolkit:
Platform.exit();
scanner.close();
}
}
Run Code Online (Sandbox Code Playgroud)
(使用与MyJavaFXProgram上述相同的版本。)