gpt4 book ai didi

JavaFX 并发 - 使用任务,该任务在线程中运行,但挂起 UI

转载 作者:行者123 更新时间:2023-12-02 10:23:14 25 4
gpt4 key购买 nike

关于并发有很多问题和答案,我的问题和答案可能与其他问题类似,但对我来说它不是重复的,因为出于某种原因我必须遗漏一些东西并希望得到一些建议......

我的问题更多的是,我需要第二双眼睛来指出我做错了什么以使我的代码能够在后台线程中运行,而且还更新了 GUI,而不卡住它。

最初,使用线程中的任务将 PDF 文件上传到应用程序。

这很好用。

显示进度条,动画没有问题:

上传文件()

public void uploadFile(File fileToProcess) {

fileBeingProcessed = fileToProcess;

Task<Parent> uploadingFileTask = new Task<Parent>() {
@Override
public Parent call() {
try {
progressBarStackPane.setVisible(true);
pdfPath = loadPDF(fileBeingProcessed.getAbsolutePath());
createPDFViewer();
openDocument();
} catch (IOException ex) {
java.util.logging.Logger.getLogger(MainSceneController.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
};

uploadingFileTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
fileHasBeenUploaded = true;
progressBarStackPane.setVisible(false);
uploadFilePane.setVisible(false);
tabPane.setVisible(true);

/* This is where I am getting issue, more so in createThumbnailPanels() */

setupThumbnailFlowPane();
createThumbnailPanels();

/****** ^^^^^^^^^^^^ ******/

}
});

uploadingFileTask.setOnFailed(evt -> {
uploadingFileTask.getException().printStackTrace(System.err);
System.err.println(Arrays.toString(uploadingFileTask.getException().getSuppressed()));
});

Thread uploadingFileThread = new Thread(uploadingFileTask);
uploadingFileThread.start();

}

文档上传后,它会显示在允许用户查看文档的选项卡中。

有一个辅助选项卡,上传后将被禁用,直到完成另一个名为 createThumbnailPanelsTask 的任务;

但是,在运行此任务之前,会创建缩略图面板的 FlowPane。这似乎工作没有问题,并且似乎不是 GUI 挂起的原因(这显然是 createThumbnailPanelsTask 中的循环,但为了清楚起见,我将显示 setupThumbnailFlowPane()):

setupThumbnailFlowPane()

public void setupThumbnailFlowPane() {
stage = model.getStage();
root = model.getRoot();

secondaryTabScrollPane.setFitToWidth(true);
secondaryTabScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);

/**
This will be removed from here when refactored but for now it is here,
I don't think this is anything to do with my issue
**/

Set<Node> nodes = secondaryTabScrollPane.lookupAll(".scroll-bar");
for (final Node node : nodes) {
if (node instanceof ScrollBar) {
ScrollBar sb = (ScrollBar) node;
if (sb.getOrientation() == Orientation.VERTICAL) {
sb.setUnitIncrement(30.0);
}
if (sb.getOrientation() == Orientation.HORIZONTAL) {
sb.setVisible(false);
}
}
}

secondaryTab = new FlowPane();
secondaryTab.setId("secondaryTab");
secondaryTab.setBackground(new Background(new BackgroundFill(Color.LIGHTSLATEGRAY, new CornerRadii(0), new Insets(0))));
secondaryTab.prefWidthProperty().bind(stage.widthProperty());
secondaryTab.prefHeightProperty().bind(stage.heightProperty());
secondaryTab.setPrefWrapLength(stage.widthProperty().intValue() - 150);
secondaryTab.setHgap(5);
secondaryTab.setVgap(30);
secondaryTab.setBorder(new Border(new BorderStroke(Color.TRANSPARENT, BorderStrokeStyle.NONE, CornerRadii.EMPTY, new BorderWidths(8, 10, 20, 10))));
secondaryTab.setAlignment(Pos.CENTER);
}

最后,调用了 createThumbnailPanels(),我相信这是我遇到问题的地方。

应该发生的情况是,文档上传后,上传文件 Pane 将被隐藏,显示“查看器”选项卡和“辅助”选项卡。

此时辅助选项卡已禁用,并且其左侧还有一个加载图像(gif)。

预期的行为是 createThumbnailPanels() 任务将在后台运行,并且在完成之前,该选项卡将保持禁用状态,但是在此期间,gif 图像将旋转,给人一种正在加载的印象。

加载完成后,gif 将被删除,并启用该选项卡,允许用户导航到该选项卡并查看生成的缩略图面板。

这一切都有效,但是,正如前面提到的,任务是挂起 GUI:

createThumbnailPanels()

