Java SWT Tree TreeItem Listener return 一个 Widget Disposed 异常错误

Java SWT Tree TreeItem Listener return a Widget Disposed Exception Error

我制作了一个程序,它通过文本框、按钮和文件对话框从用户那里获取多个输入,并将它们格式化为 SWT 树,用户可以在其中 select 通过复选框元素。

我面临的问题是我想让它为用户实时更新,我在这个论坛上找到了一个关于使用容器的layout()方法的解决方案,并且它适用于我的树,但前提是我在这棵树上调用 dispose(),然后重建它/之后重新绘制它。

在这棵树的后面,我有一个树数据结构,用于管理所有数据。 此外,我正在使用的 class 实现了 SWT 的 Dialog 界面,因此当我按下按钮时,将显示带有树和文本输入区域的 window。

我 class 我已经声明了树所在的容器。

final Composite container = new Composite(parent, SWT.NONE);

接下来我将调用这个包含树的实际构建过程的静态方法

createTree(container);

我有一些其他代码用于用户输入的按钮和文本区域,但这不会影响程序的行为或抛出的异常。

这是静态方法createTree(container);

public void createTree(final Composite container){
    try{
        for(Object element : container.getChildren()){
            if(element instanceof Tree){
                ((Tree) element).dispose();
            }
        }//here I am disposing of the previous tree and then I'm creating a new one to be drawn in the container when the layout() method will be called

        final Tree variantTree = new Tree(container, SWT.CHECK | SWT.V_SCROLL | SWT.H_SCROLL);
        variantTree.setBounds(10, 65, 400, 400);

//here is where I am populating the tree with the data I have stored in the Tree Data Structure that I've mentioned

        if(TestControl.getTree().getChildren().size() > 0){
            for(final Node variantElement : TestControl.getTree().getChildren()){
                final TreeItem variantTreeItem = new TreeItem(variantTree, 0);
                variantTreeItem.setText(variantElement.getName());
                variantTreeItem.setChecked(variantElement.getState());

                for(Node suiteElement : variantElement.getChildren()){
                    TreeItem suiteTreeItem = new TreeItem(variantTreeItem, 0);
                    suiteTreeItem.setText(suiteElement.getName());
                    suiteTreeItem.setChecked(suiteElement.getState());

                    for(Node testElement : suiteElement.getChildren()){
                        TreeItem testTreeItem = new TreeItem(suiteTreeItem, 0);
                        testTreeItem.setText(testElement.getName());
                        testTreeItem.setChecked(testElement.getState());
                    }
                }
            }
        }
        //here is the actual problem, the exception's stack trace points to the line where my next comment is. this listener is used to bring a file dialog window where I can select a file and use it later on 

        variantTree.addListener(SWT.MouseDoubleClick, new Listener(){
            @Override
            public void handleEvent(Event event) {
                try{
                    // TODO Auto-generated method stub
                    Point point = new Point(event.x, event.y);
                    if(!point.equals(null)){
                        TreeItem item = variantTree.getItem(point);
                        for(Node element : TestControl.getTree().getChildren()){
                            if(element.getName().equals(item.getText())){//here is the problem, why is it trying to tell me 

                                FileDialog fileDialog = new FileDialog(container.getParent().getShell(), SWT.OPEN);
                                //filtering for extensions
                                //filtering for path

                                String path;

                                if((path = fileDialog.open()) != null){
                                    String fileName = fileDialog.getFileName();
                                    Node suiteNode =  new Node(element);
                                    suiteNode.setName(fileName);
                                    TestControl.addChild(suiteNode);


                                    createTree(container);
//here I call the method in a recursive way. After I modified my Tree Data Structure with the data I got from the user, I want to redraw the tree in a real timed fashion

                                }
                            }
                        }   
                    }
                }catch(Exception exception){
                    exception.printStackTrace();
                    Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,  exception.getLocalizedMessage(), exception);
                    ErrorDialog.openError(null, "Error", "Error occured!", status);
                }
            }
        });

        variantTree.addListener(SWT.Selection, new Listener(){

            @Override
            public void handleEvent(Event event) {
                // TODO Auto-generated method stub
                if(event.detail == SWT.CHECK){
                    TreeItem item = (TreeItem) event.item;

                    for(Node element : TestControl.getTree().getChildren()){
                        if(element.getName().equals(item.getText())){
                            element.setState(item.getChecked());
                        }
                    }

                    for(Node element : TestControl.getTree().getChildren()){
                        for(Node nextElement : element.getChildren()){
                            if(nextElement.getName().equals(item.getText())){//here the error doesnt show up, even though I am using the SWT Tree element as above
                                nextElement.setState(item.getChecked());
                            }
                        }
                    }

                    for(Node element : TestControl.getTree().getChildren()){
                        for(Node nextElement : element.getChildren()){
                            for(Node lastElement : nextElement.getChildren()){
                                if(lastElement.getName().equals(item.getText())){
                                    lastElement.setState(item.getChecked());
                                }
                            }
                        }
                    }
                }
            }
        });
    }catch(Exception exception){
        exception.printStackTrace();
        Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,  exception.getLocalizedMessage(), exception);
        ErrorDialog.openError(null, "Error", "Error occured!", status);
    }
}

我还了解到可能会出现此错误,因为当我调用 dispose 时,我也应该摆脱监听器。 是否有必要,这可能是异常的来源? 谢谢,对于拥抱代码部分感到抱歉。

我假设错误发生在显示 FileDialog 后调用 createTree 方法时。

当您调用 createTree 时,您处于此循环中:

for(Node element : TestControl.getTree().getChildren()){

所以在 createTree 调用后立即返回到循环的开始并且 运行

if(element.getName().equals(item.getText()))

但是这里的 item 指的是 Tree 中的一个 TreeItem ,你刚刚处理掉了,所以它不再有效,你得到 'widget disposed' 错误。

调用 createTree 后,您必须立即停止循环,并且不要对现有树执行任何其他操作。 break 在这里停止循环就足够了:

       createTree(container);
       break;

注意:您不必处理 Tree,只需删除 TreeItem 并添加新的就足够了。