为了账号安全,请及时绑定邮箱和手机立即绑定

如何验证进度指示器的 setVisible 属性

如何验证进度指示器的 setVisible 属性

慕斯709654 2023-06-21 16:15:22
我正在编写一个 javafx 程序,我需要在登录系统后放置一个进度指示器,它应该等待特定的时间,直到它从服务器加载所需的对象。我是 javafx 的新手,我想要一种方法来验证控制器中的 setVisible(boolean) 属性,在初始化时它应该是不可见的并且在初始化方法中将它设置为 false 没有问题但是在初始化后的控制器中我认为我应该验证变化。有没有一种方法可以用来验证此属性更改?     //////pseudocode@FXML ProgressIndicator pi;public void initialize(...){ PI.setVisible(false);   }@FXML public void buttonOnClick(){Thread t1=new Thread(new Runnable(....)) // A thread to load data t1.startpi.setVisible(true); //HERE IS MY PROBLEMThread t2;//a thread to increase progress  t2.start();t1.join();}
查看完整描述

1 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

为什么 JavaFX 中的概念validate()通常无效,以及解决线程问题

要解释您的原始问题的一些问题以及为什么这个答案似乎无法直接回答它:

  1. 您通常不必validate() (即强制子组件的布局)JavaFX 中的组件,因为 JavaFX 会在每次脉冲时自动为您执行此操作(研究链接的文档以更充分地理解这一点)。

  2. 有时您可能想要生成一个布局过程(我猜这在概念上有点类似于对 JFrame 进行验证的显式调用)。但是,这通常只是因为您想测量某物的尺寸,一旦它应用了 css 并且已经完全布局(这不是您想要在这里做的)。

  3. 您不应该尝试在 JavaFX 应用程序线程之外更改场景图中的内容,因为这会导致异常和竞争条件(即您对setVisible已创建的线程内的进度指示器的调用是错误的)。

  4. 一些并发任务最好使用内置的 JavaFX 并发机制,例如将登录提交到登录服务并根据任务进度和结果与 UI 进行交互。

该怎么做

我认为你正在尝试做的是:

  1. 创建登录提示,其中登录逻辑发生在另一个线程中

  2. 当登录在另一个线程中进行时,有一个不确定的进度指示器旋转。

  3. 进度指示器仅在登录过程中显示,一旦登录尝试完成(无论成功或失败)就不会显示。

//img4.sycdn.imooc.com/6492b1bb00016f0902620652.jpg

示例应用

登录服务处理异步登录过程。登录窗格中的进度指示器指示登录正在进行中。登录完成后,登录窗格将替换为已登录用户的应用程序窗格。

以下行确保仅在登录服务执行时显示进度指示器:

progressIndicator.visibleProperty().bind(loginService.runningProperty());

完整代码:

import javafx.application.Application;

import javafx.beans.property.SimpleStringProperty;

import javafx.beans.property.StringProperty;

import javafx.concurrent.Service;

import javafx.concurrent.Task;

import javafx.geometry.Insets;

import javafx.scene.Scene;

import javafx.scene.control.*;

import javafx.scene.layout.*;

import javafx.stage.Stage;


import java.io.IOException;


public class LoginServiceApp extends Application {

    private LoginService loginService = new LoginService();


    @Override

    public void start(Stage stage) throws IOException {

        Pane loginPane = createLoginPane();

        loginService.setOnSucceeded(event ->

                stage.getScene().setRoot(createAppPane(stage))

        );


        stage.setScene(new Scene(new StackPane(loginPane)));

        stage.show();

    }


    private Pane createLoginPane() {

        GridPane credentialsGrid = new GridPane();

        credentialsGrid.setHgap(10);

        credentialsGrid.setVgap(10);

        TextField usernameField = new TextField("frobozz");

        PasswordField passwordField = new PasswordField();

        credentialsGrid.addRow(0, new Label("Username"), usernameField);

        credentialsGrid.addRow(1, new Label("Password"), passwordField);


        Button loginButton = new Button("Login");

        loginButton.setOnAction(event -> {

            loginService.setUsername(usernameField.getText());

            loginService.setPassword(passwordField.getText());

            loginService.restart();

        });

        loginButton.disableProperty().bind(loginService.runningProperty());


        ProgressIndicator progressIndicator = new ProgressIndicator();

        progressIndicator.visibleProperty().bind(loginService.runningProperty());

        progressIndicator.setPrefSize(20, 20);


        HBox loginControl = new HBox(10, loginButton, progressIndicator);

        VBox loginPane = new VBox(10, credentialsGrid, loginControl);

        loginPane.setPadding(new Insets(10));


        return loginPane;

    }


    private Pane createAppPane(Stage stage) {

        Button logoutButton = new Button("Logout");

        logoutButton.setOnAction(event -> stage.getScene().setRoot(createLoginPane()));

        HBox appPane = new HBox(logoutButton);

        appPane.setPadding(new Insets(10));


        return appPane;

    }


    public static void main(String[] args) {

        launch(args);

    }


    private static class LoginService extends Service<Void> {

        private StringProperty username = new SimpleStringProperty(this, "username");

        public final void setUsername(String value) { username.set(value); }

        public final String getUsername() { return username.get(); }

        public final StringProperty usernameProperty() { return username; }


        private StringProperty password = new SimpleStringProperty(this, "password");

        public final void setPassword(String value) { password.set(value); }

        public final String getPassword() { return password.get(); }

        public final StringProperty passwordProperty() { return password; }


        @Override

        protected Task<Void> createTask() {

            final String _username = getUsername();

            final String _password = getPassword();

            return new Task<Void>() {

                @Override

                protected Void call() throws Exception {

                    // Simulate a long call to a login service,

                    // using the username and password we saved when the task was created.

                    // If login fails, an exception can be raised to report it and the

                    // caller starting the service can monitor setOnException to handle it.

                    // Or the Task could return a result value instead of void and the caller

                    // could monitor the value property of the task in addition to the exception handler.

                    Thread.sleep(1_000);

                    return null;

                }

            };

        }

    }

}


查看完整回答
反对 回复 2023-06-21
  • 1 回答
  • 0 关注
  • 100 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信