JFace TreeViewer

chris_sit

Erfahrenes Mitglied
Hallo zusammen,

ich habe eine Struktur, die folgendem Schema entspricht:


Root
|
|- A
| |- A1
| | - A2
| - B


Die Knoten haben eine 1-N Beziehung, A kann also mehrere Kinder (A1, A2) haben. Wenn ich den TreeViewer füttere, bekomme ich auch die gewünschte Ausgabe als Baumansicht.

Jetzt würde ich die Elemente gerne Filtern, dazu gibt es ja die addFilter() Methode.
Mein Problem hierbei:

Wenn ich prüfe, ob das Element den Wert "123" besitzt, es sich aber nicht um eins der Blätter sondern einen der verzweigenden Knotten innerhalb des Baumes handelt, wird dieser "Zweig" auch entfernt.
Lasse ich Knoten mit weiteren Kindern generell zu, habe ich einen Baum mit vielen Zweigen - aber keinen Blättern.

Hat jemand eine Idee, wie ich den Baum derart stutzen kann, dass nur die Zweige durchkommen, die auf dem Weg zu den Blättern liegen?

Ich dachte mir, wenn ich bei jedem Knoten alle seine Kinder auslese und überprüfe, ob bei den Kindern ein gesuchtes Element dabei ist, nehme ich ihn dazu - aber das ist eine Menge rechnerei wenn er das für jeden Knoten in dem Baum macht.


Hoffe das war einigermaßen verständlich :rolleyes:

Gruß
Christian
 
Hallo!

Schau mal hier:
Java:
/**
 *
 */
package de.tutorials;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

/**
 * @author Thomas.Darimont
 */
public class JFaceTreeFilterExample extends ApplicationWindow {

  public JFaceTreeFilterExample(Shell shell) {
    super(shell);
    setBlockOnOpen(true);
  }


  protected void configureShell(Shell shell) {
    super.configureShell(shell);
    shell.setText("JFaceTreeFilterExample");
    shell.setSize(640, 480);
  }


  protected Control createContents(Composite composite) {

    TreeViewer treeViewer = new TreeViewer(composite);
    treeViewer.setContentProvider(createTreeContentProvider());
    treeViewer.setLabelProvider(new LabelProvider());
    treeViewer.setInput(createTreeModel());
    treeViewer.addFilter(createViewFilter());

    return composite;
  }


  private ViewerFilter createViewFilter() {
    final IPredicate treeNodeIdConstainsXPredicate = new IPredicate() {
      public boolean evaluate(Object arg) {
        return ((TreeNode) arg).getId().contains("X");
      }
    };
    return new ViewerFilter() {
      public boolean select(Viewer viewer, Object parentElement, Object element) {
        return treeNodeIdConstainsXPredicate.evaluate(element)
          || hasChildNodeWhichShouldBeDisplayed(((TreeNode) element), treeNodeIdConstainsXPredicate);
      }
    };
  }


  protected boolean hasChildNodeWhichShouldBeDisplayed(de.tutorials.JFaceTreeFilterExample.TreeNode node,
    IPredicate treeNodeIdConstainsXPredicate) {
    return null != findNode(node, treeNodeIdConstainsXPredicate);
  }


  private static Object findNode(TreeNode baseNode, IPredicate predicate) {
    Stack<TreeNode> stack = new Stack<TreeNode>();
    stack.push(baseNode);
    while (!stack.isEmpty()) {
      TreeNode currentNode = stack.pop();
      if (predicate.evaluate(currentNode)) {
        return currentNode;
      }
      for (TreeNode child : currentNode.children) {
        stack.push(child);
      }
    }

    return null;
  }

  static interface IPredicate {
    boolean evaluate(Object arg);
  }


  private IContentProvider createTreeContentProvider() {
    return new ITreeContentProvider() {
      public Object[] getChildren(Object parentElement) {
        return ((TreeNode) parentElement).getChildren();
      }


      public Object getParent(Object element) {
        return ((TreeNode) element).getParent();
      }


      public boolean hasChildren(Object element) {
        // TODO Auto-generated method stub
        return ((TreeNode) element).hasChildren();
      }


      public Object[] getElements(Object inputElement) {
        return getChildren(inputElement);
      }


      public void dispose() {
        // noop
      }


      public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        // noop
      }
    };
  }


  private Object createTreeModel() {
    TreeNode root = new TreeNode("root");
    TreeNode nodeA = root.addChild(new TreeNode("A"));
    TreeNode nodeAA = nodeA.addChild(new TreeNode("AAX"));
    TreeNode nodeAB = nodeA.addChild(new TreeNode("AB"));
    TreeNode nodeABA = nodeAB.addChild(new TreeNode("ABAX"));

    TreeNode nodeB = root.addChild(new TreeNode("B"));
    TreeNode nodeBA = nodeB.addChild(new TreeNode("BA"));
    TreeNode nodeBB = nodeB.addChild(new TreeNode("BBX"));
    return root;
  }


  /**
   * @param args
   */
  public static void main(String[] args) {
    JFaceTreeFilterExample jFaceTreeFilterExample = new JFaceTreeFilterExample(new Shell());
    jFaceTreeFilterExample.open();
  }

  // alternative: org.eclipse.jface.viewers.Treenode
  static class TreeNode {
    String id;
    int value;
    List<TreeNode> children;
    TreeNode parent;


    public TreeNode(String id) {
      this.id = id;
      this.value = id.hashCode();
      this.children = new ArrayList<TreeNode>();
    }


    TreeNode addChild(TreeNode node) {
      this.children.add(node);
      node.parent = this;
      return node;
    }


    TreeNode[] getChildren() {
      return this.children.toArray(new TreeNode[children.size()]);
    }


    boolean hasChildren() {
      return !this.children.isEmpty();
    }


    TreeNode getParent() {
      return this.parent;
    }


    /**
     * @return the id
     */
    public String getId() {
      return this.id;
    }


    /**
     * @param id the id to set
     */
    public void setId(String id) {
      this.id = id;
    }


    /**
     * @return the value
     */
    public int getValue() {
      return this.value;
    }


    /**
     * @param value the value to set
     */
    public void setValue(int value) {
      this.value = value;
    }


    public String toString() {
      return this.id + ": " + this.value;
    }
  }
}

Gruß Tom
 
Hi Thomas,

danke für den ausführlichen CodeSchnipsel, das hat mir sehr geholfen!

Ich hab es jetzt zum Laufen bekommen, bisher nur "schmalspur" - ohne das IPredicate Interface, daran hat er sich bei mir enorm gestört und den Filter zerschossen.
Konnte aber den Stack-Teil erfolgreich adaptieren und bekomme einen 1A gefilterten Tree :D
 
Zurück