2

如果在树查看器中有更多基于同一对象的树项目,则当当前选择等于我要导航的项目时,制作 aTreePath并将其传递给不会正确选择项目。TreeViewer.setSelection()

示例:
有一棵树有 2 个项目显示相同的对象(BigDecimal.ONE在本例中)。他们有不同的路径(不同的父母): 树

我希望当我在一个BigDecimal.ONE项目上时,单击链接并导航到另一个BigDecimal.ONE。在链接的选择侦听器上,我TreeSelection使用正确的TreePath. 然后我打电话setSelection。但是导航不起作用。但是,如果根项最初是折叠的,我注意到它会展开它,但不会导航到正确的项。

代码是这样的:

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;

public class TreeViewerExample {

    static class Model {
        String   name;
        Number[] children;

        public Model(String name, Number... numbers) {
            this.name = name;
            this.children = numbers;
        }

        public String toString() {
            return name;
        }
    }

    static class ModelTreeProvider extends LabelProvider implements ITableLabelProvider, ITreeContentProvider {

        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof Model) {
                return ((Model) parentElement).children;
            } else {
                return new Object[0];
            }
        }
        public Object getParent(Object element) {
            System.err.println("requesting the parent for " + element);
            return null;
        }
        public boolean hasChildren(Object element)
        {
            return getChildren(element) == null ? false : getChildren(element).length > 0;
        }
        public Object[] getElements(Object inputElement)
        {
            return (inputElement instanceof List)? ((List) inputElement).toArray():new Object[0];
        }
        public void dispose()
        {
        }
        public void inputChanged(Viewer arg0, Object arg1, Object arg2)
        {
        }
        public String getColumnText(Object element, int columnIndex)
        {
            return element.toString();
        }
        public Image getColumnImage(Object element, int columnIndex)
        {
            return null;
        }
    }

    public static void main(String[] args) {
        final List<Model> models = new ArrayList<Model>();
        models.add(new Model("Zero and one", BigDecimal.ZERO, BigDecimal.ONE));
        models.add(new Model("One and ten", BigDecimal.ONE, BigDecimal.TEN));

        Window app = new ApplicationWindow(null) {
            private TreeViewer treeViewer;
            private Link       link;
            protected Control createContents(Composite parent) {
                Composite composite = new Composite(parent, SWT.NONE);
                composite.setLayout(new FillLayout());
                treeViewer = new TreeViewer(composite);
                ModelTreeProvider provider = new ModelTreeProvider();
                treeViewer.setContentProvider(provider);
                treeViewer.setLabelProvider(provider);
                treeViewer.setInput(models);
                treeViewer.getTree().addSelectionListener(new SelectionAdapter() {
                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        if (((TreeItem) e.item).getText().equals("1")) {
                            link.setText("This is from "+((TreeItem) e.item).getParentItem().getText()
                                    + "\r\n<a href=\"go\">Go to the other " + ((TreeItem) e.item).getText() + "</a>");
                        } else {
                            link.setText(" - ");
                        }
                        link.setData(e.item);
                    }
                });
                link = new Link(composite, SWT.NONE);
                link.setText(" - ");
                link.addSelectionListener(new SelectionAdapter() {
                    public void widgetSelected(SelectionEvent e) {
                        List<Object> path = new ArrayList<Object>();
                        if (treeViewer.getTree().indexOf(treeViewer.getTree().getSelection()[0].getParentItem()) == 0)
                        {// if the first is selected, go to the second
                            path.add(treeViewer.getTree().getItem(1).getData());
                        } else {
                            path.add(treeViewer.getTree().getItem(0).getData());
                        }
                        path.add(BigDecimal.ONE);
                        treeViewer.setSelection(new TreeSelection(new TreePath(path.toArray())), true);
                    }
                });
                return composite;
            }
        };
        app.setBlockOnOpen(true);
        app.open();
    }
}

我的问题是这是一个 jface 错误还是我没有以正确的方式这样做?


编辑:

看来 eclipse.org 上已经发布了一个错误:https ://bugs.eclipse.org/bugs/show_bug.cgi?id=332736

4

1 回答 1

1

看起来这是 JFace 中的一个错误。毕竟,您正在传递,TreePath所以它应该弄清楚您想要的对象的确切实例。

问题是org.eclipse.jface.viewers.AbstractTreeViewer.isSameSelection(List, Item[])方法。它根据在项目(BigIntegers)中找到的元素错误地确定选择是相同的。它应该检查整个树路径以确保选择确实相​​同。幸运的是,您可以通过覆盖该isSameSelection(List, Item[])方法并正确检查树路径而不是元素本身来在代码中解决此问题:

       treeViewer = new TreeViewer(composite) {
            protected boolean isSameSelection(List items, Item[] current) {
                // If they are not the same size then they are not equivalent
                int n = items.size();
                if (n != current.length) {
                    return false;
                }
                Set itemSet = new HashSet(n * 2 + 1);
                for (Iterator i = items.iterator(); i.hasNext();) {
                    Item item = (Item) i.next();
                    itemSet.add(getTreePathFromItem(item));
                }
                // Go through the items of the current collection
                // If there is a mismatch return false
                for (int i = 0; i < current.length; i++) {
                    if (current[i].getData() == null
                            || !itemSet.contains(getTreePathFromItem(current[i]))) {
                        return false;
                    }
                }
                return true;
            }
       };

然而,这将解决这个特定问题,但不能保证还有其他问题等待被发现。就个人而言,我总是尽量避免在树的不同位置使用相同的元素,以防万一。

于 2011-06-09T22:56:15.957 回答