2011-06-09 59 views
2

如果樹查看器中存在更多基於同一對象的樹項目,則製作TreePath並將其傳遞給TreeViewer.setSelection()時,不會正確選擇項目當前選擇等於我想要導航的選擇。TreeViewer.setSelection()在給出的路徑後不會選擇正確的項目

例如:
有一棵樹有兩個項目顯示相同的對象(在這種情況下爲BigDecimal.ONE)。他們有不同的路徑(不同的家長): tree

我想,當我在一個BigDecimal.ONE項,點擊鏈接,導航到其他BigDecimal.ONE。在鏈接的選擇監聽器上,我使用正確的TreePath製作TreeSelection。然後我撥打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

+0

爲您提供示例代碼的榮譽! – 2011-06-09 22:57:10

回答

1

看起來這是JFace的一個bug。畢竟,你傳遞TreePath所以它應該找出你想要的對象的確切實例。

問題是org.eclipse.jface.viewers.AbstractTreeViewer.isSameSelection(List, Item[])方法。它根據項目中找到的元素(BigInteger)錯誤地確定選擇是相同的。它應該檢查整個樹的路徑,以確保選擇確實是相同的。幸運的是,你可以通過重寫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; 
      } 
     }; 

然而,這將解決這方面的問題,但不能保證有等待被發現的其他問題。就我個人而言,我總是儘量避免在樹的不同位置放置相同的元素,以防萬一。

+0

您的解決方案有效;但爲了讓程序按預期工作,應該爲'treeViewer.addSelectionChangedListener'設置一個'ISelectionChangedListener',而不是'tree.addSelectionListener'(就像我的代碼片段一樣)。 – 2011-06-10 08:37:49

+0

順便說一句,在樹的不同位置使用相同的元素不是我的選擇。 – 2011-06-10 08:39:34

+0

它在我的Windows 7和Windows XP x64機器上按原樣工作(無需替換選擇監聽器)。另外,我使用Eclipse 3.6.2。 – 2011-06-10 10:17:52