Samstag, 5. November 2011

Eclipse RCP / SWT - Einfaches TreeViewer Beispiel

Eclipse 3.7 Indigo

In diesem Artikel wird ein einfaches TreeViewer Beispiel gezeigt. Das Beispiel konzentriert sich nur auf das Anzeigen eines Baumes, wodurch alle anderen Aspekte wie Menüs, andere ViewPart Elemente und andere GUI Elemente vernachlässigt werden. Es wird ein unendlicher binärer Baum dargestellt, dessen Hierarchierstufen gezählt werden. Alle notwendigen Schritte werden in einem HandsOn Tutorial nachvollzogen.

Schritt 1: RCP Applikation mit dem Namen com.blogspot.javadingsda.easytreeviewer aus der Vorlage 'RCP application with a view' erstellen.

Schritt 2: Entferne alle inneren Klassen, Methoden und Attribute aus der View Klasse und ersetze sie durch den unten aufgeführten Code. Die View Klasse sollte wie folgt aussehen.

package com.blogspot.javadingsda.easytreeviewer;

import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class View extends ViewPart {
  public static final String ID = 
    "com.blogspot.javadingsda.easytreeviewer.view";
  private TreeViewer treeViewer; 

  public void createPartControl(Composite parent) {
    treeViewer = new TreeViewer(parent);
    treeViewer.setContentProvider(new TreeContentProvider());
    treeViewer.setInput(new MyTreeNode(0));
  }

  public void setFocus() {
  }
}

Um mit den darzustellenden Daten versorgt zu werden, benötigt der TreeViewer eine Klasse, die das Interface ITreeContentProvider implementiert. Die Methoden des ITreeContentProvider werden im Posting ITreeContentProvider Methoden beschrieben. Für unser Beispiel sind die Methoden hasChildren(Object parent), getChildren(Object parent), getParent(Object child) und getElements(Object parent)wichtig. Die Funktionsweise der Methoden wird weiter unten in Bezug auf unser Beispiel näher erläutert. In unserem Beispiel implementiert die Klasse ViewContentProvider dieses Interface und wird dem TreeViewer mit der Methode setContntProvider(IContentProvider provider) bekannt gemacht.
Die Methode setInput(Object input) initialiseirt den Baum mit dem Root Knoten. Dieser wird nicht angezeigt.

Schritt 3: Erstelle die Klase MyTreeNode.

package com.blogspot.javadingsda.easytreeviewer;

import java.util.ArrayList;

public class MyTreeNode {
    
  private int depth;
  private MyTreeNode parent = null;
  private ArrayList children; 
    
  public MyTreeNode(int depth) {
    children = new ArrayList();
    this.depth = depth;
  }
    
  public MyTreeNode getParent() {
    return parent;
  }
    
  public Object[] getChildren() {
    return children.toArray();
  }
    
  public void addChild(MyTreeNode childNode) {
    childNode.setParent(this);
    this.children.add(childNode);
  }

  private void setParent(MyTreeNode parent) {
    this.parent = parent;
  }
    
  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("Knoten mit Tiefe ");
    sb.append(String.valueOf(depth));
    return sb.toString();
  }

  public int getDepth() {
    return this.depth;
  }
}
Die Klasse MyTreeNode ist für die Informationen eines Knotens verantworltich. Sie enthält eine Referenz auf einen Parent und Referenzen auf alle Kinderknoten. Die Tiefe wird mit dem Attribut depth dargestellt und ist nur für unser Beispiel relevant. Die toString Methode liefert die bezeichung des Labels im Knoten. Diese Klasse ist dann optional, wenn der ITreeContentProvider die gesamte Darstellung übernimmt und nicht auf den hier vorgestellten MyTreeNode Objekten arbeitet, sondern den Baum irgendwie anders verwaltet.

Schritt 4: Erstelle die Klase TreeContentProvider.

package com.blogspot.javadingsda.easytreeviewer;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

public class TreeContentProvider implements ITreeContentProvider {

