2017-10-01 1 views
2

시작하는 데 시간이 걸리기 때문에 현재 프로그램 용 스플래시 화면을 만들려고합니다. 문제는 GUI (대화 작성, 테이블 업데이트 등)를 만드는 데 시간이 걸리는 것입니다. 그리고 GUI 작성을 백그라운드 스레드 (예 : "태스크"클래스)로 옮길 수는 없습니다. "FXApplication Thread에 없다"예외가 생길 것이기 때문입니다. 태스크의 방법을백그라운드에서 JavaFX GUI로드 중

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

을 그리고 "전화": 나는 사용하여 시도 난 그냥없이 표시하고 EventDispatchThread로의 시작 화면을 업데이트 할 수있는 스윙의 프로그램을 작성

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

어떤 진짜 동행. 코드는 다음처럼 보였다 :

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 포함) 자바 FX 애플리케이션 스레드의 오프 대부분의 장면 그래프 오브젝트를 수정할 수 있습니다. 활성 장면 그래프 란 현재 표시된 장면에 장면으로 첨부 된 장면 그래프를 의미합니다. WebView과 같은 복잡한 컨트롤은이 규칙의 예외 일 수 있으며 JavaFX 응용 프로그램 스레드에서 작성해야 할 수 있습니다.

JavaFX 응용 프로그램 스레드에서 만든 장면 그래프 개체는 JavaFX 응용 프로그램 스레드의 활성 장면 그래프에만 연결해야합니다 (예 : Platform.runLater() 사용). 또한 활성 장면 그래프에 계속 첨부되어있는 한 JavaFX 응용 프로그램 스레드에서 작업해야합니다.

+0

답변 해 주셔서 감사합니다. 나는 이미이 방법을 시도했다. 이렇게하면 스플래시 화면을 표시하고 GUI를 만들 수 있지만 진행률 표시 줄을 업데이트 할 수 없습니다. 예제 코드에 대한 내 원래 게시물을 참조하십시오. – maumau

관련 문제