2017-01-31 19 views
0

У меня есть метод, который считывает значения из базы данных и возвращает Map<Integer,String>.. Этот метод занимает некоторое время, чтобы вернуть карту.JavaFX: отключить все компоненты во время выполнения процесса и показать индикатор прогресса

До тех пор, пока значения не будут считаны. Я хочу индикатор прогресса (только индикатор заполнения, такой как индикатор, будет достаточным, нет необходимости в индикаторе выполнения), который будет отображаться на экране, а все остальные компоненты должны быть отключены до тех пор, пока индикатор времени не будет показано на рисунке.

public void scanDevice() { 
    ObservableList<TextField> list = FXCollections.observableArrayList(vehicleId, vehicleName, deviceType, 
      offboardBroker1, offboardBroker2, postfixQueue, pKIServer); 
    editedValuesMap.clear(); 
    // devicePlugged = true; 
    if (cbChooseProject.getSelectionModel().getSelectedItem() != null) { 
     try { 
      devicePlugged = dsAdapter.getAdapter(); 
      if (devicePlugged) { 
       if (bScanDevice.isFocused()) { 
        readMap = new HashMap<Integer, String>(); 
        //Process Start 
        readMap = dsAdapter.initScan(); 
        //Process End 

        if (!readMap.isEmpty() && readMap != null) { 
         isWritten = true; 
         isDeviceSideEnabled(); 
         editDeviceContents.setDisable(false); 
         vehicleId.setText(readMap.get(0)); 
         vehicleName.setText(readMap.get(1)); 
         deviceType.setText(readMap.get(2)); 
         offboardBroker1.setText(readMap.get(3)); 
         offboardBroker2.setText(readMap.get(4)); 
         postfixQueue.setText(readMap.get(5)); 
         pKIServer.setText(readMap.get(6)); 
         lContentsSerialNo.setText(readMap.get(7)); 
        } 
       } 
      } 

ответ

0

Вы могли бы отключены все узлы с методом, как следующие, но если вы также желая ждать, пока что-то происходит наложение с помощью StackPane сек может быть предпочтительный выбор.

public void setNodesDiabled(boolean disable, Node... nodes) { 
    for(Node node : nodes) { 
     node.setDisable(disable); 
    } 
} 

С произвольным количеством узлов, то можно отключить и повторно включить как можно больше узлов, которые имеют отношение к процессу. Это также помогает очистить, поскольку у вас не будет нескольких node.setDisable(true); node2.setDisable(true); и так далее.

Здесь в этом примере вам не понадобится setNodesDisabled(), потому что накладка StackPane предотвращает щелчок на чем-либо, кроме того, что внутри него. Цвет фона серый с 70% альфа, так что вы можете сказать, что это оверлей.

public class ProgressExample extends Application { 

    public StackPane layout, main, progress; 

    public StackPane createProgressPane() { 
     ProgressIndicator indicator = new ProgressIndicator(); 
     indicator.setMaxHeight(50); 
     indicator.setMaxWidth(50); 

     StackPane pane = new StackPane(); 
     pane.setAlignment(Pos.CENTER); 
     pane.setStyle("-fx-background-color: rgba(160,160,160,0.7)"); 
     pane.getChildren().add(indicator); 

     Task<Void> task = new Task<Void>(){ 
      protected Void call() throws Exception { 
       // Your process here. 
       // Any changes to UI components must be inside Platform.runLater() or else it will hang. 
       Thread.sleep(2000); 

       Platform.runLater(() -> { 
        layout.getChildren().remove(pane); 
       }); 
       return null; 
      } 
     }; 
     new Thread(task).start(); 
     return pane; 
    } 

    public StackPane createMainPane() { 
     Label label = new Label("Hello World!"); 
     label.setFont(Font.font("Tahoma", FontWeight.SEMI_BOLD, 16)); 

     Button start = new Button("Start Process"); 
     start.setOnAction(action -> { 
      progress = createProgressPane(); 
      layout.getChildren().add(progress); 
     }); 

     VBox vbox = new VBox(10); 
     vbox.setAlignment(Pos.CENTER); 
     vbox.getChildren().addAll(label, start); 
     vbox.setPadding(new Insets(10,10,10,10)); 

     StackPane pane = new StackPane(); 
     pane.getChildren().add(vbox); 
     return pane; 
    } 

    public void start(Stage stage) throws Exception { 
     main = createMainPane(); 

     layout = new StackPane(); 
     layout.getChildren().add(main); 

     Scene scene = new Scene(layout, 900, 550); 
     stage.setScene(scene); 
     stage.setTitle("Progress Example"); 
     stage.setOnCloseRequest(e -> { 
      Platform.exit(); 
      System.exit(0); 
     }); 
     stage.show(); 
    } 

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

Я считаю, что проблема в том, что вы пытаетесь изменить значения TextField с внутри Task, который не является поток приложения FX поэтому вы получаете Not on FX application thread. Чтобы исправить это, вам нужно поместить свои строки, которые изменяют узлы внутри Platform.runLater(), как показано ниже в вашем операторе if.

if (readMap != null && !readMap.isEmpty()) { // Swap the order, can't check empty if it's null. 
    isWritten = true; 
    isDeviceSideEnabled(); 
    Platform.runLater(() -> { 
     editDeviceContents.setDisable(false); 
     vehicleId.setText(readMap.get(0)); 
     vehicleName.setText(readMap.get(1)); 
     deviceType.setText(readMap.get(2)); 
     offboardBroker1.setText(readMap.get(3)); 
     offboardBroker2.setText(readMap.get(4)); 
     postfixQueue.setText(readMap.get(5)); 
     pKIServer.setText(readMap.get(6)); 
     lContentsSerialNo.setText(readMap.get(7)); 
    }); 
} 
+0

Не могли бы вы рассказать мне, что использовать этот Thread.sleep (2000); Нужно ли вычислять время, требуемое моим методом, а затем спать поток за это время и из-за ограничений проекта я должен использовать макет BorderPane. Я получаю следующее сообщение об ошибке: Исключение в теме "Thread-5" java.lang.IllegalStateException: не на потоке приложения FX; currentThread = Thread-5 –

+0

Использование 'Thread.sleep (2000);' в примере было просто потому, что это пример. Без чего-либо внутри, чтобы занять время, область прогресса не будет видна достаточно долго, проверяя ее. Вам это не нужно. Что касается ошибки, можете ли вы отредактировать вопрос, чтобы включить эти строки в 'Задача'? Вам нужно поместить ваши строки, которые изменяют узлы и панели FX в пределах их собственной 'Platform.runLater()'. –

+0

Mathews, я добавил код, содержащий мой процесс. Значения считывания процесса с устройства a отображают его в пользовательском интерфейсе. –

1

Вот ВПЧЭ:

Он использует Service, который может быть запущен несколько раз. Это не полный, но с чего начать.

public class Main extends Application { 
    @Override 
    public void start(Stage primaryStage) { 

     BorderPane root = new BorderPane(); 
     Scene scene = new Scene(root, 400, 400); 
     scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm()); 

     Service<Void> serv = new Service<Void>() { 

      @Override 
      protected Task<Void> createTask() { 
       return new Task<Void>() { 

        @Override 
        protected Void call() throws Exception { 
         int maxWork = 10; 
         for (int i = 0; i < maxWork; i++) { 
          Thread.sleep(1000); 
          updateProgress(i + 1, maxWork); 
         } 

         return null; 
        } 

        @Override 
        protected void succeeded() { 
         super.succeeded(); 
         updateProgress(1, 1); 
        } 

        @Override 
        protected void cancelled() { 
         super.cancelled(); 
         updateProgress(1, 1); 
        } 

        @Override 
        protected void failed() { 
         super.failed(); 
         updateProgress(1, 1); 
        } 

       }; 
      } 
     }; 

     ProgressIndicator pi = new ProgressIndicator(); 
     pi.progressProperty().bind(serv.progressProperty()); 


     Button bStart = new Button("Start"); 
     bStart.setOnAction(e -> { 
      serv.reset(); 
      serv.start(); 
     }); 

     root.setCenter(bStart); 
     root.setBottom(pi); 

     primaryStage.setScene(scene); 
     primaryStage.show(); 

     pi.getScene().getRoot().disableProperty().bind(serv.runningProperty()); 
    } 

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

В CSS я добавил:

.progress-indicator:disabled { 
    -fx-opacity: 1; 
}