  @Override
  public void dispose() {
  }

  @Override
  public void inputChanged(Viewer viewer, Object oldInput, 
                           Object newInput) {
  }

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

  @Override
  public Object[] getChildren(Object parentElement) {
    if (parentElement instanceof MyTreeNode) {
      MyTreeNode parentNode = (MyTreeNode) parentElement;
      return parentNode.getChildren();
    }
    return null;
  }

  @Override
  public Object getParent(Object element) {
    if (element instanceof MyTreeNode) {
      MyTreeNode node = (MyTreeNode) element;
      return node.getParent();
    }
    return null;
  }

  @Override
  public boolean hasChildren(Object element) {
    if (element instanceof MyTreeNode) {
      MyTreeNode node = (MyTreeNode) element;
      if (node.getChildren().length == 0) {
        createChildNodes(node);
      }
      return true;
    }
    return false;
  }

  public void createChildNodes(Object parent) {
    if (parent instanceof MyTreeNode) {
      MyTreeNode node = (MyTreeNode)parent;
      node.addChild(new MyTreeNode(node.getDepth() + 1));
      node.addChild(new MyTreeNode(node.getDepth() + 1));
    }
  }
}

public Object[] getElements(Object inputElement)

Diese Methode wird aufgerufen, wenn der Baum das erste mal initialieriert wird, und zwar wenn die Methode setInput(Object input) des TreeViewers aufgerufen wird. In unserem Beispiel werden in dieser Methode die ersten Kinderknoten erzeugt und wiedergegeben.

public Object[] getChildren(Object parentElement)

getChildren gibt die Kinderknoten zum parentElement wieder. In unserem Beispiel hält jeder Knoten Referenzen auf die Kinderknoten. Diese können mit der getChildren Methode abgefragt werden. getChildren wird immer dann aufgerufen, wenn die Kinderknoten angezeigt werden sollen.

public Object getParent(Object element)

Wird vom TreeViewer aufgerufen, wenn dieser geschlossene Knoten programmatisch aufdecken möchte und wenn der TreeViewer den 'geöffnet' Status programmatisch setzen möchte. In unserem Beipiel kommt diese Methode nicht zum Einsatz, wird aber implementiert um der Vollständigkeit zu genügen.

public boolean hasChildren(Object element)

Bevor der TreeViewer die Kinder eines Knotens anzeigt, wird dem Benutzer visuell angezeigt, dass sich unter einem geschlossenen Knoten weitere Knoten befinden. Das Aussehen ist Betriebssystemspezifisch. In WinXP ist dies ein kleines plus Zeichen, Win7 verwendet hingegen ein kleines Dreieck links neben dem Knoten. Die Methode hasChildren liefert für diese Anzeige die Information, ob sich unter dem Knoten weitere Kinderknoten befinden. Der Übergabeparameter element ist dabei der Elternknoten. In unserem Beispiel werden zwei neue Kinderknoten für einen Elternknoten erzeugt, wenn dieser keine Kinderknoten besitzt. Somit entseht der unendliche binäre Baum.

public void createChildNodes(Object parent)

Diese Methode erzeugt zwei Kinderknoten zu einem Elternknoten.

An dieser Stelle muss noch erwähnt werden, dass das Erzeugen der Kinderknoten auch in der MyTreeNode Klasse hätte implementiert werden können. Es ist generell eine Designfrage, ob der ITreeContentProvider alle informationen von den Knoten abfragt oder diese ermittelt.

Schritt 4: Anwendung starten.
Die Anwendung kann ausgeführt und getestet werden.

Weiterlesen:

TreeViewer mit 'Drag and Drop'

TreeViewer – Ereignisse beim öffnen/schließen eines Baumkontens im TreeViewer

TreeViewer - Methoden des ITreeContentProvider

Eclipse RCP - Hintergrundfarbe und Image eines Labels im TreeViewer

Keine Kommentare:

Kommentar veröffentlichen