如何在java中多次调用launch()

2022-09-03 17:23:34

如何在java中多次调用launch()我被赋予一个例外,如“MAIN:java.lang.IllegalStateException中的错误:应用程序启动不得调用多次”

我已经在我的java应用程序中创建了休息cleint,当请求来临时,它调用javafx并在完成webview操作后打开webview,使用Panform.exit()方法关闭javafx窗口。当第二个请求来时,我得到这个错误如何重新设置这个错误。

JavaFx Application Code:

public class AppWebview extends Application  {

    public static Stage stage;

    @Override
    public void start(Stage _stage) throws Exception {

        stage = _stage;
        StackPane root = new StackPane();

        WebView view = new WebView();

        WebEngine engine = view.getEngine();
        engine.load(PaymentServerRestAPI.BROWSER_URL);
        root.getChildren().add(view);
        engine.setJavaScriptEnabled(true);
        Scene scene = new Scene(root, 800, 600);
        stage.setScene(scene);

        engine.setOnResized(new EventHandler<WebEvent<Rectangle2D>>() {
            public void handle(WebEvent<Rectangle2D> ev) {
                Rectangle2D r = ev.getData();
                stage.setWidth(r.getWidth());
                stage.setHeight(r.getHeight());
            }
        });

        JSObject window = (JSObject) engine.executeScript("window");
        window.setMember("app", new BrowserApp());

        stage.show();

    }

    public static void main(String[] args) {
        launch(args);
    }

RestClient 方法:调用 JavaFX 应用程序

// method 1 to lanch javafx
javafx.application.Application.launch(AppWebview.class);

// method 2 to lanch javafx
String[] arguments = new String[] {"123"};
AppWebview .main(arguments);

答案 1

你不能在 JavaFX 应用程序上多次调用 launch(),这是不允许的。

来自 javadoc:

It must not be called more than once or an exception will be thrown.

定期显示窗口的建议

  1. 只需呼叫一次。Application.launch()
  2. 使用 Platform.setImplicitExit(false) 保持 JavaFX 运行时在后台运行,以便 JavaFX 在您隐藏最后一个应用程序窗口时不会自动关闭。
  3. 下次需要另一个窗口时,将窗口 show() 调用包装在 Platform.runLater() 中,以便在 JavaFX 应用程序线程上执行调用。

有关此方法的简短摘要实现:

如果您要混合 Swing,则可以使用 JFXPanel 而不是应用程序,但使用模式将与上面概述的模式类似。

乌姆普斯样本

此示例比需要的要复杂一些,因为它还涉及计时器任务。但是,它确实提供了一个完整的独立示例,有时可能会有所帮助。

import javafx.animation.PauseTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.*;

// hunt the Wumpus....
public class Wumpus extends Application {
    private static final Insets SAFETY_ZONE = new Insets(10);
    private Label cowerInFear = new Label();
    private Stage mainStage;

    @Override
    public void start(final Stage stage) {
        // wumpus rulez
        mainStage = stage;
        mainStage.setAlwaysOnTop(true);

        // the wumpus doesn't leave when the last stage is hidden.
        Platform.setImplicitExit(false);

        // the savage Wumpus will attack
        // in the background when we least expect
        // (at regular intervals ;-).
        Timer timer = new Timer();
        timer.schedule(new WumpusAttack(), 0, 5_000);

        // every time we cower in fear
        // from the last savage attack
        // the wumpus will hide two seconds later.
        cowerInFear.setPadding(SAFETY_ZONE);
        cowerInFear.textProperty().addListener((observable, oldValue, newValue) -> {
            PauseTransition pause = new PauseTransition(
                    Duration.seconds(2)
            );
            pause.setOnFinished(event -> stage.hide());
            pause.play();
        });

        // when we just can't take it  anymore,
        // a simple click will quiet the Wumpus,
        // but you have to be quick...
        cowerInFear.setOnMouseClicked(event -> {
            timer.cancel();
            Platform.exit();
        });

        stage.setScene(new Scene(cowerInFear));
    }

    // it's so scary...
    public class WumpusAttack extends TimerTask {
        private String[] attacks = {
                "hugs you",
                "reads you a bedtime story",
                "sings you a lullaby",
                "puts you to sleep"
        };

        // the restaurant at the end of the universe.
        private Random random = new Random(42);

        @Override
        public void run() {
            // use runlater when we mess with the scene graph,
            // so we don't cross the streams, as that would be bad.
            Platform.runLater(() -> {
                cowerInFear.setText("The Wumpus " + nextAttack() + "!");
                mainStage.sizeToScene();
                mainStage.show();
            });
        }

        private String nextAttack() {
            return attacks[random.nextInt(attacks.length)];
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

更新, 一月 2020

Java 9 添加了一个名为 Platform.startup() 的新功能,您可以使用它来触发 JavaFX 运行时的启动,而无需定义从中派生并调用它的类。 对该方法有类似的限制(您不能调用多次),因此如何应用它的元素与此答案中的讨论和Wumpus示例类似。Applicationlaunch()Platform.startup()launch()Platform.startup()launch()

有关如何使用的演示,请参阅Fabian对如何实现JavaFX和非JavaFX交互的回答?Platform.startup()


答案 2

我使用类似这样的东西,类似于其他答案。

private static volatile boolean javaFxLaunched = false;

public static void myLaunch(Class<? extends Application> applicationClass) {
    if (!javaFxLaunched) { // First time
        Platform.setImplicitExit(false);
        new Thread(()->Application.launch(applicationClass)).start();
        javaFxLaunched = true;
    } else { // Next times
        Platform.runLater(()->{
            try {
                Application application = applicationClass.newInstance();
                Stage primaryStage = new Stage();
                application.start(primaryStage);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}

推荐