【问题标题】:Updating javafx treeview in with progress indicator使用进度指示器更新 javafx 树视图
【发布时间】:2016-01-18 14:16:07
【问题描述】:

我正在尝试创建一个基本上是具有计算机文件结构的树项的类(是的,我正在尝试在这里创建一个文件管理器)。我已将 TreeView 设置为延迟加载,并且效果很好。但是对于非常长的目录(有很多文件夹的目录,例如%Windir%/WinSxS),它需要一些时间。我已经实现了进度指示器(工作还没有完成,但这就是我想要的)。它也可以,但它不会更新用户界面。

我知道任务更新进度指示器必须在另一个线程中运行(javafx 线程除外)。所以我尝试了ThreadPlatform#runLaterCountdownLatch 等(我可能以错误的方式实现它)。但我要么无法更新进度指示器 ui,要么遇到 Concurrent Modification 错误。以下是我迄今为止的课程代码(我的许多尝试之一):

class FileTreeItemImpl extends TreeItem<String> {

private boolean isLeaf = false;
private boolean childrenCached = false;
private boolean leafCached = false;
// File is basically one of root dirs
private final File file;
// pi is passed as constructor from the controller class (in which pi is injected via FXML)
private volatile ProgressIndicator pi;
// This is to control pi's progress
private static volatile double x = 0;

public FileTreeItemImpl() {
    this("Root", new File("/"), null);
}

public FileTreeItemImpl(String file, File fileObj, ProgressIndicator pi) {
    super(file);
    this.pi = pi;
    this.file = fileObj;

}

@Override
public ObservableList<TreeItem<String>> getChildren() {
    if (!childrenCached) {
        childrenCached = true;
        if (file != null && file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                x = 0;
                new Thread() {
                    @Override
                    public void run() {
                        for (File childFile : files) {
                            pi.setProgress(x / (files.length - 1));
                            x++;
                            if (childFile.isDirectory())
                                getChildren().add(new FileTreeItemImpl(childFile.getName(), childFile, pi));

                        }
                    }
                }.start();
            }
        }
    }
    return super.getChildren();
}

@Override
public boolean isLeaf() {
    if (!leafCached) {
        leafCached = true;
        isLeaf = file.isFile();
    }
    return isLeaf;
}

}

注意:上面的代码完全符合我的要求,但直到该目录的子文件夹数量很少。如果有太多(同样,像%winddir%/WinSxS),那么我会得到ConcurrentModificationException

编辑: 无论如何,这里是堆栈跟踪:

Exception in thread "JavaFX Application Thread" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:386)
    at java.util.AbstractList$Itr.next(AbstractList.java:355)
    at javafx.scene.control.TreeItem.updateExpandedDescendentCount(TreeItem.java:892)
    at javafx.scene.control.TreeItem.getExpandedDescendentCount(TreeItem.java:880)
    at javafx.scene.control.TreeItem.updateExpandedDescendentCount(TreeItem.java:894)
    at javafx.scene.control.TreeItem.getExpandedDescendentCount(TreeItem.java:880)
    at javafx.scene.control.TreeItem.updateExpandedDescendentCount(TreeItem.java:894)
    at javafx.scene.control.TreeItem.getExpandedDescendentCount(TreeItem.java:880)
    at javafx.scene.control.TreeItem.updateExpandedDescendentCount(TreeItem.java:894)
    at javafx.scene.control.TreeItem.getExpandedDescendentCount(TreeItem.java:880)
    at javafx.scene.control.TreeUtil.getExpandedDescendantCount(TreeUtil.java:40)
    at javafx.scene.control.TreeUtil.updateExpandedItemCount(TreeUtil.java:49)
    at javafx.scene.control.TreeView.updateExpandedItemCount(TreeView.java:1042)
    at javafx.scene.control.TreeView.getExpandedItemCount(TreeView.java:614)
    at javafx.scene.control.TreeView$TreeViewFocusModel.getItemCount(TreeView.java:1649)
    at javafx.scene.control.FocusModel.isFocused(FocusModel.java:128)
    at javafx.scene.control.TreeCell.updateFocus(TreeCell.java:557)
    at javafx.scene.control.TreeCell.indexChanged(TreeCell.java:476)
    at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116)
    at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1957)
    at com.sun.javafx.scene.control.skin.VirtualFlow.addLeadingCells(VirtualFlow.java:1246)
    at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1194)
    at javafx.scene.Parent.layout(Parent.java:1079)
    at javafx.scene.Parent.layout(Parent.java:1085)
    at javafx.scene.Parent.layout(Parent.java:1085)
    at javafx.scene.Parent.layout(Parent.java:1085)
    at javafx.scene.Scene.doLayoutPass(Scene.java:552)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)

【问题讨论】:

    标签: java multithreading javafx treeview concurrentmodification


    【解决方案1】:

    我有一个类似的实现,将ProgressIndicator 用作TreeItem 的一部分。 - 我使用Task 解决了这个问题,我用它来更新 UI。

    我的Task 实现如下所示:

    class ProgressWorker extends Task<Void> {
    
        ...
    
        @Override
        protected Void call() throws Exception {
            while (getCurrentRow() < getMaxRow()) {
                Thread.sleep(100);
                updateProgress(getCurrentRow(), getMaxRow());
                updateMessage(getTextMessage());
            }
            return null;
        }
    }
    

    使用bind 将Tasks progressProperty 绑定到Indicator:

    progressIndicator.progressProperty().bind(this.worker.progressProperty());
    

    现在将 worker 启动为 Thread。 - 并将您的操作作为线程。 在您的线程内部,您应该能够更新其属性绑定到指标的任务。

    (很郁闷,比我想象的要难用英文解释)

    【讨论】:

    • 非常感谢。我在多次尝试中实现了Task,但我一定是做错了什么。无论如何,您的示例有所帮助:)
    • 很高兴我能帮上忙。 - 我还得到了一个可能有帮助的示例实现:pastebin.com/qxnWn8Rm(一周后到期)
    猜你喜欢
    • 2018-07-26
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多