2017-01-21 5 views
0

私のJavaプログラムでは、いくつかのオプションをユーザに与え、そのうちの1人が何かを表示するためにJavaFXProgramを呼び出します。このJavaFXが実際に終了したときに、Javaプログラムでもっと多くのコードを実行したいだけです。5秒かかることがあります。理想的には私が望むのはAndroidのようなものです。 startActivityForResult()と呼び出し、onActivityResult()の呼び出しを待ちます。 どうすれば私の状況で同様の行動を達成できますか?JavaプログラムでJavaFXを呼び出し、終了するまで待つより多くのコードを実行する

私が持っている問題を再現するために書いたこのコードがあります。それは同様の考えですが、何とかこれはJavaFXを呼び出し、ループの開始に行き、問題なくユーザーからの入力を取得します。私の他のプログラムでは、私はいつもException in thread "main" java.util.InputMismatchExceptionを取得して再び入力をスキャンします。しかし、私が言ったように、理想的には、JavaFXアプリケーションを終了した後にのみ、より多くのコードを実行したいと考えています。

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

} 

EDIT1:私はちょうど私が何かを2回表示しようとすることに気づいた

:それはException in thread "main" java.lang.IllegalStateException: Application launch must not be called more than onceでクラッシュ(例えば1、近いJavaFXアプリケーションを選択し、再度1を選択してください)。 JavaFXアプリケーションもこのコードで正しく終了していないようです。

+0

あなたは 'showAndWait()'を探しています。この方法ではないですか? –

+0

これは既に行われていませんか? ['Application.launch()'](http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#launch-java.lang.Class-java.lang.String。 ..-)はJavaFXアプリケーションが終了するまで戻りません。しかし、一般的には 'launch()'を複数回呼び出すことができないので、このアプローチはうまくいきません。 –

+0

どのような場合でもGUIアプリケーションをコマンドラインから起動するのはなぜですか?これを行うにはかなり難しいです:あなたはいくつかのスレッディングなどで手を汚さなければなりません。単純なウィンドウで「私に何かを見せる」オプションを表示してみませんか? –

答えて

2

あなたのコードは、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の同じバージョンを使用しています。)

関連する問題