Probleme beim Einfügen von Nodes in einen TreeViewer

Crai

Mitglied
Einfügen von Nodes in einen TreeViewer(Eclipse Plugin)

Hallo,

ich bin zur Zeit dabei, mich in in das Thema Views im Zusammenhang mit der Entwicklung eines Plugins für Eclipse einzuarbeiten.
Dazu verwende ich teilweise Beispiele aus dem Buch "The Java Developer's Guide to Eclipse".
Eines davon (Kapitel 15/com.ibm.jdg2e.jface,viewers) stellt einen TreeViewer dar, der mit
nem doch recht komplizierten Datenmodell gefüttert wird. Ich hab dann mal das ganze
versucht nachzuprogrammieren unter Verwendung eines recht einfachen Datenmodels(ich erzeuge mit der Klasse Input einfach eine RootTreeNode mit noch ein paar Kindern dazu).

Jetzt habe ich folgendes Problem, auf dessen Lösung ich nicht komme:
Zum einen gibt die Methode getElements(inputElement) nur immer das Wurzelelement zurück und zum andren wird die Methode getChildren(inputElelement) nie aufgerufen. Die Folge: Eine TreeView mit dem Wurzelelement. Klickt man drauf, so erscheint drunter als Child wieder das Wurzelelement, darauf geklickt wieder und wieder, etc.

Zur Veranschaulichung hier mal der Quelltext der betreffenden Klassen:

Klasse, die die Daten liefert
Code:
package de.mcp.view.data;

import javax.swing.tree.DefaultMutableTreeNode;


public class Input 
{
	public DefaultMutableTreeNode rootNode = null;
	
	public Input(int anzahl)
	{
		DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode("rootNode");
		rootNode = treeNode;
		DefaultMutableTreeNode child = null;
		rootNode.add(new DefaultMutableTreeNode("Stage2"));
		treeNode = (DefaultMutableTreeNode)rootNode.getFirstChild();
		for (int i=0;i < anzahl;i++)
		{
			child = new DefaultMutableTreeNode("childNode_" + i);
			treeNode.add(child);
		}
	}
	
	public DefaultMutableTreeNode getRootNode()
	{
		return rootNode;
	}

}


Klasse, die den Viewer aufruft

Code:
package com.ibm.jdg2e.jface.viewers.examples;

/*
 * "The Java Developer's Guide to Eclipse"
 *   by D'Anjou, Fairbrother, Kehn, Kellerman, McCarthy
 * 
 * (C) Copyright International Business Machines Corporation, 2003, 2004. 
 * All Rights Reserved.
 * 
 * Code or samples provided herein are provided without warranty of any kind.
 */

import javax.swing.tree.TreeNode;

import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;

import de.mcp.view.Provider.OwnLabelProvider;
import de.mcp.view.Provider.OwnTreeContentProvider;
import de.mcp.view.data.Input;

/**
 * TreeViewer example.
 */
public class TreeViewerExample extends AbstractViewerExample 
{
	private Input input = new Input(6);
	private OwnTreeContentProvider contentProvider = null;

  /**
   * Create TreeViewer example.
   * 
   * @see com.ibm.jdg2e.jface.viewers.examples.AbstractViewerExample#createViewer(org.eclipse.swt.widgets.Composite)
   */
  public void createViewer(Composite parent) 
  {
    viewer = new TreeViewer(parent);

    GridData gridData = new GridData(GridData.FILL_BOTH);

    viewer.getControl().setLayoutData(gridData);

    contentProvider = new OwnTreeContentProvider();
    viewer.setContentProvider(contentProvider);
	viewer.setLabelProvider(new OwnLabelProvider());

    viewer.setInput(input.getRootNode());

  }

}

Der Content-Viewer

Code:
package de.mcp.view.Provider;

import javax.swing.tree.DefaultMutableTreeNode;

import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

public class OwnTreeContentProvider implements ITreeContentProvider, IPropertyChangeListener {

	public void propertyChange(PropertyChangeEvent event) 
	{
		
	}

	public Object[] getChildren(Object parentElement) 
	{
		if (parentElement instanceof DefaultMutableTreeNode) 
		{
			int anzahl = ((DefaultMutableTreeNode)parentElement).getChildCount();
			Object[] obj = new Object[anzahl];
			for (int i=0;i<anzahl;i++)
			{
				obj[i] = ((DefaultMutableTreeNode)parentElement).getChildAt(i);
			}
			return obj;
		}
		return null;
	}

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

