如果在树查看器中有更多基于同一对象的树项,那么当当前选择等于一个时,制作TreePath
并将其传递给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 bug还是我没有以正确的方式做到这一点?
修改
看来eclipse.org上已经有一个已发布的错误:https://bugs.eclipse.org/bugs/show_bug.cgi?id=332736
答案 0 :(得分: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;
}
};
然而,这将解决这个特殊问题,但无法保证等待找到其他问题。就个人而言,我总是尽量避免在树的不同位置使用相同的元素,以防万一。