2

ツリー ビューアに同じオブジェクトに基づくツリー アイテムが他にもある場合、 を作成してTreePathに渡すとTreeViewer.setSelection()、現在の選択がナビゲートしたいアイテムと同じ場合、アイテムが正しく選択されません。

例:
同じオブジェクト (BigDecimal.ONEこの場合) を示す 2 つの項目を持つツリーがあります。それらには異なるパスがあります (異なる親): 木

あるアイテムにいるときに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[])方法です。BigIntegerアイテム ( s) で見つかった要素に基づいて、選択が同じであると誤って判断します。ツリーパス全体をチェックして、選択が実際に同じであることを確認する必要があります。幸いなことに、メソッドをオーバーライドすることでコード内でこれを修正し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 に答える