あなたのコードは、JavaFXアプリケーションのライフサイクルに適合しないため、コードが正しく動作しません。これは、Application
のAPIドキュメントに完全に記載されています。手短に言えば、Application
クラスは、のアプリケーション全体(またはアプリケーションのライフサイクルかもしれません)を表します。
JavaFXでウィンドウを表示するには、FXアプリケーションスレッドで実行する必要があります。FXツールキットを起動して、このスレッドを開始する必要があります。 Application.launch()
メソッドは、FXツールキットを起動し、FXアプリケーションスレッドを開始し、アプリケーションクラスのインスタンスを作成し、そのインスタンスでinit()
を呼び出し、そのインスタンスでstart()
を呼び出します(start()
への呼び出しはFXアプリケーションスレッドで発生します)。
documentedとして、Application.launch()
は、FXツールキットがシャットダウンされる(つまり、アプリケーションが終了する)までブロックされず、一度だけ呼び出されなければなりません。 (アプリケーション全体を表しているので、これは意味があり、2回呼び出すことで回避する方法はありません)。
アプリケーションの構造は実際にはユーザーの観点からも意味をなさない。 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
のサブクラスではありません。 JFXPanel
を作成することで、FXツールキットを起動するためのハックがありますが、これは実際にはちょっとしたハックです。Application
クラスを実際には実行しないで、launch()
を呼び出すことを明示的に行います。完了するための初期化。私はthis questionの答えでこれを行う方法を示したので、そこからそのソリューションを借りてみましょう。ここではFXツールキットを開始するために使用されるApplication
クラスがある(ただし、あなたが実行メインクラスではありません):
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アプリケーションスレッドで新しいウィンドウを作成して表示することだけです。だからあなたの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();
}
}
(これは上記MyJavaFXProgram
の同じバージョンを使用しています。)
あなたは 'showAndWait()'を探しています。この方法ではないですか? –
これは既に行われていませんか? ['Application.launch()'](http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#launch-java.lang.Class-java.lang.String。 ..-)はJavaFXアプリケーションが終了するまで戻りません。しかし、一般的には 'launch()'を複数回呼び出すことができないので、このアプローチはうまくいきません。 –
どのような場合でもGUIアプリケーションをコマンドラインから起動するのはなぜですか?これを行うにはかなり難しいです:あなたはいくつかのスレッディングなどで手を汚さなければなりません。単純なウィンドウで「私に何かを見せる」オプションを表示してみませんか? –