public void createThumbnailPanels() {
Task<Void> createThumbnailPanelsTask = new Task<Void>() {
@Override
public Void call() {
if (model.getIcePdfDoc() != null) {
numberOfPagesInDocument = model.getIcePdfDoc().getNumberOfPages();
for (int thumbIndex = 0; thumbIndex < numberOfPagesInDocument; thumbIndex++) {
ThumbnailPanel tb = new ThumbnailPanel(thumbIndex, main, model);
Thumbnail tn = new Thumbnail(tb);
model.setThumbnailAt(tn, thumbIndex);
eventHandlers.setMouseEventsForThumbnails(tb);

/*
I have added this in as I am under the impression that a task runs in a background thread,
and then to update the GUI, I need to call this:
*/

Platform.runLater(() -> {
secondaryTab.getChildren().add(tb);
});

}

}

return null;
}
};

createThumbnailPanelsTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {

/*
Further GUI modification run in setOnSucceeded so it runs on main GUI thread(?)
*/
secondaryTabScrollPane.setContent(secondaryTab);
secondaryTab.setDisable(false);
secondaryTab.setGraphic(null);

}
});

createThumbnailPanelsTask.setOnFailed(evt -> {
createThumbnailPanelsTask.getException().printStackTrace(System.err);
System.err.println(Arrays.toString(createThumbnailPanelsTask.getException().getSuppressed()));
});

Thread createThumbnailPanelsThread = new Thread(createThumbnailPanelsTask);
createThumbnailPanelsThread.start();
}

除了创建面板时 GUI 挂起之外,一切都工作正常。

创建后,可以再次控制 GUI,加载 gif 已被删除,选项卡已启用,用户可以导航到它并查看面板。

显然,我在并发性方面缺少一些东西。

如上所述,我的印象是任务在后台线程中运行,所以我有点困惑为什么它似乎没有这样做。再次,显然我缺少一些东西。

我已经阅读、阅读、阅读有关并发的内容,但似乎无法找出我的方法中哪里出了问题。我很想尝试使用服务,但是,我觉得考虑到这一点让事情变得过于复杂,而且显然有一种简单的方法可以实现我想要实现的目标。

任何帮助将不胜感激......朝着正确的方向前进,或者对我的理解中出现错误的地方进行一些澄清。

提前致谢,毫无疑问,这是显而易见的事情,一旦排序将帮助我避免将来出现此问题!

更新的代码

createThumbnailPanels()

 public void createThumbnailPanels() {
Task<Void> createThumbnailPanelsTask = new Task<Void>() {
//TODO: Need to check that it's a PDF
@Override
public Void call() {
if (model.getIcePdfDoc() != null) {
numberOfPagesInDocument = model.getIcePdfDoc().getNumberOfPages();
for (int thumbIndex= 0; thumbIndex< numberOfPagesInDocument; thumbIndex++) {
ThumbnailPanel tb = new ThumbnailPanel(thumbIndex, main, model);
Thumbnail tn = new Thumbnail(tb);
eventHandlers.setMouseEventsForThumbnails(tb);
model.setThumbnailAt(tn, thumbIndex);
model.setThumbnailPanels(tb);
}
setThumbnailPanelsToScrollPane();
}
return null;
}
};

createThumbnailPanelsTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
// setThumbnailPanelsToScrollPane();
}
});

createThumbnailPanelsTask.setOnFailed(evt -> {

createThumbnailPanelsTask.getException().printStackTrace(System.err);
System.err.println(Arrays.toString(createThumbnailPanelsTask.getException().getSuppressed()));
});

Thread createThumbnailPanelsThread = new Thread(createThumbnailPanelsTask);
createThumbnailPanelsThread.start();
}

setThumbnailPanelsToScrollPane()

 public void setThumbnailPanelsToScrollPane() {
Task<Void> setThumbnailPanelsToScrollPaneTask = new Task<Void>() {
//TODO: Need to check that it's a PDF
@Override
public Void call() {
Platform.runLater(() -> {
secondaryTab.getChildren().addAll(model.getThumbnailPanels());
secondaryTabScrollPane.setContent(main.informationExtractionPanel);
secondaryTab.setDisable(false);
secondaryTab.setGraphic(null);
});

return null;
}
};


setThumbnailPanelsToScrollPaneTask.setOnFailed(evt -> {
setThumbnailPanelsToScrollPaneTask.getException().printStackTrace(System.err);
System.err.println(Arrays.toString(setThumbnailPanelsToScrollPaneTask.getException().getSuppressed()));
});

Thread setThumbnailPanelsToScrollPaneThread = new Thread(setThumbnailPanelsToScrollPaneTask);
setThumbnailPanelsToScrollPaneThread.start();
}

仅供引用:如果我在 setOnSucceeded 中调用 setThumbnailPanelsToScrollPane();,它似乎不起作用。

最佳答案

getChildren().add 正在 JavaFX GUI 线程上运行(这就是 Platform.runLater 所做的),但它只需要在 Platform.runLater 中运行它,如果您添加子项的父项连接到显示的 gui 的根,这意味着您应该能够将子项添加到未连接到任何子项的父项root,并在子添加过程结束时将整个父级添加到根,如果您在任何异步代码中执行 Platform.runLater ,它将在您的情况下在 gui 线程上运行在异步 for 循环中添加 ThumbnailPanels ,如果它们的数量很大,GUI 将挂起。

关于JavaFX 并发 - 使用任务,该任务在线程中运行,但挂起 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54179449/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com