2017-10-01 2 views
2

私は現在起動に時間がかかるので、私のプログラムのためのスプラッシュスクリーンを作成しようとしています。 問題は、GUIの作成(ダイアログの作成、テーブルの更新など)に時間がかかることです。そして、私は "Not on FXApplication Thread"例外を取得するので、GUI作成をバックグラウンドスレッド(「タスク」クラスのような)に移動することはできません。 私が使用してみました:JavaFX GUIをバックグラウンドでロードしています

Platform.runLater(new Runnable() { 
      public void run() { 
      //create GUI 
    } 
} 

とタスクの「コール」方法:

public class InitWorker extends Task<Void> { 

    private Model model; 
    private ViewJFX view; 

    public InitWorker(Model model) { 
     this.model = model; 
    } 

    @Override 
    protected Void call() throws Exception { 
      View view = new View(); 
      Collection collection = new Collection(); 
      //do stuff 
    } 
} 

を私はSwingでプログラムを書いたとき、私はせずに、EventDispatchThreadのスプラッシュ画面を表示し、更新することができ本当の共演者。コードは次のように見えた:

public void build() { 
     MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Menus"); 
     menuCreator = new MenuCreatorOld (model, this); 
     menuCreator.createMenu(); 
     MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE, "Creating Toolbar"); 
     toolBar = menuCreator.createToolBar(); 

     createWesternPanelToolBar(); 

     shoppingPanel = new ShoppingListOld(model, this, collectionController, shoppingController, controller); 

     centerTabbedPane = new JTabbedPane(); 
      MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Collection"); 
      collectionPanel = new CollectionOld(model, collectionController, this, controller); 
      MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Wish List"); 
      wishPanel = new WishListOld(model, this, collectionController, wishController, controller); 

      MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Folders Table"); 
      //and so on 
} 

public static void updateProgressBar(int progressValue, String text) { 
    System.out.println("Loading Bar Value:"+progressValue); 
    progressBar.setValue(progressValue); 
    loadingLabel.setText(text); 
    progressBar.setString(text); 
} 

ロードバーにスプラッシュ画面を表示しながら、バックグラウンドでのGUIを作成する方法はありますか?

編集:

私は私のコードを見ていたし、5秒で起動時間を短縮することができました。ほとんどのダイアログは、作成時にデータベースからデータを取り込みます。そこで、ダイアログの作成をgetterメソッドに移しました。その結果、3秒の改善となりました。しかし、私はまだバックグラウンドスレッドでGUIを作成する方法があるかどうかを知りたいです。

編集:

示唆したように、私はまた、 "タスク" で "RunLater" を使用してみました。 この方法でGUIを作成してSplashScreenを表示できますが、GUIの作成によってJavaFXアプリケーションスレッドがブロックされるため、プログレスバーと進行状況ラベルは更新できません。進行状況バーとラベルは、GUIが完全に作成された後にのみ更新されます。

ここであなたたちは(私はスプラッシュ画面を削除し、唯一のプログレスバーとプログレスラベルを保持)を実行することができます例を示します

public class InitWorker extends Task<Void> { 


    private static ProgressBar progressBar; 
    private static Label progressLabel; 
    private static double PROGRESS_MAX = 5; 
    private double loadingValue; 

    public InitWorker() { 
     loadingValue = 0; 
    } 

    @Override 
    protected void succeeded() { 
     System.out.println("Succeeded"); 
    } 

    @Override 
    protected void failed() { 
     System.out.println("Failed"); 
    } 

