1 回答

TA貢獻1805條經驗 獲得超9個贊
為什么 JavaFX 中的概念validate()
通常無效,以及解決線程問題
要解釋您的原始問題的一些問題以及為什么這個答案似乎無法直接回答它:
您通常不必
validate()
?(即強制子組件的布局)JavaFX 中的組件,因為 JavaFX 會在每次脈沖時自動為您執行此操作(研究鏈接的文檔以更充分地理解這一點)。有時您可能想要生成一個布局過程(我猜這在概念上有點類似于對 JFrame 進行驗證的顯式調用)。但是,這通常只是因為您想測量某物的尺寸,一旦它應用了 css 并且已經完全布局(這不是您想要在這里做的)。
您不應該嘗試在 JavaFX 應用程序線程之外更改場景圖中的內容,因為這會導致異常和競爭條件(即您對
setVisible
已創建的線程內的進度指示器的調用是錯誤的)。一些并發任務最好使用內置的 JavaFX 并發機制,例如將登錄提交到登錄服務并根據任務進度和結果與 UI 進行交互。
該怎么做
我認為你正在嘗試做的是:
創建登錄提示,其中登錄邏輯發生在另一個線程中
當登錄在另一個線程中進行時,有一個不確定的進度指示器旋轉。
進度指示器僅在登錄過程中顯示,一旦登錄嘗試完成(無論成功或失?。┚筒粫@示。
示例應用
登錄服務處理異步登錄過程。登錄窗格中的進度指示器指示登錄正在進行中。登錄完成后,登錄窗格將替換為已登錄用戶的應用程序窗格。
以下行確保僅在登錄服務執行時顯示進度指示器:
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;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? };
? ? ? ? }
? ? }
}
添加回答
舉報