	public boolean hasChildren(Object element) 
	{
		if (((DefaultMutableTreeNode)element).getChildCount() > 0)
				return true;
		else
		{
			return false;			
		}
	}

	public Object[] getElements(Object inputElement) 
	{
		DefaultMutableTreeNode parent = (DefaultMutableTreeNode)((DefaultMutableTreeNode)inputElement).getParent();
		if (parent == null)
		{
			parent = ((DefaultMutableTreeNode)inputElement);
			Object[] obj = new Object[1];
			obj[0] = parent;
			return obj;

		}
		else
			return this.getChildren(parent);
	}

	public void dispose() 
	{
	
	}

	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		// TODO Auto-generated method stub

	}

}

Ich bin echt froh, für jeden Hinweis! Ich denke fast, ich hab das mit den Elementen einfügen, nicht so ganz verstanden, oder? :(

Gruß,
Craimore
 
Zuletzt bearbeitet:
#getElements() wird nur beim inputElement aufgerufen, sonst #getChildren().

#getElements() macht bei dir folgendes: es wird mit dem inputElement aufgerufen. dann holst du den parent
Code:
		DefaultMutableTreeNode parent = (DefaultMutableTreeNode)((DefaultMutableTreeNode)inputElement).getParent();
der ist natürlich null, denn der "rootNode" hat keinen parent. also ist die bedingung wahr und dann wird das hier ausgeführt:
Code:
			parent = ((DefaultMutableTreeNode)inputElement);
			Object[] obj = new Object[1];
			obj[0] = parent;
			return obj;
also ist das parent sein eigenes Kind. da das kind identisch ist mit dem inputElement, wird nur #getElements() gerufen, nie #getChildren().

probier mal
Code:
	public Object[] getElements(Object inputElement) 
	{
		return getChildren(inputElement);
	}

das inputElement liegt unsichtbar als wurzel "hinter" den anderen knoten.

hth
 
Hallo,

vielen vielen Dank für deine Lösung! Du hast mir damit sehr geholfen! :) :)
Ich bin gestern den ganzen Nachmittag nur
vor diesem Problem gesessen und hab irgendwann den Wald vor lauter Bäumen nicht mehr gesehen!

Ich hätte da noch eine allgemeine Frage:

Wenn ich mich noch etwas mehr in die Plugin-Entwicklung eingearbeitet habe, soll ich einen TreeViewer entwickeln,
der den Inhalt einer Library(bestehend aus sehr vielen verschiedenen Dateien in unterschiedl. Verzeichnissen)
darstellen kann. Natürlich mit unterschiedlichen "Dekorierungen" und verschiedenen PopUp-Menüs, je nach Typ der selektierten Datei.
Ist es da nun besser die Klasse des Package-Explorers oder Navigators abzuleiten oder von Grund auf neu die View aufzubauen?
Ich denke die Package-Explorer-Klasse oder die des Navigators bieten sich stark an, denn viele Funktionen müssen gleich oder ähnlich sein.
Andrerseits gibts es auch vollkommen neue Funktionen...?

Außerdem welche der beiden Klassen wäre als Basisklasse am besten?

Gruß,

Crai
 
als basisklassen taugen beide nicht. die grafische darstellung bekommst du quasi geschenkt, wenn du ein passendes modell hast, das die bibliothek abstrahiert.

hinter dem package explorer steht z.b. das "java model", das du dir höchstens mal angucken kannst, um zu sehen, wie es implementiert ist. das "java model" kann aber nicht direkt von einem treeviewer angezeigt werden, sonst wäre er nicht wiederverwendbar; dafür hast du dann die provider, die als adapter zwischen dem modell und dem treeviewer sitzen ("pluggable adapter").

der content-provider sowie die diversen label provider sind also vom "java model" abhängig und somit für dich nicht wiederverwendbar. du hast ein anderes modell, und somit brauchst du auch eigene provider, die zwischen treeviewer und modell vermitteln.

kennst du die artikel unter eclipse.org/articles? da ist das, was du vorhast, schön beschrieben (bis auf dekorierungen, aber bis dahin wird noch etwas zeit vergehen).
 
schade, dass die beiden nicht als basisklassen taugen.
ich hab den artikel auf eclipse.org, den du gemeint hast, heute durchgearbeitet und ich
muss sagen jetzt ist mir alles um einiges verständlicher!

So, jetzt gehts mal ans Einlesen der Ordnerstrukturen, um sie dann in meiner View darzustellen...

Gruß und Dank,

Crai
 
Zurück