我處于啟動新視圖但在其控制器中向服務器發出請求以獲取一些物件的情況。這個請求需要一些時間,所以我想在這個等待時間內實作一點加載視圖。因此,在我的控制器中,我實作了一個服務物件以在另一個執行緒中發出此請求:
public void initialize(URL url, ResourceBundle resourceBundle) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/MiniPages/LoadingPage.fxml"));
Scene scene = new Scene(root);
Stage primaryStage = new Stage();
primaryStage.initStyle(StageStyle.UNDECORATED);
Service<ProjectModel> service = new Service<ProjectModel>() {
@Override
protected Task<ProjectModel> createTask() {
return new Task<ProjectModel>() {
@Override
protected ProjectModel call() throws Exception {
SenderText data = new SenderText();
int id = Integer.parseInt(data.getData());
Client client = Client.getInstance();
JSONObject tosend = new JSONObject();
tosend.put("Type", "Get Project");
tosend.put("IDproject", id);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateSerializer());
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateDeserializer());
Gson gson = gsonBuilder.setPrettyPrinting().create();
client.sendText(tosend.toString());
String response = client.receiveText();
ProjectModel project = gson.fromJson(response, ProjectModel.class);
projectLocal = project;
System.out.println(gson.toJson(projectLocal));
primaryStage.close();
primaryStage.hide();
return project;
}
};
}
};
service.start();
primaryStage.setScene(scene);
primaryStage.initModality(Modality.APPLICATION_MODAL);
while (service.getValue() == null) {
primaryStage.showAndWait();
}
primaryStage.close();
System.out.println("Finish");
primaryStage.close();
} catch (Exception e) {
e.printStackTrace();
}
}
我測驗并在 call() 方法上設定了物件。但是加載視圖沒有關閉。我也嘗試打電話primaryStage.show()而不是打電話,showandWait()但沒有奏效。知道如何解決嗎?
uj5u.com熱心網友回復:
JavaFX 中有兩個主要的執行緒規則(類似于大多數其他 UI 工具包)。
- 您不得從后臺執行緒對 UI 執行操作。這包括創建、顯示或隱藏視窗。
- 您不得阻塞 UI 執行緒(“FX 應用程式執行緒”)。
primaryStage.close()您通過呼叫該call()方法違反了第一條規則。
您的繁忙while回圈違反了第二條規則。(更糟糕的是;我認為該服務的value屬性僅在 FX 應用程式執行緒上更新。因此,由于您阻塞了該執行緒,因此value無法更新該屬性并且while回圈永遠不會退出。)
要在后臺完成時執行 UI 操作Task,您可以使用onSucceeded處理程式。在后臺任務成功完成后,在 FX 應用程式執行緒上呼叫此處理程式。
public void initialize(URL url, ResourceBundle resourceBundle) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/MiniPages/LoadingPage.fxml"));
Scene scene = new Scene(root);
Stage primaryStage = new Stage();
primaryStage.initStyle(StageStyle.UNDECORATED);
Service<ProjectModel> service = new Service<ProjectModel>() {
@Override
protected Task<ProjectModel> createTask() {
return new Task<ProjectModel>() {
@Override
protected ProjectModel call() throws Exception {
SenderText data = new SenderText();
int id = Integer.parseInt(data.getData());
Client client = Client.getInstance();
JSONObject tosend = new JSONObject();
tosend.put("Type", "Get Project");
tosend.put("IDproject", id);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateSerializer());
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateDeserializer());
Gson gson = gsonBuilder.setPrettyPrinting().create();
client.sendText(tosend.toString());
String response = client.receiveText();
ProjectModel project = gson.fromJson(response, ProjectModel.class);
return project;
}
};
}
};
service.setOnSucceeded(event -> {
System.out.println("Finish");
// I think; don't know what projectLocal is, or
// which threads it should be accessed from:
projectLocal = project ;
primaryStage.hide();
});
service.start();
primaryStage.setScene(scene);
primaryStage.showAndWait();
} catch (Exception e) {
e.printStackTrace();
}
}
順便說一句,您可能不需要Service這里。Service真正為重復使用而設計,您只使用一次。只需在后臺執行緒上創建Task并運行它就足夠了:
public void initialize(URL url, ResourceBundle resourceBundle) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/MiniPages/LoadingPage.fxml"));
Scene scene = new Scene(root);
Stage primaryStage = new Stage();
primaryStage.initStyle(StageStyle.UNDECORATED);
Task<ProjectModel> task = new Task<ProjectModel>() {
@Override
protected ProjectModel call() throws Exception {
SenderText data = new SenderText();
int id = Integer.parseInt(data.getData());
Client client = Client.getInstance();
JSONObject tosend = new JSONObject();
tosend.put("Type", "Get Project");
tosend.put("IDproject", id);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateSerializer());
gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateDeserializer());
Gson gson = gsonBuilder.setPrettyPrinting().create();
client.sendText(tosend.toString());
String response = client.receiveText();
ProjectModel project = gson.fromJson(response, ProjectModel.class);
return project;
}
};
task.setOnSucceeded(event -> {
System.out.println("Finish");
// I think; don't know what projectLocal is, or
// which threads it should be accessed from:
projectLocal = project ;
primaryStage.hide();
});
new Thread(task).start();
primaryStage.setScene(scene);
primaryStage.showAndWait();
} catch (Exception e) {
e.printStackTrace();
}
}
您的代碼結構在這里看起來有點奇怪。看起來您需要在啟動時為您的應用程式創建一個模型,并且該啟動需要一些時間,因此您在加載時會顯示某種“啟影片面”。這里奇怪的部分是您是在initialize()FXML 控制器的方法中執行此操作的。這應該Application作為生命周期方法的一部分在您的類中完成start()。該結構應如下所示:
public class App extends Application {
public static void main(String[] args) {
Application.launch();
}
@Override
public void start(Stage primaryStage) throws Exception {
Task<ProjectModel> task = new Task<>() {
@Override
public ProjectModel call() throws Exception {
return loadModel();
}
};
Stage loadingStage = showLoadingStage();
task.setOnSucceeded(e -> {
loadingStage.hide();
showMainStage(primaryStage, task.getValue());
});
new Thread(task).start();
}
private ProjectModel loadModel() throws Exception {
// load model and return it....
}
private Stage showLoadingStage() throws Exception {
Scene scene = new Scene(getClass().getResource("LoadingPage.fxml"));
Stage loadingStage = new Stage();
loadingStage.initStyle(StageStyle.UNDECORATED);
loadingStage.setScene(scene);
loadingStage.show();
return loadingStage ;
}
private void showMainStage(Stage stage, ProjectModel model) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
Parent root = loader.load();
MainController controller = loader.getController();
controller.setModel(model);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
作為具有以下方法MainController的常規 FXML 控制器setModel(...):
public class MainController {
private ProjectModel model ;
// @FXML-annotated fields
@FXML
private void initialize() {
// initialization work that does not require model
}
public void setModel(ProjectModel model) {
this.model = model ;
// initialize any UI that depends on the model, etc.
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/477128.html
上一篇:“org.hibernate.PersistentObjectException:分離的物體傳遞給堅持”我無法解決的錯誤
下一篇:無法在Java單元測驗中捕獲值
