1 回答

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