    @Override 
    protected Void call() throws Exception { 
     System.out.println("RUNNING"); 
     Platform.runLater(new Runnable() { 
      public void run() { 
       displaySplashScreen(); 
       for(int i=0; i<10; i++) { 
        try { 
         Thread.sleep(200); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        updateProgressBar(loadingValue++, "Label "+i); 
        Stage stage = new Stage(); 
        Label label = new Label("Label " + i); 
        VBox panel = new VBox(); 
        panel.getChildren().add(label); 
        Scene scene = new Scene(panel); 
        stage.setScene(scene); 
        stage.centerOnScreen(); 
        stage.show(); 
       } 
//    updateProgressBar(1, "Initializing..."); 

      }}); 

     return null; 
    } 


    public void updateProgressBar(double loadingValue, String text) { 
     progressBar.setProgress(loadingValue/PROGRESS_MAX); 
     progressLabel.setText(text); 
    } 




    public static void displaySplashScreen() { 

     Stage progressBarStage = new Stage(); 
     progressBar = new ProgressBar(); 
     Scene progressBarScene = new Scene(progressBar); 
     progressBarStage.setScene(progressBarScene); 

     Stage progressLabelStage = new Stage(); 
     progressLabel = new Label("Loading..."); 
     progressLabel.setPadding(new Insets(5)); 
     progressLabel.setStyle("-fx-background-color: red"); 
     Scene progressLabelScene = new Scene(progressLabel); 
     progressLabelStage.setScene(progressLabelScene); 

     double progressBarWidth = 500; 
     double progressBarHeight = 75; 

     //muss angezeigt werden, um sie abhängig von Größe zu positionieren 
     progressBarStage.show(); 
     progressLabelStage.show(); 
     // 

     progressBarStage.setWidth(progressBarWidth); 
     progressBarStage.setHeight(progressBarHeight); 
     progressBarStage.centerOnScreen(); 
     progressBarStage.centerOnScreen(); 
     progressLabelStage.setY(progressLabelStage.getY() + 25); 


    } 

} 
+3

GUIを作成するのにかなりの時間がかかりません。 GUIで表示するデータなどを取得するのに時間がかかるかもしれませんが、その部分をバックグラウンドスレッドで実行できます。実際のGUI作成に時間がかかることは確かですか? –

+0

私は自分のコードを見て、起動時間を5秒短縮できました。ほとんどのダイアログは、作成時にデータベースからデータを取り込みます。そこで、ダイアログの作成をgetterメソッドに移しました。その結果、3秒の改善となりました。しかし、私はまだ背景のスレッドでGUIを作成する一般的な方法があるかどうかを知りたいです。 – maumau

+0

あなたはどのハードウェアとOSを使用していますか?問題を示す[mcve]を提供できますか? – Itai

答えて

0

に例を示しますTask documentation titled "A Task Which Modifies The Scene Graph"を参照してください。

final Group group = new Group(); 
Task<Void> task = new Task<Void>() { 
    @Override protected Void call() throws Exception { 
     for (int i=0; i<100; i++) { 
      if (isCancelled()) break; 
      final Rectangle r = new Rectangle(10, 10); 
      r.setX(10 * i); 
      Platform.runLater(new Runnable() { 
       @Override public void run() { 
        group.getChildren().add(r); 
       } 
      }); 
     } 
     return null; 
    } 
}; 

上記の例では、100 runLaterの呼び出しによって矩形をシーングラフに追加しています。これを行うより効率的な方法は、アクティブシーングラフに添付されていないグループに四角形を追加し、runLaterコールのアクティブシーングラフにグループを追加するだけです。たとえば、次のように

final Group groupInSceneGraph = new Group(); 
Task<Void> task = new Task<Void>() { 
    @Override protected Void call() throws Exception { 
     final Group localGroup = new Group(); 
     for (int i=0; i<100; i++) { 
      if (isCancelled()) break; 
      final Rectangle r = new Rectangle(10, 10); 
      r.setX(10 * i); 

      localGroup.getChildren().add(r); 
     } 

     Platform.runLater(new Runnable() { 
      @Override public void run() { 
       groupInSceneGraph.add(localGroup); 
      } 
     }); 

     return null; 
    } 
}; 

あなたがいる限り、オブジェクトがアクティブなシーングラフに添付されていないとして、作成して(ロードFXMLを含む)のJavaFXアプリケーションスレッドのオフほとんどのシーングラフオブジェクトを変更することができます。アクティブシーングラフとは、現在、シーンとして表示されているステージにアタッチされているシーングラフを意味します。 (WebViewなどの複雑なコントロールは、このルールの例外であり、JavaFXアプリケーションスレッドでの作成が必要な場合があります)。

JavaFXアプリケーションスレッドから作成したシーングラフオブジェクトは、JavaFXアプリケーションスレッドのアクティブシーングラフにのみ添付する必要があります(たとえばPlatform.runLater()を使用)。また、アクティブなシーングラフに引き続きアタッチされている限り、JavaFXアプリケーションスレッド上でそれらと作業する必要があります。

+0

あなたの答えをありがとう。私はすでにこの方法を試みました。この方法で私はスプラッシュ画面を表示してGUIを作成できますが、プログレスバーを更新することはできません。コード例の私の元の記事を見てください。 – maumau

関連する問題