JavaFX:在进程运行时禁用所有组件并显示进度指示器

时间:2017-01-31 11:00:18

标签: java javafx progress progress-indicator

我有一个从数据库读取值并返回Map<Integer,String>.的方法。此方法需要一些时间才能返回地图。

直到时间值被读取我想要一个进度指示器(只有像指示器一样的加载环就足够了,不需要进度条)才能在屏幕上显示,所有其他组件应该被禁用,直到显示时间进度条

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

2 个答案:

答案 0 :(得分:1)

这是一个SSCE:

它使用可以多次启动的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;
}

答案 1 :(得分: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%的alpha值,因此您可以将其称为叠加层。

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

我认为问题在于您正在尝试更改TextFieldTask s的值,这不是FX应用程序线程,这就是您获得Not on FX application thread的原因。要解决此问题,您需要将修改节点的行(如下所示)修改为if语句。

Platform.runLater()