【发布时间】:2015-09-15 17:01:52
【问题描述】:
我正在尝试构建一个进度条,当我的应用程序正在检索数据并将其填充到 GUI 时,该进度条正在更新。我认为进度条会被大量重复使用,所以我决定创建自己的类。但是,我不相信我通常理解 Worker/Task 或多线程来创建可重用的情况。创建可以侦听应用程序线程并相应更新进度条的进度条的推荐方法是什么。这是我的尝试:
// Simple Progress Bar View as Pop Up
public class ProgressIndicatorUtil{
@FXML
private ProgressBar progressBar;
@FXML
private Label statusLabel;
@FXML
private Button closeButton;
@FXML
private Label valueLabel;
private Worker worker;
private Stage stage;
public void setPopUpStage(Stage stage) {
this.stage = stage;
}
public void setWorker(Worker worker) {
this.worker = worker;
}
public void setLinkToMainPage(Object controller) {
((Task<String>) worker).setOnSucceeded(event -> stage.close());
((Task<String>) worker).setOnCancelled(event -> {
closeButton.setVisible(true);
stage.requestFocus();
statusLabel.setTextFill(Color.RED);}
);
valueLabel.textProperty().bind(Bindings.format("%5.1f%%", worker.progressProperty().multiply(100)));
progressBar.progressProperty().bind(worker.progressProperty());
statusLabel.textProperty().bind(worker.messageProperty());
}
@FXML
private void handleClose(ActionEvent e){
stage.close();
}
}
调用视图弹出窗口并运行进度条线程的控制器。
public class MyController{
//Controller calling the view and disabling the main GUI
private void loadProgressBar(Worker worker){
try{
FXMLLoader loader = new FXMLLoader(getClass()
.getClassLoader().getResource("main/resources/fxml/ProgressBar.fxml"));
AnchorPane pane = (AnchorPane)loader.load();
Stage popUpStage = new Stage();
popUpStage.initModality(Modality.WINDOW_MODAL);
Scene scene = new Scene(pane);
popUpStage.setScene(scene);
ProgressIndicatorUtil controller = loader.getController();
controller.setPopUpStage(popUpStage);
controller.setWorker(worker);
controller.setLinkToMainPage(this);
mainPane.setDisable(true);
popUpStage.showingProperty().addListener((obs, hidden, showing) -> {
if(hidden) mainPane.setDisable(false);});
popUpStage.show();
}catch(IOException e){
e.printStackTrace();
}
}
private void runProgressBar(Worker worker) {
new Thread((Runnable) worker).start();
}
//A user action that runs the progress bar and GUI
@FXML
private void aBigProcessingEvent(ActionEvent event) {
Worker worker = new Task<String>(){
@Override
protected String call() throws Exception {
updateProgress(0, 3);
updateMessage("Clearing Data");
processingEvent01();
updateProgress(1, 3);
updateMessage("Retriving Data And Adding To List");
processingEvent02();
updateProgress(2, 3);
updateMessage("Populating Data");
processingEvent03();
updateProgress(3, 3);
return "Finished!";
}
};
loadProgressBar(worker);
runProgressBar(worker);
}
}
该程序在视觉上工作正常,但它会引发这样的异常 (Not On FX Application Thread) 并在我的“处理事件”方法上运行 Platform.runLater() 将导致我的进度条立即为 100%,但它不会不再抛出异常。关于如何将应用程序修改方法和工作方法分开,同时保持进度与 processingEvent 方法连接的任何建议?非常感谢。
【问题讨论】:
-
您可以尝试创建一个 Integer 对象,然后将其传递给线程并在任务完成时递增。然后将您的进度设置为整数/任务数的值。确保在访问对象的引用时使用同步。
-
@MarcinDeszczynski 你不能这样做:它肯定会生成 OP 描述的那种
IllegalStateExceptions。绑定到任务的进度属性并调用updateProgress(...)正是这样做的正确方法。 -
这段代码对我来说很合适;我无法测试它,因为它不完整。哪一行抛出
IllegalStateException?processingEvent*()方法有什么作用?您应该将所有耗时的方法保留在后台线程中,但将任何更新 UI 的方法调用包装在Platform.runLater(...)中。 (updateProgress和updateMessage方法被设计为从后台线程调用;它们基本上为您处理对Platform.runLater(...)的调用。)
标签: java multithreading javafx