当前位置:  开发笔记 > 编程语言 > 正文

在Java程序中调用JavaFX并等待退出以运行更多代码

如何解决《在Java程序中调用JavaFX并等待退出以运行更多代码》经验,为你挑选了1个好方法。

在我的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);
    }

}

编辑1:

我只是注意到,如果我尝试显示两次(例如:选择1,关闭JavaFX应用程序,然后再次选择1),它将崩溃Exception in thread "main" java.lang.IllegalStateException: Application launch must not be called more than once。似乎该代码中的JavaFX Application也未正确退出。



1> James_D..:

您的代码无法正常使用,因为它不适合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 ;
    }

}

那你就可以

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


}

如果您真的想从命令行中驱动所有这些操作(老实说,我看不出有这样做的正当理由),那么它就变得很棘手,因此您必须在某些时候管理线程之间的交互,这很麻烦。可能最简单的方法是,确保在应用程序启动时启动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
    }
}

这个想法是调用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 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();
    }

}

(使用与MyJavaFXProgram上述相同的版本。)

推荐阅读
郑小蒜9299_941611_G
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有